Skip to content

Commit

Permalink
Add prelude file, emptying top-level init.
Browse files Browse the repository at this point in the history
Update readme.

Rename io.py to path.py.
  • Loading branch information
MylesBartlett committed Nov 13, 2024
1 parent 539e15e commit de489ba
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 12 deletions.
53 changes: 44 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Serox

_Rusty abstractions for Python._
_Rusty abstractions for Python_

`Serox` defines a emulates a suite of commonly-used Rust abstractions in a manner that is near-fully
`serox` provides a suite of commonly-used Rust abstractions in a manner that is near-fully
static-type-checker compliant, the exceptions being cases involving higher-kinded types (HKTs; e.g.
`Iterator.collect`) as these are not currently supported by Python's type system. Namely:
`Iterator.collect`) as these are not currently supported by Python's type system.

The subset of abstractions most broadly-applicable are importable from `serox.prelude`.

## Features

1. `Iterator` combinators that allow for the seamless chaining of operations over data with
[rayon]-inspired functionality for effortless parallelism.
Expand All @@ -18,23 +22,54 @@ static-type-checker compliant, the exceptions being cases involving higher-kinde
redresses this.

4. The `qmark` decorator emulates the '?' (error/null short-circuiting) operator, allowing for
propagation of error and null values without interrupting the control flow. Without this, one has
propagation of error and null values without disrupting the control flow. Without this, one has
to resort to awkward pattern-matching to perform common operations such as `unwrap_or` (setting
`Null` to a default value) or `map` (applying a function to the contained value if `Some`).

## Example

Early exiting (in the fashion of Rust's `?` operator) an Option/Result-returning function is enabled
by the `qmark` ('question mark') decorator:

```python
from serox import Option, qmark
from serox.prelude import *

@qmark
def some_function(foo: Option[str]) -> Option[str]:
foo_bar: str = value.map(lambda x: x + "bar").q
return Some(foo_bar + "_baz")
def some_function(value: Option[int]) -> Option[float]:
squared: int = value.map(lambda x: x ** 2).q
# The above expands to the rather verbose:
# match value:
# case Null():
# return Null[float]()
# case Some(x):
# squared = value ** 2

return Some(1.0 / squared)
```

[rayon]: https://github.com/rayon-rs/rayon
## Requirements

Python version `>=3.12.3` is required for typing purposes.

## Installation

`serox` is available on PyPI and thus the latest version can be installed via `pip` with

```sh
pip install serox
```

or via [uv] with

```sh
uv add serox
```

## Acknowledgements

Credit to [result](https://github.com/rustedpy/result) and
[rustshed](https://github.com/pawelrubin/rustshed/) for laying the groundwork for the `Result` and
`qmark` implementations.

[rayon]: https://github.com/rayon-rs/rayon
[uv]: https://docs.astral.sh/uv/
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ lint.ignore = [
"PLW2901", # overwriting loop variable
"PLC0105", # covariant typevars have to end in "_co"
]
lint.per-file-ignores = { "__init__.py" = ["F403"] }
lint.select = [
"E", # pycodestyle
"F", # pyflakes
Expand All @@ -122,6 +121,10 @@ lint.select = [
]
target-version = "py310"

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F403"]
"prelude" = ["F403"]

[tool.ruff.lint.isort]
case-sensitive = true
classes = []
Expand Down
1 change: 1 addition & 0 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
-e file:.
black==24.4.2
bump2version==1.0.1
# via serox
cfgv==3.4.0
# via pre-commit
click==8.1.7
Expand Down
2 changes: 2 additions & 0 deletions requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
# universal: false

-e file:.
bump2version==1.0.1
# via serox
joblib==1.4.2
# via serox
numpy==2.0.1
Expand Down
2 changes: 1 addition & 1 deletion serox/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from .collections import *
from .io import *
from .iter import *
from .misc import *
from .option import *
from .optional import *
from .path import *
from .question_mark import *
from .range import *
from .result import *
Expand Down
File renamed without changes.
32 changes: 32 additions & 0 deletions serox/prelude.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# pyright: reportUnusedImport=false
from .cmp import Ord, PartialOrd
from .iter import Bridge, DoubleEndedIterator, Iterator
from .misc import Clone, Dupe
from .option import Null, Option, Some
from .optional import none, some
from .question_mark import qmark
from .range import Range
from .result import Err, Ok, Result
from .vec import Vec

# export all imports
__all__ = [
"Bridge",
"Clone",
"DoubleEndedIterator",
"Dupe",
"Err",
"Iterator",
"Null",
"Ok",
"Option",
"Ord",
"PartialOrd",
"Range",
"Result",
"Some",
"Vec",
"none",
"qmark",
"some",
]
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit de489ba

Please sign in to comment.