haiway 0.10.1__tar.gz → 0.10.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. haiway-0.10.11/.github/workflows/ci.yml +35 -0
  2. haiway-0.10.11/.github/workflows/publish.yml +35 -0
  3. haiway-0.10.11/.gitignore +83 -0
  4. haiway-0.10.11/Makefile +89 -0
  5. {haiway-0.10.1/src/haiway.egg-info → haiway-0.10.11}/PKG-INFO +14 -15
  6. haiway-0.10.11/config/pre-push +57 -0
  7. haiway-0.10.11/examples/fastAPI/.dockerignore +5 -0
  8. haiway-0.10.11/examples/fastAPI/Dockerfile +37 -0
  9. haiway-0.10.11/examples/fastAPI/Makefile +86 -0
  10. haiway-0.10.11/examples/fastAPI/README.md +1 -0
  11. haiway-0.10.11/examples/fastAPI/config/.env.example +11 -0
  12. haiway-0.10.11/examples/fastAPI/config/unit.json +50 -0
  13. haiway-0.10.11/examples/fastAPI/docker-compose.yml +44 -0
  14. haiway-0.10.11/examples/fastAPI/pyproject.toml +65 -0
  15. haiway-0.10.11/examples/fastAPI/src/features/todos/__init__.py +5 -0
  16. haiway-0.10.11/examples/fastAPI/src/features/todos/calls.py +16 -0
  17. haiway-0.10.11/examples/fastAPI/src/features/todos/config.py +1 -0
  18. haiway-0.10.11/examples/fastAPI/src/features/todos/state.py +12 -0
  19. haiway-0.10.11/examples/fastAPI/src/features/todos/types.py +15 -0
  20. haiway-0.10.11/examples/fastAPI/src/features/todos/user_tasks.py +17 -0
  21. haiway-0.10.11/examples/fastAPI/src/integrations/__init__.py +0 -0
  22. haiway-0.10.11/examples/fastAPI/src/integrations/postgres/__init__.py +12 -0
  23. haiway-0.10.11/examples/fastAPI/src/integrations/postgres/client.py +146 -0
  24. haiway-0.10.11/examples/fastAPI/src/integrations/postgres/config.py +19 -0
  25. haiway-0.10.11/examples/fastAPI/src/integrations/postgres/state.py +64 -0
  26. haiway-0.10.11/examples/fastAPI/src/integrations/postgres/types.py +27 -0
  27. haiway-0.10.11/examples/fastAPI/src/server/__init__.py +10 -0
  28. haiway-0.10.11/examples/fastAPI/src/server/__main__.py +10 -0
  29. haiway-0.10.11/examples/fastAPI/src/server/application.py +54 -0
  30. haiway-0.10.11/examples/fastAPI/src/server/config.py +11 -0
  31. haiway-0.10.11/examples/fastAPI/src/server/middlewares/__init__.py +5 -0
  32. haiway-0.10.11/examples/fastAPI/src/server/middlewares/context.py +133 -0
  33. haiway-0.10.11/examples/fastAPI/src/server/routes/__init__.py +7 -0
  34. haiway-0.10.11/examples/fastAPI/src/server/routes/technical.py +21 -0
  35. haiway-0.10.11/examples/fastAPI/src/server/routes/todos.py +26 -0
  36. haiway-0.10.11/examples/fastAPI/src/solutions/__init__.py +0 -0
  37. haiway-0.10.11/examples/fastAPI/src/solutions/user_tasks/__init__.py +12 -0
  38. haiway-0.10.11/examples/fastAPI/src/solutions/user_tasks/calls.py +54 -0
  39. haiway-0.10.11/examples/fastAPI/src/solutions/user_tasks/config.py +1 -0
  40. haiway-0.10.11/examples/fastAPI/src/solutions/user_tasks/postgres.py +106 -0
  41. haiway-0.10.11/examples/fastAPI/src/solutions/user_tasks/state.py +25 -0
  42. haiway-0.10.11/examples/fastAPI/src/solutions/user_tasks/types.py +70 -0
  43. haiway-0.10.11/examples/fastAPI/uv.lock +435 -0
  44. haiway-0.10.11/guidelines/functionalities.md +252 -0
  45. haiway-0.10.11/guidelines/packages.md +321 -0
  46. haiway-0.10.11/hatch_version.py +20 -0
  47. haiway-0.10.11/junit/test-results.xml +1 -0
  48. {haiway-0.10.1 → haiway-0.10.11}/pyproject.toml +11 -5
  49. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/context/access.py +8 -0
  50. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/context/identifier.py +18 -1
  51. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/helpers/metrics.py +24 -4
  52. haiway-0.10.11/src/haiway/py.typed +0 -0
  53. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/utils/collections.py +93 -16
  54. haiway-0.10.11/tests/__init__.py +0 -0
  55. haiway-0.10.11/uv.lock +316 -0
  56. haiway-0.10.1/PKG-INFO +0 -87
  57. haiway-0.10.1/setup.cfg +0 -4
  58. haiway-0.10.1/src/haiway.egg-info/SOURCES.txt +0 -54
  59. haiway-0.10.1/src/haiway.egg-info/dependency_links.txt +0 -1
  60. haiway-0.10.1/src/haiway.egg-info/requires.txt +0 -9
  61. haiway-0.10.1/src/haiway.egg-info/top_level.txt +0 -1
  62. {haiway-0.10.1 → haiway-0.10.11}/LICENSE +0 -0
  63. {haiway-0.10.1 → haiway-0.10.11}/README.md +0 -0
  64. /haiway-0.10.1/src/haiway/py.typed → /haiway-0.10.11/examples/fastAPI/src/features/__int__.py +0 -0
  65. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/__init__.py +0 -0
  66. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/context/__init__.py +0 -0
  67. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/context/disposables.py +0 -0
  68. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/context/logging.py +0 -0
  69. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/context/metrics.py +0 -0
  70. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/context/state.py +0 -0
  71. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/context/tasks.py +0 -0
  72. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/context/types.py +0 -0
  73. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/helpers/__init__.py +0 -0
  74. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/helpers/asynchrony.py +0 -0
  75. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/helpers/caching.py +0 -0
  76. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/helpers/retries.py +0 -0
  77. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/helpers/throttling.py +0 -0
  78. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/helpers/timeouted.py +0 -0
  79. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/helpers/tracing.py +0 -0
  80. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/state/__init__.py +0 -0
  81. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/state/attributes.py +0 -0
  82. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/state/path.py +0 -0
  83. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/state/requirement.py +0 -0
  84. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/state/structure.py +0 -0
  85. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/state/validation.py +0 -0
  86. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/types/__init__.py +0 -0
  87. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/types/default.py +0 -0
  88. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/types/frozen.py +0 -0
  89. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/types/missing.py +0 -0
  90. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/utils/__init__.py +0 -0
  91. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/utils/always.py +0 -0
  92. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/utils/env.py +0 -0
  93. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/utils/freezing.py +0 -0
  94. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/utils/logs.py +0 -0
  95. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/utils/mimic.py +0 -0
  96. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/utils/noop.py +0 -0
  97. {haiway-0.10.1 → haiway-0.10.11}/src/haiway/utils/queue.py +0 -0
  98. {haiway-0.10.1 → haiway-0.10.11}/tests/test_async_queue.py +0 -0
  99. {haiway-0.10.1 → haiway-0.10.11}/tests/test_attribute_path.py +0 -0
  100. {haiway-0.10.1 → haiway-0.10.11}/tests/test_auto_retry.py +0 -0
  101. {haiway-0.10.1 → haiway-0.10.11}/tests/test_cache.py +0 -0
  102. {haiway-0.10.1 → haiway-0.10.11}/tests/test_context.py +0 -0
  103. {haiway-0.10.1 → haiway-0.10.11}/tests/test_state.py +0 -0
  104. {haiway-0.10.1 → haiway-0.10.11}/tests/test_streaming.py +0 -0
  105. {haiway-0.10.1 → haiway-0.10.11}/tests/test_timeout.py +0 -0
