From 514962d9e3bcc6c88b118df76b18d066b9ca62a4 Mon Sep 17 00:00:00 2001 From: Walter Oggioni Date: Sat, 22 Jun 2024 08:13:48 +0800 Subject: [PATCH] initial commit --- .gitea/workflows/build.yaml | 23 ++++++++++++ pyproject.toml | 35 +++++++++++++++++ requirements.txt | 34 +++++++++++++++++ src/pwo/maybe.py | 75 +++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 .gitea/workflows/build.yaml create mode 100644 pyproject.toml create mode 100644 requirements.txt create mode 100644 src/pwo/maybe.py diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml new file mode 100644 index 0000000..b05764c --- /dev/null +++ b/.gitea/workflows/build.yaml @@ -0,0 +1,23 @@ +name: CI +on: + push: + branches: [ master ] +jobs: + build: + runs-on: woryzen + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + cache: 'pip' + - name: Execute build + env: + TWINE_REPOSITORY_URL: ${{ vars.PYPI_REGISTRY_URL }} + TWINE_USERNAME: ${{ vars.PUBLISHER_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PUBLISHER_TOKEN }} + run: | + python -m venv .venv + .venv/bin/pip install -r requirements.txt + .venv/bin/python -m build + .venv/bin/python -m twine upload --repository gitea dist/*{.whl,tar.gz} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..e120b74 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,35 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "pwo" +version = "0.0.1" +authors = [ + { name="Walter Oggioni", email="oggioni.walter@gmail.com" }, +] +description = "Python language utilities" +readme = "README.md" +requires-python = ">=3.10" +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", +] +dependencies = [ + 'typing_extensions==4.7.1' +] + +[project.urls] +"Homepage" = "https://gitea.woggioni.net/woggioni/pwo" +"Bug Tracker" = "https://gitea.woggioni.net/woggioni/pwo/issues" + +[tool.mypy] +python_version = "3.12" +disallow_untyped_defs = true +show_error_codes = true +no_implicit_optional = true +warn_return_any = true +warn_unused_ignores = true +exclude = ["scripts", "docs", "test"] +strict = true \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b39a50b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,34 @@ +build==1.2.1 +certifi==2024.6.2 +cffi==1.16.0 +charset-normalizer==3.3.2 +cryptography==42.0.8 +docutils==0.21.2 +idna==3.7 +importlib_metadata==7.2.0 +jaraco.classes==3.4.0 +jaraco.context==5.3.0 +jaraco.functools==4.0.1 +jeepney==0.8.0 +keyring==25.2.1 +markdown-it-py==3.0.0 +mdurl==0.1.2 +more-itertools==10.3.0 +mypy==1.10.0 +mypy-extensions==1.0.0 +nh3==0.2.17 +packaging==24.1 +pkginfo==1.11.1 +pycparser==2.22 +Pygments==2.18.0 +pyproject_hooks==1.1.0 +readme_renderer==43.0 +requests==2.32.3 +requests-toolbelt==1.0.0 +rfc3986==2.0.0 +rich==13.7.1 +SecretStorage==3.3.3 +twine==5.1.0 +typing_extensions==4.12.2 +urllib3==2.2.2 +zipp==3.19.2 diff --git a/src/pwo/maybe.py b/src/pwo/maybe.py new file mode 100644 index 0000000..f0d00d6 --- /dev/null +++ b/src/pwo/maybe.py @@ -0,0 +1,75 @@ +from __future__ import annotations +from typing import TypeVar, Generic, Optional, Callable, Any + +T = TypeVar('T') +U = TypeVar('U') + + +class Maybe(Generic[T]): + + def __init__(self, value: Optional[T] = None): + self._value: Optional[T] = value + + @staticmethod + def of(obj: T) -> Maybe[T]: + return Maybe(obj) + + @staticmethod + def of_nullable(obj: Optional[T]) -> Maybe[T]: + return Maybe(obj) + + @staticmethod + def empty() -> Maybe[U]: + return _empty + + @property + def value(self) -> T: + value = self._value + if not value: + raise ValueError('Empty Maybe') + else: + return value + + @property + def is_present(self) -> bool: + return self._value is not None + + @property + def is_empty(self) -> bool: + return not self.is_present + + def map(self, transformer: Callable[[T], U]) -> Maybe[U]: + result: Maybe[U] + if self.is_present: + result = Maybe(transformer(self.value)) + else: + result = Maybe.empty() + return result + + def filter(self, predicate: Callable[[T], bool]) -> Maybe[T]: + return self if self.is_present and predicate(self.value) else Maybe.empty() + + def flat_map(self, transformer: Callable[[T], Maybe[U]]) -> Maybe[U]: + return transformer(self.value) if self.is_present else Maybe.empty() + + def or_else(self, alt: T) -> T: + return self.value if self.is_present else alt + + def or_none(self) -> Optional[T]: + return self.value if self.is_present else None + + def or_else_throw(self, supplier: Callable[[], Exception]) -> T: + if self.is_present: + return self.value + else: + raise supplier() + + def or_else_get(self, supplier: Callable[[], T]) -> Maybe[T]: + return self if self.is_present else Maybe.of_nullable(supplier()) + + def if_present(self, callback: Callable[[T], U]) -> None: + if self.is_present: + callback(self.value) + + +_empty: Maybe[Any] = Maybe(None)