Skip to content

Commit

Permalink
Merge branch 'packaging' of https://github.com/biocpy/biocutils into …
Browse files Browse the repository at this point in the history
…packaging
  • Loading branch information
jkanche committed Nov 1, 2023
2 parents af0f9a3 + c1948f5 commit be739ee
Show file tree
Hide file tree
Showing 21 changed files with 221 additions and 135 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Changelog

## Version 0.0.1
## Version 0.0.1

- First release of the package.
10 changes: 4 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
"""
Setup file for biocutils.
Use setup.cfg to configure your project.
"""Setup file for biocutils. Use setup.cfg to configure your project.
This file was generated with PyScaffold 4.5.
PyScaffold helps you to put up the scaffold of your new Python project.
Learn more under: https://pyscaffold.org/
This file was generated with PyScaffold 4.5.
PyScaffold helps you to put up the scaffold of your new Python project.
Learn more under: https://pyscaffold.org/
"""
from setuptools import setup

Expand Down
3 changes: 1 addition & 2 deletions src/biocutils/factor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
def factor(
x: Sequence, levels: Optional[Sequence] = None, sort_levels: bool = False
) -> Tuple[list, list]:
"""
Convert a sequence of hashable values into a factor.
"""Convert a sequence of hashable values into a factor.
Args:
x (Sequence): A sequence of hashable values.
Expand Down
4 changes: 2 additions & 2 deletions src/biocutils/intersect.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@


def intersect(*x: Sequence, duplicate_method: DUPLICATE_METHOD = "first") -> list:
"""Identify the intersection of values in multiple sequences, while
preserving the order of values in the first sequence.
"""Identify the intersection of values in multiple sequences, while preserving the order of values in the first
sequence.
Args:
x (Sequence):
Expand Down
5 changes: 2 additions & 3 deletions src/biocutils/normalize_subscript.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ def normalize_subscript(
names: Optional[Sequence[str]] = None,
non_negative_only: bool = True,
) -> Tuple:
"""
Normalize a subscript for ``__getitem__`` or friends into a sequence of
integer indices, for consistent downstream use.
"""Normalize a subscript for ``__getitem__`` or friends into a sequence of integer indices, for consistent
downstream use.
Args:
sub:
Expand Down
46 changes: 29 additions & 17 deletions src/biocutils/print_truncated.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@


def print_truncated(x, truncated_to: int = 3, full_threshold: int = 10) -> str:
"""
Pretty-print an object, replacing the middle elements of lists/dictionaries
with an ellipsis if there are too many. This provides a useful preview of
an object without spewing out all of its contents on the screen.
"""Pretty-print an object, replacing the middle elements of lists/dictionaries with an ellipsis if there are too
many. This provides a useful preview of an object without spewing out all of its contents on the screen.
Args:
x: Object to be printed.
Expand All @@ -22,18 +20,27 @@ def print_truncated(x, truncated_to: int = 3, full_threshold: int = 10) -> str:
String containing the pretty-printed contents.
"""
if isinstance(x, dict):
return print_truncated_dict(x, truncated_to=truncated_to, full_threshold=full_threshold)
return print_truncated_dict(
x, truncated_to=truncated_to, full_threshold=full_threshold
)
elif isinstance(x, list):
return print_truncated_list(x, truncated_to=truncated_to, full_threshold=full_threshold)
return print_truncated_list(
x, truncated_to=truncated_to, full_threshold=full_threshold
)
else:
return repr(x)