@@ -0,0 +1,35 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ pull_request:
9
+ branches:
10
+ - "*"
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ${{ matrix.os }}
15
+ strategy:
16
+ matrix:
17
+ os: [ubuntu-latest, macos-latest, windows-latest]
18
+ python-version: ["3.12", "3.13"]
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Install uv and set the python version
24
+ uses: astral-sh/setup-uv@v5
25
+ with:
26
+ python-version: ${{ matrix.python-version }}
27
+
28
+ - name: Install
29
+ run: uv sync --all-groups --all-extras --frozen --no-python-downloads
30
+
31
+ - name: Lint
32
+ run: uv run ruff check --output-format=github ./src ./tests
33
+
34
+ - name: Test
35
+ run: uv run pytest --rootdir= ./tests --doctest-modules --junitxml=junit/test-results.xml
@@ -0,0 +1,35 @@
1
+ name: publish
2
+
3
+ on:
4
+ release:
5
+ types:
6
+ - released
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ id-token: write
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ with:
16
+ ref: ${{ github.event.release.tag_name }}
17
+
18
+ - name: Install uv and set the python version
19
+ uses: astral-sh/setup-uv@v5
20
+ with:
21
+ python-version: 3.12
22
+
23
+ - name: Install
24
+ run: uv sync --all-groups --all-extras --frozen --no-python-downloads
25
+
26
+ - name: Lint
27
+ run: uv run ruff check --output-format=github ./src ./tests
28
+
29
+ - name: Test
30
+ run: uv run pytest --rootdir= ./tests --doctest-modules --junitxml=junit/test-results.xml
31
+
32
+ - name: Publish
33
+ env:
34
+ PROJECT_VERSION: ${{ github.event.release.tag_name }}
35
+ run: uv build && uv publish
@@ -0,0 +1,83 @@
1
+ ## macOS
2
+ .DS_Store
3
+ .AppleDouble
4
+ .LSOverride
5
+ ._*
6
+ .fseventsd
7
+ .TemporaryItems
8
+ .Trashes
9
+ .VolumeIcon.icns
10
+ .com.apple.timemachine.donotpresent
11
+ .AppleDB
12
+ .AppleDesktop
13
+ Network Trash Folder
14
+ Temporary Items
15
+ .apdisk
16
+
17
+ ## Python
18
+ __pycache__/
19
+ *.py[cod]
20
+ *$py.class
21
+ *.so
22
+ .Python
23
+ build/
24
+ develop-eggs/
25
+ dist/
26
+ downloads/
27
+ eggs/
28
+ .eggs/
29
+ parts/
30
+ sdist/
31
+ var/
32
+ wheels/
33
+ share/python-wheels/
34
+ *.egg-info/
35
+ .installed.cfg
36
+ *.egg
37
+ MANIFEST
38
+ *.manifest
39
+ *.spec
40
+ pip-log.txt
41
+ pip-delete-this-directory.txt
42
+ htmlcov/
43
+ .tox/
44
+ .nox/
45
+ .coverage
46
+ .coverage.*
47
+ .cache
48
+ nosetests.xml
49
+ coverage.xml
50
+ *.cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ *.mo
54
+ *.pot
55
+ .ipynb_checkpoints
56
+ .python-version
57
+ .env
58
+ .venv
59
+ .dev_venv
60
+ env/
61
+ venv/
62
+ ENV/
63
+ env.bak/
64
+ venv.bak/
65
+ .ropeproject
66
+ /site
67
+ .mypy_cache/
68
+ .dmypy.json
69
+ dmypy.json
70
+ .venv/
71
+ [Bb]in
72
+ [Ii]nclude
73
+ [Ll]ib
74
+ [Ll]ib64
75
+ [Ll]ocal
76
+ [Ss]cripts
77
+ pyvenv.cfg
78
+ pip-selfcheck.json
79
+
80
+ ## Editors
81
+ .vscode/
82
+ .idea/
83
+ local_cache/
@@ -0,0 +1,89 @@
1
+ SHELL := sh
2
+ .ONESHELL:
3
+ .SHELLFLAGS := -eu -c
4
+ .DELETE_ON_ERROR:
5
+
6
+ SOURCES_PATH := src
7
+ TESTS_PATH := tests
8
+
9
+ # load environment config from .env if able
10
+ -include .env
11
+
12
+ ifndef UV_VERSION
13
+ UV_VERSION := 0.6.2
14
+ endif
15
+
16
+ .PHONY: uv_check venv sync update format lint test release
17
+
18
+ # Check installed UV version and install if needed
19
+ uv_check:
20
+ @echo 'Checking uv version...'
21
+
22
+ # Install if not present
23
+ @if ! command -v uv > /dev/null; then \
24
+ echo '...installing uv...'; \
25
+ curl -LsSf https://github.com/astral-sh/uv/releases/download/$(UV_VERSION)/uv-installer.sh | sh; \
26
+ if [ $$? -ne 0 ]; then \
27
+ echo "...installing uv failed!"; \
28
+ exit 1; \
29
+ fi; \
30
+ fi
31
+
32
+ # Check version and update if needed
33
+ @if command -v uv > /dev/null; then \
34
+ CURRENT_VERSION=$$(uv --version | head -n1 | cut -d" " -f2); \
35
+ if [ "$$(printf "%s\n%s" "$(UV_VERSION)" "$$CURRENT_VERSION" | sort -V | head -n1)" != "$(UV_VERSION)" ]; then \
36
+ echo '...updating uv...'; \
37
+ curl -LsSf https://github.com/astral-sh/uv/releases/download/$(UV_VERSION)/uv-installer.sh | sh; \
38
+ if [ $$? -ne 0 ]; then \
39
+ echo "...updating uv failed!"; \
40
+ exit 1; \
41
+ fi; \
42
+ else \
43
+ echo '...uv version is up-to-date!'; \
44
+ fi; \
45
+ fi
46
+
47
+ # Setup virtual environment for local development.
48
+ venv: uv_check
49
+ @echo '# Preparing development environment...'
50
+ @echo '...cloning .env...'
51
+ @cp -n ./config/.env.example ./.env || :
52
+ @echo '...preparing git hooks...'
53
+ @cp -n ./config/pre-push ./.git/hooks/pre-push || :
54
+ @echo '...preparing venv...'
55
+ @uv sync --all-groups --all-extras --frozen --reinstall
56
+ @echo '...development environment ready! Activate venv using `. ./.venv/bin/activate`.'
57
+
58
+ # Sync environment with uv based on constraints
59
+ sync: uv_check
60
+ @echo '# Synchronizing dependencies...'
61
+ @uv sync --all-groups --all-extras --frozen
62
+ @echo '...finished!'
63
+
64
+ # Update and lock dependencies from pyproject.toml
65
+ update:
66
+ @echo '# Updating dependencies...'
67
+ @uv sync --all-groups --all-extras --upgrade
68
+ @echo '...finished!'
69
+
70
+ # Run formatter.
71
+ format:
72
+ @ruff check --quiet --fix $(SOURCES_PATH) $(TESTS_PATH)
73
+ @ruff format --quiet $(SOURCES_PATH) $(TESTS_PATH)
74
+
75
+ # Run linters and code checks.
76
+ lint:
77
+ @bandit -r $(SOURCES_PATH)
78
+ @ruff check $(SOURCES_PATH) $(TESTS_PATH)
79
+ @pyright --project ./
80
+
81
+ # Run tests suite.
82
+ test:
83
+ @python -B -m pytest -v --cov=$(SOURCES_PATH) --rootdir=$(TESTS_PATH)
84
+
85
+ release: lint test
86
+ @echo '# Preparing release...'
87
+ @uv build
88
+ @uv publish
89
+ @echo '...finished!'
@@ -1,7 +1,9 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: haiway
3
- Version: 0.10.1
3
+ Version: 0.10.11
4
4
  Summary: Framework for dependency injection and state management within structured concurrency model.
