Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# Changelog

## Version 0.10.0 - 0.10.4
## Version 0.10.0 - 0.10.5

- Added methods to write to RDS/RData files.
- Supports atomic types, generic dictionaries/lists, and **BiocPy objects**.
- Read `symbols` registered in RDS objects.
- Fixed an issue with S4 classes not properly saved as RDS files.
- Implement `save_rds` generic for sparse matrix formats (csc, csr and coo).
- Implement `save_rds` for NumPy scalars.
- Added `register_parser` decorator to dynamically register custom R-to-Python class parser functions.

## Version 0.9.0 - 0.9.1

Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,19 @@ write_rda(objects, "workspace.rda")

### 3. Custom Extensions

If you have custom S4 representations or class mapping needs, you can parse the raw RDS structure into Python dictionary representations using `parse_rds`/`parse_rda` and apply your custom deserializers:
For custom R classes or S4 structures, you can register custom parser functions dynamically using the `register_parser` decorator:

```python
import rds2py

@rds2py.register_parser("MyCustomRClass")
def parse_my_custom_class(robject, **kwargs):
# Construct your custom Python representation from the raw RDS dictionary
value = robject.get("data", None)
return {"coerced": True, "value": value}
```

You can also parse the raw RDS structure into Python dictionary representations using `parse_rds`/`parse_rda` and apply your custom deserializers:

```python
from rds2py import parse_rds
Expand Down
2 changes: 1 addition & 1 deletion src/rds2py/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
del version, PackageNotFoundError


from .generics import read_rds, read_rda, save_rds
from .generics import read_rds, read_rda, save_rds, register_parser
from .rdsutils import parse_rds, parse_rda, write_rds, write_rda
16 changes: 16 additions & 0 deletions src/rds2py/generics.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,22 @@ def _dispatcher(robject: dict, **kwargs):
return robject


def register_parser(class_name: str):
"""Decorator to register a custom R-to-Python class parser.

Args:
class_name:
The R class name to register.
"""

def decorator(func):
REGISTRY[class_name] = func

return func

return decorator


@singledispatch
def save_rds(x: Any, path: Optional[str] = None):
"""Save a Python object as RDS file.
Expand Down
17 changes: 17 additions & 0 deletions tests/test_custom_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import rds2py
from rds2py.generics import _dispatcher

__author__ = "jkanche"
__copyright__ = "jkanche"
__license__ = "MIT"


def test_register_parser():
@rds2py.register_parser("DummyRClass")
def parse_dummy(robj, **kwargs):
return {"coerced": True, "value": robj.get("data", None)}

robj = {"type": "S4", "class_name": "DummyRClass", "data": 42}
res = _dispatcher(robj)

assert res == {"coerced": True, "value": 42}
Loading