Skip to content

Commit db759fe

Browse files
authored
BiocFrame extends BiocObject, metadata is now a named list. (#134)
1 parent d55f687 commit db759fe

3 files changed

Lines changed: 15 additions & 57 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
# Changelog
22

3-
## Version 0.7.0
3+
## Version 0.7.0 - 0.7.1
44

55
- Major update to type hints throughout the module for better type safety and consistency.
66
- Fixed bug in slice operations where column indices might be incorrectly initialized.
77
- Added missing index validation in `get_row()` for integer row indices. Similar index validation in `remove_columns()` and `remove_rows()` for out-of-range indices.
88
- Accept a list of column values and column names to initialize a biocframe object.
99
- Implement empty, contains, head, tail,
1010
- Coercions to list and `NamedList` from bioctuls.
11+
- `BiocFrame` now extends `BiocObject`, with metadata attribute now a `NamedList` from the biocutils package.
1112

1213
## Version 0.6.3
14+
1315
- Implement `remove_rows()`.
1416
- Implement `has_row()`.
1517
- Add support for slice objects in `remove_columns()` and enforce homogeneous types.
@@ -47,6 +49,7 @@
4749
- Internal refactoring to use generics from the BiocUtils package.
4850

4951
## Version 0.3
52+
5053
This release migrates the package to a more palatable Google's Python style guide. A major modification to the package is with casing, all `camelCase` methods, functions and parameters are now `snake_case`.
5154

5255
In addition, docstrings and documentation has been updated to use sphinx's features of linking objects to their types. Sphinx now also documents private and special dunder methods (e.g. `__getitem__`, `__copy__` etc). Intersphinx has been updated to link to references from dependent packages.
@@ -56,6 +59,7 @@ configuration for flake8, ruff and black has been added to pyproject.toml and se
5659
In addition, pyscaffold has been updated to use "myst-parser" as the markdown compiler instead of recommonmark. As part of the pyscaffold setup, one may use pre-commits to run some of the routine tasks of linting and formatting before every commit. While this is sometimes annoying and can be ignored with `--no-verify`, it brings some consistency to the code base.
5760

5861
## Version 0.2
62+
5963
- refactor DataFrame as BiocFrame
6064
- implementing slicing methods, tests
6165

src/biocframe/frame.py

Lines changed: 8 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def __next__(self) -> Tuple[Optional[Union[ut.Names, str]], Dict[str, Any]]:
104104
############################
105105

106106

107-
class BiocFrame:
107+
class BiocFrame(ut.BiocObject):
108108
"""`BiocFrame` is an alternative to :class:`~pandas.DataFrame`, with support for nested and flexible column types.
109109
Inspired by the ``DFrame`` class from Bioconductor's **S4Vectors** package. Any object may be used as a column,
110110
provided it has:
@@ -168,6 +168,12 @@ def __init__(
168168
_validate:
169169
Internal use only.
170170
"""
171+
172+
super().__init__(
173+
metadata=metadata,
174+
_validate=_validate,
175+
)
176+
171177
if data is None:
172178
data = {}
173179

@@ -176,7 +182,7 @@ def __init__(
176182
# making sure all column values are lists
177183
for k, v in data.items():
178184
if not isinstance(v, list):
179-
# if its a scalar, make a list else corce to list
185+
# if its a scalar, make a list else coerce to list
180186
data[k] = list(v) if isinstance(v, abc.Sequence) else [v]
181187
elif isinstance(data, Sequence) and not isinstance(data, (str, dict)):
182188
if column_names is None:
@@ -206,19 +212,12 @@ def __init__(
206212
else:
207213
self._column_names = column_names if isinstance(column_names, ut.Names) else ut.Names(column_names)
208214

209-
self._metadata = {} if metadata is None else metadata
210215
self._column_data = column_data
211216

212217
if _validate:
213218
_validate_rows(self._number_of_rows, self._data, self._row_names)
214219
_validate_columns(self._column_names, self._data, self._column_data)
215220

216-
def _define_output(self, in_place: bool = False) -> BiocFrame:
217-
if in_place is True:
218-
return self
219-
else:
220-
return self.__copy__()
221-
222221
def __eq__(self, other: Any) -> bool:
223222
"""Check if the current object is equal to another.
224223
@@ -668,51 +667,6 @@ def column_data(self, column_data: Optional[BiocFrame]) -> None:
668667
)
669668
self.set_column_data(column_data, in_place=True)
670669

671-
def get_metadata(self) -> dict:
672-
"""Get the metadata.
673-
674-
Returns:
675-
Dictionary of metadata for this object.
676-
"""
677-
return self._metadata
678-
679-
def set_metadata(self, metadata: Dict[str, Any], in_place: bool = False) -> BiocFrame:
680-
"""Set new metadata.
681-
682-
Args:
683-
metadata:
684-
New metadata for this object.
685-
686-
in_place:
687-
Whether to modify the ``BiocFrame`` object in place.
688-
689-
Returns:
690-
A modified ``BiocFrame`` object, either as a copy of the original
691-
or as a reference to the (in-place-modified) original.
692-
"""
693-
if not isinstance(metadata, dict):
694-
raise TypeError(f"`metadata` must be a dictionary, provided {type(metadata)}.")
695-
output = self._define_output(in_place)
696-
output._metadata = metadata
697-
return output
698-
699-
@property
700-
def metadata(self) -> Dict[str, Any]:
701-
"""Alias for :py:attr:`~get_metadata`."""
702-
return self.get_metadata()
703-
704-
@metadata.setter
705-
def metadata(self, metadata: Dict[str, Any]) -> None:
706-
"""Alias for :py:attr:`~set_metadata` with ``in_place = True``.
707-
708-
As this mutates the original object, a warning is raised.
709-
"""
710-
warn(
711-
"Setting property 'metadata' is an in-place operation, use 'set_metadata' instead",
712-
UserWarning,
713-
)
714-
self.set_metadata(metadata, in_place=True)
715-
716670
################################
717671
######>> Single getters <<######
718672
################################

tests/test_methods.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test_bframe_basic_ops():
5959
assert len(bframe.column_names) == 3
6060

6161
assert bframe.get_column_data() is None
62-
assert bframe.metadata == {}
62+
assert bframe.metadata == ut.NamedList()
6363

6464
assert len(bframe.dims) == 2
6565
assert bframe.dims == (3, 3)
@@ -104,7 +104,7 @@ def test_bframe_setters():
104104
assert bframe.column_names is not None
105105
assert len(bframe.column_names) == 3
106106

107-
assert bframe.metadata == {}
107+
assert bframe.metadata == ut.NamedList()
108108

109109
bframe.metadata = {"a": "b"}
110110
assert bframe.metadata is not None

0 commit comments

Comments
 (0)