5
+ Project-URL: Homepage, https://miquido.com
6
+ Project-URL: Repository, https://github.com/miquido/haiway.git
5
7
  Maintainer-email: Kacper Kaliński <kacper.kalinski@miquido.com>
6
8
  License: MIT License
7
9
 
@@ -24,25 +26,22 @@ License: MIT License
24
26
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
27
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
28
  SOFTWARE.
27
- Project-URL: Homepage, https://miquido.com
28
- Project-URL: Repository, https://github.com/miquido/haiway.git
29
- Classifier: License :: OSI Approved :: MIT License
29
+ License-File: LICENSE
30
30
  Classifier: Intended Audience :: Developers
31
+ Classifier: License :: OSI Approved :: MIT License
31
32
  Classifier: Programming Language :: Python
32
- Classifier: Typing :: Typed
33
33
  Classifier: Topic :: Software Development
34
34
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
35
+ Classifier: Typing :: Typed
35
36
  Requires-Python: >=3.12
36
- Description-Content-Type: text/markdown
37
- License-File: LICENSE
38
37
  Provides-Extra: dev
39
- Requires-Dist: haiway; extra == "dev"
40
- Requires-Dist: ruff~=0.9; extra == "dev"
41
- Requires-Dist: pyright~=1.1; extra == "dev"
42
- Requires-Dist: bandit~=1.7; extra == "dev"
43
- Requires-Dist: pytest~=7.4; extra == "dev"
44
- Requires-Dist: pytest-cov~=4.1; extra == "dev"
45
- Requires-Dist: pytest-asyncio~=0.23; extra == "dev"
38
+ Requires-Dist: bandit~=1.7; extra == 'dev'
39
+ Requires-Dist: pyright~=1.1; extra == 'dev'
40
+ Requires-Dist: pytest-asyncio~=0.23; extra == 'dev'
41
+ Requires-Dist: pytest-cov~=4.1; extra == 'dev'
42
+ Requires-Dist: pytest~=7.4; extra == 'dev'
43
+ Requires-Dist: ruff~=0.9; extra == 'dev'
44
+ Description-Content-Type: text/markdown
46
45
 
