Skip to content
This repository has been archived by the owner on Dec 15, 2020. It is now read-only.

Commit

Permalink
updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Jackevansevo committed Apr 23, 2017
1 parent 0045bec commit 62ccabc
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 68 deletions.
9 changes: 5 additions & 4 deletions basic_utils/core.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import operator
import os

from collections import defaultdict
from functools import reduce
from typing import List

import operator
import os
from .primitives import sentinel

sentinel = object()

__all__ = [
'clear', 'getattrs', 'map_getattr', 'recursive_default_dict', 'rgetattr',
Expand Down Expand Up @@ -56,7 +57,7 @@ def recursive_default_dict():
return defaultdict(recursive_default_dict)


def rgetattr(obj, attrs, default=sentinel):
def rgetattr(obj: object, attrs: str, default=sentinel):
"""Get a nested attribute within an object"""
return reduce(getattr, [obj] + attrs.split('.'))

Expand Down
100 changes: 45 additions & 55 deletions basic_utils/helpers.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from functools import reduce
from itertools import chain
from operator import getitem
from typing import Sequence, Iterable, Any, Callable
from typing import Any, Callable, Iterable, Sequence


def first(seq: Sequence) -> Any:
def first(seq: Iterable) -> Any:
"""
Returns first element in a sequence.
Expand All @@ -14,46 +14,61 @@ def first(seq: Sequence) -> Any:
return next(iter(seq))


def rest(seq: Sequence) -> Any:
"""
Returns remaining elements in a sequence
>>> rest([1, 2, 3])
[2, 3]
"""
return seq[1:]


def last(seq: Sequence) -> Any:
"""
Returns the last item in a sequence
Returns the last item in a Sequence
>>> last([1, 2, 3])
3
"""
return seq[-1]


def butlast(seq: Sequence) -> Any:
def butlast(seq: Sequence) -> Sequence:
"""
Returns an iterable of all but the last item in the sequence
Returns all but the last item in sequence
>>> butlast([1, 2, 3])
[1, 2]
"""
return seq[:-1]


def rest(seq: Sequence) -> Any:
"""
Returns remaining elements in a sequence
>>> rest([1, 2, 3])
[2, 3]
"""
return seq[1:]


def reverse(seq: Sequence) -> Sequence:
"""
Returns a sequence of items in seq in reverse order
Returns sequence in reverse order
>>> reverse([1, 2, 3])
[3, 2, 1]
"""
return seq[::-1]


def flatten(seq: Iterable) -> Iterable:
"""
Returns a generator object which when evalutated
returns a flatted version of seq
>>> list(flatten([1, [2, [3, [4, 5], 6], 7]]))
[1, 2, 3, 4, 5, 6, 7]
"""
for item in seq:
if isinstance(item, Iterable) and not isinstance(item, (str, bytes)):
yield from flatten(item)
else:
yield item


def partial_flatten(seq: Iterable) -> Iterable:
"""
Returns partially flattened version of seq
Expand All @@ -64,19 +79,19 @@ def partial_flatten(seq: Iterable) -> Iterable:
return chain.from_iterable(seq)


def flatten(seq: Iterable) -> Iterable:
def dedupe(seq: Sequence, key=None):
"""
Returns a generator object which when evalutated
returns a flatted version of seq
Removes duplicates from a sequence while maintaining order
>>> list(flatten([1, [2, [3, [4, 5], 6], 7]]))
[1, 2, 3, 4, 5, 6, 7]
>>> list(dedupe([1, 5, 2, 1, 9, 1, 5, 10]))
[1, 5, 2, 9, 10]
"""
seen = set() # type: set
for item in seq:
if isinstance(item, Iterable) and not isinstance(item, (str, bytes)):
yield from flatten(item)
else:
val = item if key is None else key(item)
if val not in seen:
yield item
seen.add(val)


def get_keys(obj, keys, default=None):
Expand All @@ -92,21 +107,21 @@ def get_keys(obj, keys, default=None):
return tuple(obj.get(key, default) for key in keys)


def dict_subset(d, keys, include_missing=True, default_key=None):
def dict_subset(d: dict, keys, prune=False, default=None):
"""
Returns a new dictionary with a subset of key value pairs from the original
>>> d = {'a': 1, 'b': 2}
>>> dict_subset(d, ('c',), True, 'missing')
{'c': 'missing'}
"""
new = {k: d.get(k, default_key) for k in keys}
if include_missing:
return new
return {k: v for k, v in new.items() if v}
new = {k: d.get(k, default) for k in keys}
if prune:
return prune(new)
return new


def get_in_dict(d, keys: Sequence[str]) -> Any:
def get_in_dict(d: dict, keys: Sequence[str]) -> Any:
"""
Retrieve nested key from dictionary
Expand All @@ -129,31 +144,6 @@ def set_in_dict(d: dict, keys: Sequence[str], value) -> None:
get_in_dict(d, butlast(keys))[last(keys)] = value


def uniq(seq):
"""
Removes duplicates from a sequence
>>> uniq([1, 2, 1, 1, 2, 3])
[1, 2, 3]
"""
return type(seq)(set(seq))


def dedupe(seq: Sequence, key=None):
"""
Removes duplicates from a sequence while maintaining order
>>> list(dedupe([1, 5, 2, 1, 9, 1, 5, 10]))
[1, 5, 2, 9, 10]
"""
seen = set() # type: set
for item in seq:
val = item if key is None else key(item)
if val not in seen:
yield item
seen.add(val)


def prune_dict(d: dict, key: Callable = lambda x: x is not None) -> dict:
"""
Returns new dictionary with key / values pairs filtered by key function.
Expand Down
8 changes: 8 additions & 0 deletions basic_utils/primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
__all__ = ['dec', 'even', 'identity', 'inc', 'odd']


sentinel = object()


def identity(x: Any) -> Any:
"""
Returns the same values passed as arguments
Expand All @@ -16,6 +19,8 @@ def identity(x: Any) -> Any:

def inc(x: int) -> int:
"""
Increments argument by 1
>>> inc(10)
11
"""
Expand All @@ -24,6 +29,8 @@ def inc(x: int) -> int:

def dec(x: int) -> int:
"""
Decrements argument by 1
>>> dec(5)
4
"""
Expand All @@ -32,6 +39,7 @@ def dec(x: int) -> int:

def even(x: int) -> bool:
"""
Returns True if something
>>> even(2)
True
"""
Expand Down
4 changes: 4 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
'sphinx.ext.viewcode',
'sphinx.ext.githubpages']


# Order things by the same order they appear in the source
autodoc_member_order = 'bysource'

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

Expand Down
7 changes: 7 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,10 @@ Helpers

.. automodule:: basic_utils.helpers
:members:


Primitives
========================================

.. automodule:: basic_utils.primitives
:members:
9 changes: 0 additions & 9 deletions tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
rest,
reverse,
set_in_dict,
uniq,
)


Expand Down Expand Up @@ -128,14 +127,6 @@ def test_set_in_dict(data, keys, value, expected):
assert data == expected


@pytest.mark.parametrize("data, expected", [
([1, 2, 1, 2, 3, 3], [1, 2, 3]),
])
def test_uniq(data, expected):
"""Tests that uniq removes duplicates from a sequence"""
assert uniq(data) == expected


@pytest.mark.parametrize("data, key, expected", [
([1, 5, 2, 1, 9, 1, 5, 10], None, [1, 5, 2, 9, 10]),
(["jack", "joe", "jay", "ian"], len, ["jack", "joe"])
Expand Down

0 comments on commit 62ccabc

Please sign in to comment.