def print_truncated_list(x: List, truncated_to: int = 3, full_threshold: int = 10, transform: Optional[Callable] = None, sep: str = ", ", include_brackets: bool = True) -> str:
"""
Pretty-print a list, replacing the middle elements with an ellipsis if
there are too many. This provides a useful preview of an object without
spewing out all of its contents on the screen.
def print_truncated_list(
x: List,
truncated_to: int = 3,
full_threshold: int = 10,
transform: Optional[Callable] = None,
sep: str = ", ",
include_brackets: bool = True,
) -> str:
"""Pretty-print a list, replacing the middle elements with an ellipsis if there are too many. This provides a useful
preview of an object without spewing out all of its contents on the screen.
Args:
x: List to be printed.
Expand All @@ -58,7 +65,7 @@ def print_truncated_list(x: List, truncated_to: int = 3, full_threshold: int = 1
Whether to include the start/end brackets.
Returns:
String containing the pretty-printed truncated list.
String containing the pretty-printed truncated list.
"""
collected = []
if transform is None:
Expand All @@ -81,11 +88,16 @@ def transform(y):
return output


def print_truncated_dict(x: Dict, truncated_to: int = 3, full_threshold: int = 10, transform: Optional[Callable] = None, sep: str = ", ", include_brackets: bool = True) -> str:
"""
Pretty-print a dictionary, replacing the middle elements with an ellipsis
if there are too many. This provides a useful preview of an object without
spewing out all of its contents on the screen.
def print_truncated_dict(
x: Dict,
truncated_to: int = 3,
full_threshold: int = 10,
transform: Optional[Callable] = None,
sep: str = ", ",
include_brackets: bool = True,
) -> str:
"""Pretty-print a dictionary, replacing the middle elements with an ellipsis if there are too many. This provides a
useful preview of an object without spewing out all of its contents on the screen.
Args:
x: Dictionary to be printed.
Expand Down
22 changes: 8 additions & 14 deletions src/biocutils/print_wrapped_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ def print_wrapped_table(
sep: str = " ",
window: Optional[int] = None,
) -> str:
"""
Pretty-print a table with aligned and wrapped columns. All column contents
are padded so that they are right-justified. Wrapping is performed whenever
a new column would exceed the window width, in which case the entire column
(and all subsequent columns) are printed below the previous columns.
"""Pretty-print a table with aligned and wrapped columns. All column contents are padded so that they are right-
justified. Wrapping is performed whenever a new column would exceed the window width, in which case the entire
column (and all subsequent columns) are printed below the previous columns.
Args:
columns:
Expand Down Expand Up @@ -105,9 +103,8 @@ def reinitialize():
def create_floating_names(
names: Optional[List[str]], indices: Sequence[int]
) -> List[str]:
"""
Create the floating names to use in :py:meth:`~print_wrapped_table`. If no
names are present, positional indices are used instead.
"""Create the floating names to use in :py:meth:`~print_wrapped_table`. If no names are present, positional indices
are used instead.
Args:
names:
Expand All @@ -126,8 +123,7 @@ def create_floating_names(


def truncate_strings(values: List[str], width: int = 40) -> List[str]:
"""
Truncate long strings for printing in :py:meth:`~print_wrapped_table`.
"""Truncate long strings for printing in :py:meth:`~print_wrapped_table`.
Args:
values:
Expand All @@ -147,10 +143,8 @@ def truncate_strings(values: List[str], width: int = 40) -> List[str]:


def print_type(x) -> str:
"""
Print the type of an object, with some special behavior for certain classes
(e.g., to add the data type of NumPy arrays). This is intended for display
at the top of the columns of :py:meth:`~print_wrapped_table`.
"""Print the type of an object, with some special behavior for certain classes (e.g., to add the data type of NumPy
arrays). This is intended for display at the top of the columns of :py:meth:`~print_wrapped_table`.
Args:
x: Some object.
Expand Down
5 changes: 2 additions & 3 deletions src/biocutils/subset.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@


def subset(x: Any, indices: Union[Sequence[int], slice]) -> Any:
"""Subset ``x`` by ``indices`` to obtain a new object with the desired
subset of elements. This attempts to use ``x``'s ``__getitem__`` method, if
available; otherwise it falls back to iteration over the indices.
"""Subset ``x`` by ``indices`` to obtain a new object with the desired subset of elements. This attempts to use
``x``'s ``__getitem__`` method, if available; otherwise it falls back to iteration over the indices.
If ``x`` has a ``shape`` method that returns a tuple (a la NumPy arrays),
subsetting is only attempted on the first dimension via the ``__getitem__``
Expand Down
4 changes: 2 additions & 2 deletions src/biocutils/union.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@


def union(*x: Sequence, duplicate_method: DUPLICATE_METHOD = "first") -> list:
"""Identify the union of values in multiple sequences, while preserving the
order of the first (or last) occurence of each value.
"""Identify the union of values in multiple sequences, while preserving the order of the first (or last) occurence
of each value.
Args:
x (Sequence):
Expand Down
11 changes: 5 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
"""
Dummy conftest.py for biocutils.
"""Dummy conftest.py for biocutils.
If you don't know what this is for, just leave it empty.
Read more about conftest.py under:
- https://docs.pytest.org/en/stable/fixture.html
- https://docs.pytest.org/en/stable/writing_plugins.html
If you don't know what this is for, just leave it empty.
Read more about conftest.py under:
- https://docs.pytest.org/en/stable/fixture.html
- https://docs.pytest.org/en/stable/writing_plugins.html
"""

# import pytest
22 changes: 12 additions & 10 deletions tests/test_factor.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,32 @@ def test_factor_simple():


def test_factor_levels():
revlev = [5,4,3,2,1]
revlev = [5, 4, 3, 2, 1]
lev, ind = factor([1, 3, 5, 5, 3, 1], levels=revlev)
assert lev == revlev
assert ind == [4,2,0,0,2,4]
assert ind == [4, 2, 0, 0, 2, 4]

# Preserves duplicates.
duplicated = [5,4,5,4,3,4,2,3,1,1,2]
duplicated = [5, 4, 5, 4, 3, 4, 2, 3, 1, 1, 2]
lev, ind = factor([1, 3, 5, 5, 3, 1], levels=duplicated)
assert lev == duplicated
assert ind == [8,4,0,0,4,8]
assert ind == [8, 4, 0, 0, 4, 8]

# Ignores None.
noney = [None,1,2,3,4,5,None]
noney = [None, 1, 2, 3, 4, 5, None]
lev, ind = factor([1, 3, 5, 5, 3, 1], levels=noney)
assert lev == noney
assert ind == [1,3,5,5,3,1]
assert ind == [1, 3, 5, 5, 3, 1]


def test_factor_sorted():
lev, ind = factor(["C", "D", "A", "B", "C", "A"], sort_levels = True)
lev, ind = factor(["C", "D", "A", "B", "C", "A"], sort_levels=True)
assert lev == ["A", "B", "C", "D"]
assert ind == [2,3,0,1,2,0]
assert ind == [2, 3, 0, 1, 2, 0]

# Not affected if you supply the levels directly.
lev, ind = factor(["C", "D", "A", "B", "C", "A"], levels = ["D", "C", "B", "A"], sort_levels = True)
lev, ind = factor(
["C", "D", "A", "B", "C", "A"], levels=["D", "C", "B", "A"], sort_levels=True
)
assert lev == ["D", "C", "B", "A"]
assert ind == [1,0,3,2,1,3]
assert ind == [1, 0, 3, 2, 1, 3]
18 changes: 6 additions & 12 deletions tests/test_intersect.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,26 @@ def test_intersect_simple():

def test_intersect_duplicates():
# Doesn't report B, D, or F, despite the fact they have multiple counts.
out = intersect(
["B", "B", "C", "A", "D", "D", "E"], ["A", "A", "C", "E", "F", "F"]
)
out = intersect(["B", "B", "C", "A", "D", "D", "E"], ["A", "A", "C", "E", "F", "F"])
assert out == ["C", "A", "E"]

# Doesn't report A multiple times.
out = intersect(
["C", "A", "D", "A", "E", "A"], ["A", "C", "E", "F"]
)
out = intersect(["C", "A", "D", "A", "E", "A"], ["A", "C", "E", "F"])
assert out == ["C", "A", "E"]

# Switches the order of A being reported.
out = intersect(
["C", "A", "D", "A", "E", "A"],
["A", "C", "E", "F"],
duplicate_method = "last"
["C", "A", "D", "A", "E", "A"], ["A", "C", "E", "F"], duplicate_method="last"
)
assert out == ["C", "E", "A"]

# Handles the single case correctly.
single = ["A", "B", "A", "C", "D", "E", "D", "C"]
out = intersect(single)
assert out == [ "A", "B", "C", "D", "E" ]
assert out == ["A", "B", "C", "D", "E"]

out = intersect(single, duplicate_method = "last")
assert out == [ "B", "A", "E", "D", "C" ]
out = intersect(single, duplicate_method="last")
assert out == ["B", "A", "E", "D", "C"]


def test_intersect_none():
Expand Down
2 changes: 1 addition & 1 deletion tests/test_list_type_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def test_simple_list():

xt = (1, 2, None)
assert not is_list_of_type(xt, int)
assert is_list_of_type(xt, int, ignore_none = True)
assert is_list_of_type(xt, int, ignore_none=True)


def test_should_fail():
Expand Down
16 changes: 10 additions & 6 deletions tests/test_map_to_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@

def test_map_to_index_simple():
mapping = map_to_index(["A", "B", "C", "D"])
assert mapping == { "A": 0, "B": 1, "C": 2, "D": 3 }
assert mapping == {"A": 0, "B": 1, "C": 2, "D": 3}


def test_map_to_index_duplicates():
duplicated = ["A", "B", "C", "D", "A", "B", "C", "D"]

mapping = map_to_index(duplicated)
assert mapping == { "A": 0, "B": 1, "C": 2, "D": 3 }
assert mapping == {"A": 0, "B": 1, "C": 2, "D": 3}

mapping = map_to_index(
["A", "B", "C", "D", "A", "B", "C", "D"], duplicate_method="last"
)
assert mapping == {"A": 4, "B": 5, "C": 6, "D": 7}

mapping = map_to_index(["A", "B", "C", "D", "A", "B", "C", "D"], duplicate_method="last")
assert mapping == { "A": 4, "B": 5, "C": 6, "D": 7 }

def test_map_to_index_none():
noney = [ None, "A", None, "B", None, "C", None, "D", None ]
noney = [None, "A", None, "B", None, "C", None, "D", None]
mapping = map_to_index(noney)
assert mapping == { "A": 1, "B": 3, "C": 5, "D": 7 }
assert mapping == {"A": 1, "B": 3, "C": 5, "D": 7}
2 changes: 2 additions & 0 deletions tests/test_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def test_match_simple():
mm2 = match(x, map_to_index(levels))
assert mm == mm2


def test_match_duplicates():
x = [5, 1, 2, 3, 5, 6, 7, 7, 2, 1]
mm = match(x, [1, 2, 3, 3, 5, 6, 1, 7, 6])
Expand All @@ -19,6 +20,7 @@ def test_match_duplicates():
mm = match(x, [1, 2, 3, 3, 5, 6, 1, 7, 6], duplicate_method="last")
assert mm == [4, 6, 1, 3, 4, 8, 7, 7, 1, 6]


def test_match_none():
mm = match(["A", None, "B", "D", None, "A", "C", None, "B"], ["D", "C", "B", "A"])
assert list(mm) == [3, None, 2, 0, None, 3, 1, None, 2]
Expand Down
Loading

0 comments on commit be739ee

Please sign in to comment.