47
46
  # 🚗 haiway 🚕 🚚 🚙
48
47
 
@@ -0,0 +1,57 @@
1
+ #!/bin/sh
2
+
3
+ if git rev-parse --verify HEAD >/dev/null 2>&1
4
+ then
5
+ against=HEAD
6
+ else
7
+ against=$(git hash-object -t tree /dev/null)
8
+ fi
9
+
10
+ remote="$1"
11
+ url="$2"
12
+
13
+ zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
14
+
15
+ while read local_ref local_oid remote_ref remote_oid
16
+ do
17
+ if test "$local_oid" = "$zero"
18
+ then
19
+ # Handle delete
20
+ :
21
+ else
22
+ if test "$remote_oid" = "$zero"
23
+ then
24
+ # New branch, examine all commits
25
+ range="$local_oid"
26
+ else
27
+ # Update to existing branch, examine new commits
28
+ range="$remote_oid..$local_oid"
29
+ fi
30
+
31
+ # Check for WIP commit
32
+ commit=$(git rev-list -n 1 --grep '^WIP' "$range")
33
+ if test -n "$commit"
34
+ then
35
+ echo >&2 "Found WIP commit in $local_ref, not pushing"
36
+ exit 1
37
+ fi
38
+ fi
39
+ done
40
+
41
+ . ./.venv/bin/activate
42
+
43
+ make lint
44
+
45
+ if test $? != 0
46
+ then
47
+ cat <<\EOF
48
+
49
+ Error: Linting failed.
50
+
51
+ Ensure project quality and make all linting rules pass!
52
+
53
+ EOF
54
+ exit 1
55
+ fi
56
+
57
+ exec git diff-index --check --cached $against --
@@ -0,0 +1,5 @@
1
+ *
2
+ !./pyproject.toml
3
+ !./config/unit.json
4
+ !./src
5
+ !./uv.lock
@@ -0,0 +1,37 @@
1
+ ARG PYTHON_TAG=3.12
2
+ ARG UNIT_TAG=1.32.1-python${PYTHON_TAG}
3
+
4
+ # SERVER #
5
+
6
+ FROM unit:${UNIT_TAG} AS server_builder
7
+
8
+ # copy only the parts needed for production
9
+ COPY ./src/integrations ./src/integrations
10
+ COPY ./src/solutions ./src/solutions
11
+ COPY ./src/features ./src/features
12
+ COPY ./src/server ./src/server
13
+
14
+ # install dependencies and packages
15
+ COPY --from=ghcr.io/astral-sh/uv:0.5.14 /uv /uvx /bin/
16
+
17
+ ENV UV_PROJECT_ENVIRONMENT="/usr/local/"
18
+
19
+ RUN --mount=type=bind,source=./uv.lock,target=./uv.lock --mount=type=bind,source=./pyproject.toml,target=./pyproject.toml uv sync --python python${PYTHON_TAG} --locked --no-editable --no-python-downloads --link-mode copy --compile-bytecode --only-group server
20
+
21
+ FROM server_builder AS server
22
+
23
+ # allow access to home directory for asyncpg library
24
+ RUN chgrp -R unit ${HOME} && chmod -R 050 ${HOME}
25
+
26
+ RUN apt-get update \
27
+ && apt-get upgrade -y \
28
+ && apt-get -y autoremove \
29
+ && apt-get clean \
30
+ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
31
+
32
+ # copy configuration
33
+ COPY ./config/unit.json /docker-entrypoint.d/config.json
34
+
35
+ CMD ["unitd", "--no-daemon", "--log", "/dev/stdout"]
36
+
37
+ # port 80 is already exposed by nginx unit image, can't change it...
@@ -0,0 +1,86 @@
1
+ SHELL := sh
2
+ .ONESHELL:
3
+ .SHELLFLAGS := -eu -c
4
+ .DELETE_ON_ERROR:
5
+
6
+ SOURCES_PATH := src
7
+
8
+ # load environment config from .env if able
9
+ -include .env
10
+
11
+ ifndef UV_VERSION
12
+ UV_VERSION := 0.5.14
13
+ endif
14
+
15
+ .PHONY: uv_check venv sync update format lint run docker_run
16
+
17
+ # Check installed UV version and install if needed
18
+ uv_check:
19
+ @echo 'Checking uv version...'
20
+
21
+ # Install if not present
22
+ @if ! command -v uv > /dev/null; then \
23
+ echo '...installing uv...'; \
24
+ curl -LsSf https://github.com/astral-sh/uv/releases/download/$(UV_VERSION)/uv-installer.sh | sh; \
25
+ if [ $$? -ne 0 ]; then \
26
+ echo "...installing uv failed!"; \
27
+ exit 1; \
28
+ fi; \
29
+ fi
30
+
31
+ # Check version and update if needed
32
+ @if command -v uv > /dev/null; then \
33
+ CURRENT_VERSION=$$(uv --version | head -n1 | cut -d" " -f2); \
34
+ if [ "$$(printf "%s\n%s" "$(UV_VERSION)" "$$CURRENT_VERSION" | sort -V | head -n1)" != "$(UV_VERSION)" ]; then \
35
+ echo '...updating uv...'; \
36
+ curl -LsSf https://github.com/astral-sh/uv/releases/download/$(UV_VERSION)/uv-installer.sh | sh; \
37
+ if [ $$? -ne 0 ]; then \
38
+ echo "...updating uv failed!"; \
39
+ exit 1; \
40
+ fi; \
41
+ else \
42
+ echo '...uv version is up-to-date!'; \
43
+ fi; \
44
+ fi
45
+
46
+ # Setup virtual environment for local development.
47
+ venv: uv_check
48
+ @echo '# Preparing development environment...'
49
+ @echo '...cloning .env...'
50
+ @cp -n ./config/.env.example ./.env || :
51
+ @echo '...preparing git hooks...'
52
+ @cp -n ./config/pre-push ./.git/hooks/pre-push || :
53
+ @echo '...preparing venv...'
54
+ @uv sync --all-groups --all-extras --frozen --reinstall
55
+ @echo '...development environment ready! Activate venv using `. ./.venv/bin/activate`.'
56
+
57
+ # Sync environment with uv based on constraints
58
+ sync: uv_check
59
+ @echo '# Synchronizing dependencies...'
60
+ @uv sync --all-groups --all-extras --frozen
61
+ @echo '...finished!'
62
+
63
+ # Update and lock dependencies from pyproject.toml
64
+ update:
65
+ @echo '# Updating dependencies...'
66
+ @uv sync --all-groups --all-extras --upgrade
67
+ @echo '...finished!'
68
+
69
+ # Run formatter.
70
+ format:
71
+ @ruff check --quiet --fix $(SOURCES_PATH)
72
+ @ruff format --quiet $(SOURCES_PATH)
73
+
74
+ # Run linters and code checks.
75
+ lint:
76
+ @bandit -r $(SOURCES_PATH)
77
+ @ruff check $(SOURCES_PATH)
78
+ @pyright --project ./
79
+
80
+ # Run the server
81
+ run:
82
+ @python -m server
83
+
84
+ # Run all services locally using docker-compose.
85
+ docker_run:
86
+ @docker compose up --force-recreate --build server
@@ -0,0 +1 @@
1
+ ## Haiway FastAPI Example
@@ -0,0 +1,11 @@
1
+ PYTHONOPTIMIZE=0
2
+ DEBUG_LOGGING=1
3
+ # Server
4
+ SERVER_PORT=8080
5
+ # Postgres
6
+ POSTGRES_DATABASE=postgres
7
+ POSTGRES_HOST=localhost
8
+ POSTGRES_PORT=5432
9
+ POSTGRES_USER=postgres
10
+ POSTGRES_PASSWORD=postgres
11
+ POSTGRES_SSLMODE=disable
@@ -0,0 +1,50 @@
1
+ {
2
+ "listeners": {
3
+ "*:80": {
4
+ "pass": "routes/api"
5
+ }
6
+ },
7
+ "routes": {
8
+ "api": [
9
+ {
10
+ "match": {
11
+ "uri": "/health"
12
+ },
13
+ "action": {
14
+ "return": 204
15
+ }
16
+ },
17
+ {
18
+ "match": {
19
+ "uri": "/*"
20
+ },
21
+ "action": {
22
+ "pass": "applications/server"
23
+ }
24
+ }
25
+ ]
26
+ },
27
+ "applications": {
28
+ "server": {
29
+ "type": "python",
30
+ "protocol": "asgi",
31
+ "path": "/",
32
+ "module": "server",
33
+ "callable": "app",
34
+ "processes": 1,
35
+ "environment": {
36
+ "PYTHONOPTIMIZE": "2",
37
+ "HOME": "."
38
+ }
39
+ }
40
+ },
41
+ "access_log": {
42
+ "path": "/dev/stdout",
43
+ "format": "$time_local [ACCESS] $request_line -> $status"
44
+ },
45
+ "settings": {
46
+ "http": {
47
+ "server_version": false
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,44 @@
1
+ services:
2
+ server:
3
+ depends_on:
4
+ postgres:
5
+ condition: service_healthy
6
+ links:
7
+ - postgres
8
+ build:
9
+ context: .
10
+ dockerfile: Dockerfile
11
+ target: server
12
+ ports:
13
+ - ${SERVER_PORT:-8080}:80
14
+ restart: no
15
+ environment:
16
+ PYTHONOPTIMIZE: ${PYTHONOPTIMIZE:-2}
17
+ DEBUG_LOGGING: ${DEBUG_LOGGING}
18
+ POSTGRES_DATABASE: ${POSTGRES_DATABASE}
19
+ POSTGRES_HOST: postgres
20
+ POSTGRES_PORT: 5432
21
+ POSTGRES_USER: ${POSTGRES_USER}
22
+ POSTGRES_SSLMODE: ${POSTGRES_SSLMODE:-prefer}
23
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
24
+
25
+ postgres:
26
+ image: postgres:16.3-alpine3.20
27
+ restart: always
28
+ environment:
29
+ POSTGRES_USER: ${POSTGRES_USER}
30
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
31
+ POSTGRES_DB: ${POSTGRES_DATABASE}
32
+ volumes:
33
+ - postgres_data:/var/lib/postgresql/data
34
+ ports:
35
+ - ${POSTGRES_PORT}:5432
36
+ healthcheck:
37
+ test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DATABASE}"]
38
+ interval: 10s
39
+ start_period: 10s
40
+ timeout: 10s
41
+ retries: 3
42
+
43
+ volumes:
44
+ postgres_data:
@@ -0,0 +1,65 @@
1
+ [build-system]
2
+ requires = ["setuptools"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "haiway_fastapi"
7
+ description = "Example of haiway usage with fastapi."
8
+ version = "0.1.0"
9
+ readme = "README.md"
10
+ maintainers = [
11
+ { name = "Kacper Kaliński", email = "kacper.kalinski@miquido.com" },
12
+ ]
13
+ requires-python = ">=3.12"
14
+ dependencies = [
15
+ "haiway @ git+https://github.com/miquido/haiway@main",
16
+ "asyncpg~=0.30",
17
+ "httpx~=0.28.0",
18
+ ]
19
+
20
+ [project.urls]
21
+ Homepage = "https://miquido.com"
22
+
23
+ [dependency-groups]
24
+ server = [
25
+ "haiway_fastapi",
26
+ "fastapi-slim~=0.115",
27
+ ]
28
+ dev = [
29
+ "haiway_fastapi",
30
+ "uvicorn~=0.30",
31
+ "ruff~=0.8.0",
32
+ "pyright~=1.1",
33
+ "bandit~=1.7",
34
+ ]
35
+
36
+ [tool.ruff]
37
+ target-version = "py312"
38
+ line-length = 100
39
+ extend-exclude = [".venv", ".git", ".cache"]
40
+ lint.select = ["E", "F", "A", "I", "B", "PL", "W", "C", "RUF", "UP"]
41
+ lint.ignore = []
42
+
43
+ [tool.ruff.lint.per-file-ignores]
44
+ "__init__.py" = ["F401", "E402"]
45
+ "./tests/*.py" = ["PLR2004"]
46
+
47
+ [tool.pyright]
48
+ pythonVersion = "3.12"
49
+ venvPath = "."
50
+ venv = ".venv"
51
+ include = ["./src"]
52
+ exclude = ["**/node_modules", "**/__pycache__"]
53
+ ignore = []
54
+ stubPath = "./stubs"
55
+ reportMissingImports = true
56
+ reportMissingTypeStubs = true
57
+ typeCheckingMode = "strict"
58
+ userFileIndexingLimit = -1
59
+ useLibraryCodeForTypes = true
60
+
61
+ [tool.setuptools]
62
+ include-package-data = true
63
+
64
+ [tool.setuptools.packages.find]
65
+ where = ["src"]
@@ -0,0 +1,5 @@
1
+ from features.todos.calls import complete_todo
2
+
3
+ __all__ = [
4
+ "complete_todo",
5
+ ]
@@ -0,0 +1,16 @@
1
+ from uuid import UUID
2
+
3
+ from haiway import ctx
4
+
5
+ from features.todos.state import Todos
6
+
7
+ __all__ = [
8
+ "complete_todo",
9
+ ]
10
+
11
+
12
+ async def complete_todo(
13
+ *,
14
+ identifier: UUID,
15
+ ) -> None:
16
+ await ctx.state(Todos).complete(identifier=identifier)
@@ -0,0 +1,12 @@
1
+ from haiway import State
2
+
3
+ from features.todos.types import TodoCompletion
4
+ from features.todos.user_tasks import complete_todo_task
5
+
6
+ __all__ = [
7
+ "Todos",
8
+ ]
9
+
10
+
11
+ class Todos(State):
12
+ complete: TodoCompletion = complete_todo_task