This commit is contained in:
23
.gitea/workflows/build.yaml
Normal file
23
.gitea/workflows/build.yaml
Normal file
@@ -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}
|
35
pyproject.toml
Normal file
35
pyproject.toml
Normal file
@@ -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
|
34
requirements.txt
Normal file
34
requirements.txt
Normal file
@@ -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
|
75
src/pwo/maybe.py
Normal file
75
src/pwo/maybe.py
Normal file
@@ -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)
|
Reference in New Issue
Block a user