pico-sqlalchemy 0.2.1.dev0__tar.gz → 0.4.0__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 (95) hide show
  1. pico_sqlalchemy-0.4.0/.github/ISSUE_TEMPLATE/bug_report.yml +32 -0
  2. pico_sqlalchemy-0.4.0/.github/ISSUE_TEMPLATE/feature_request.yml +18 -0
  3. pico_sqlalchemy-0.4.0/.github/PULL_REQUEST_TEMPLATE.md +10 -0
  4. pico_sqlalchemy-0.4.0/.github/dependabot.yml +11 -0
  5. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/.github/workflows/ci.yml +24 -3
  6. pico_sqlalchemy-0.4.0/.github/workflows/codeql.yml +28 -0
  7. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/.github/workflows/docs.yml +5 -5
  8. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/.github/workflows/publish-to-pypi.yml +15 -3
  9. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/.github/workflows/sync-keywords.yml +2 -2
  10. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/AGENTS.md +4 -3
  11. {pico_sqlalchemy-0.2.1.dev0/docs → pico_sqlalchemy-0.4.0}/CHANGELOG.md +18 -0
  12. pico_sqlalchemy-0.4.0/CLAUDE.md +19 -0
  13. pico_sqlalchemy-0.4.0/CODE_OF_CONDUCT.md +31 -0
  14. pico_sqlalchemy-0.4.0/CONTRIBUTING.md +34 -0
  15. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/PKG-INFO +56 -26
  16. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/README.md +50 -24
  17. pico_sqlalchemy-0.4.0/SECURITY.md +23 -0
  18. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0/docs}/CHANGELOG.md +18 -0
  19. pico_sqlalchemy-0.4.0/docs/architecture.md +488 -0
  20. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/docs/development/project-tooling.md +3 -3
  21. pico_sqlalchemy-0.4.0/docs/faq.md +406 -0
  22. pico_sqlalchemy-0.4.0/docs/hooks.py +8 -0
  23. pico_sqlalchemy-0.4.0/docs/how-to/alembic.md +153 -0
  24. pico_sqlalchemy-0.4.0/docs/how-to/multiple-databases.md +217 -0
  25. pico_sqlalchemy-0.4.0/docs/how-to/testing.md +284 -0
  26. pico_sqlalchemy-0.4.0/docs/migration.md +198 -0
  27. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/docs/overview.md +1 -1
  28. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/docs/quickstart.md +1 -1
  29. pico_sqlalchemy-0.4.0/docs/reference/configuration.md +139 -0
  30. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/docs/reference/declarative-base.md +6 -1
  31. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/docs/reference/repository.md +2 -183
  32. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/docs/reference/transactions.md +6 -0
  33. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/docs/requirements.txt +1 -0
  34. pico_sqlalchemy-0.4.0/docs/skills.md +59 -0
  35. pico_sqlalchemy-0.4.0/examples/crud-async/README.md +25 -0
  36. pico_sqlalchemy-0.4.0/examples/crud-async/app/__init__.py +0 -0
  37. pico_sqlalchemy-0.4.0/examples/crud-async/app/main.py +47 -0
  38. pico_sqlalchemy-0.4.0/examples/crud-async/app/models.py +12 -0
  39. pico_sqlalchemy-0.4.0/examples/crud-async/app/repositories.py +43 -0
  40. pico_sqlalchemy-0.4.0/examples/crud-async/app/services.py +26 -0
  41. pico_sqlalchemy-0.4.0/examples/crud-async/config.yml +3 -0
  42. pico_sqlalchemy-0.4.0/examples/crud-async/requirements.txt +3 -0
  43. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/mkdocs.yml +14 -2
  44. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/pyproject.toml +28 -2
  45. pico_sqlalchemy-0.4.0/src/pico_sqlalchemy/__init__.py +51 -0
  46. pico_sqlalchemy-0.4.0/src/pico_sqlalchemy/_version.py +1 -0
  47. pico_sqlalchemy-0.4.0/src/pico_sqlalchemy/base.py +38 -0
  48. pico_sqlalchemy-0.4.0/src/pico_sqlalchemy/config.py +91 -0
  49. pico_sqlalchemy-0.4.0/src/pico_sqlalchemy/decorators.py +275 -0
  50. pico_sqlalchemy-0.4.0/src/pico_sqlalchemy/factory.py +95 -0
  51. pico_sqlalchemy-0.4.0/src/pico_sqlalchemy/interceptor.py +141 -0
  52. pico_sqlalchemy-0.4.0/src/pico_sqlalchemy/paging.py +115 -0
  53. pico_sqlalchemy-0.4.0/src/pico_sqlalchemy/py.typed +0 -0
  54. pico_sqlalchemy-0.4.0/src/pico_sqlalchemy/repository_interceptor.py +358 -0
  55. pico_sqlalchemy-0.4.0/src/pico_sqlalchemy/session.py +403 -0
  56. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/src/pico_sqlalchemy.egg-info/PKG-INFO +56 -26
  57. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/src/pico_sqlalchemy.egg-info/SOURCES.txt +26 -2
  58. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/src/pico_sqlalchemy.egg-info/requires.txt +1 -1
  59. pico_sqlalchemy-0.4.0/tests/conftest.py +57 -0
  60. pico_sqlalchemy-0.4.0/tests/test_coverage_boost_v2.py +276 -0
  61. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/tests/test_interceptor.py +9 -25
  62. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/tests/test_ioc_integration.py +10 -26
  63. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/tests/test_pagination_sort.py +18 -40
  64. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/tests/test_repository_interceptor_coverage.py +30 -41
  65. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/tests/test_repository_query.py +12 -35
  66. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/tests/test_session_propagation.py +5 -16
  67. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/tests/test_transaction_manager.py +4 -6
  68. pico_sqlalchemy-0.4.0/tests/test_transaction_scope.py +133 -0
  69. pico_sqlalchemy-0.2.1.dev0/CLAUDE.md +0 -19
  70. pico_sqlalchemy-0.2.1.dev0/docs/architecture.md +0 -232
  71. pico_sqlalchemy-0.2.1.dev0/docs/faq.md +0 -136
  72. pico_sqlalchemy-0.2.1.dev0/docs/reference/configuration.md +0 -106
  73. pico_sqlalchemy-0.2.1.dev0/docs/skills.md +0 -117
  74. pico_sqlalchemy-0.2.1.dev0/manage.sh +0 -65
  75. pico_sqlalchemy-0.2.1.dev0/src/pico_sqlalchemy/__init__.py +0 -27
  76. pico_sqlalchemy-0.2.1.dev0/src/pico_sqlalchemy/_version.py +0 -1
  77. pico_sqlalchemy-0.2.1.dev0/src/pico_sqlalchemy/base.py +0 -8
  78. pico_sqlalchemy-0.2.1.dev0/src/pico_sqlalchemy/config.py +0 -22
  79. pico_sqlalchemy-0.2.1.dev0/src/pico_sqlalchemy/decorators.py +0 -111
  80. pico_sqlalchemy-0.2.1.dev0/src/pico_sqlalchemy/factory.py +0 -41
  81. pico_sqlalchemy-0.2.1.dev0/src/pico_sqlalchemy/interceptor.py +0 -61
  82. pico_sqlalchemy-0.2.1.dev0/src/pico_sqlalchemy/paging.py +0 -50
  83. pico_sqlalchemy-0.2.1.dev0/src/pico_sqlalchemy/repository_interceptor.py +0 -184
  84. pico_sqlalchemy-0.2.1.dev0/src/pico_sqlalchemy/session.py +0 -212
  85. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/.coveragerc +0 -0
  86. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/LICENSE +0 -0
  87. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/MANIFEST.in +0 -0
  88. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/docs/index.md +0 -0
  89. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/docs/javascripts/extra.js +0 -0
  90. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/docs/stylesheets/extra.css +0 -0
  91. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/setup.cfg +0 -0
  92. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/src/pico_sqlalchemy.egg-info/dependency_links.txt +0 -0
  93. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/src/pico_sqlalchemy.egg-info/entry_points.txt +0 -0
  94. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/src/pico_sqlalchemy.egg-info/top_level.txt +0 -0
  95. {pico_sqlalchemy-0.2.1.dev0 → pico_sqlalchemy-0.4.0}/tox.ini +0 -0
@@ -0,0 +1,32 @@
1
+ name: Bug Report
2
+ description: Report a bug in pico-sqlalchemy
3
+ labels: ["bug"]
4
+ body:
5
+ - type: textarea
6
+ id: description
7
+ attributes:
8
+ label: Description
9
+ description: What happened?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: reproduction
14
+ attributes:
15
+ label: Steps to Reproduce
16
+ description: Minimal code or steps to reproduce the issue.
17
+ validations:
18
+ required: true
19
+ - type: input
20
+ id: version
21
+ attributes:
22
+ label: pico-sqlalchemy version
23
+ placeholder: "0.2.0"
24
+ validations:
25
+ required: true
26
+ - type: input
27
+ id: python-version
28
+ attributes:
29
+ label: Python version
30
+ placeholder: "3.11"
31
+ validations:
32
+ required: true
@@ -0,0 +1,18 @@
1
+ name: Feature Request
2
+ description: Suggest an enhancement for pico-sqlalchemy
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: Problem
9
+ description: What problem does this solve?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: solution
14
+ attributes:
15
+ label: Proposed Solution
16
+ description: How should it work?
17
+ validations:
18
+ required: true
@@ -0,0 +1,10 @@
1
+ ## Summary
2
+
3
+ <!-- Brief description of the changes -->
4
+
5
+ ## Checklist
6
+
7
+ - [ ] Tests pass (`pytest tests/ -v`)
8
+ - [ ] Code formatted (`ruff format src/ tests/`)
9
+ - [ ] Lint clean (`ruff check src/ tests/`)
10
+ - [ ] CHANGELOG.md updated (if user-facing change)
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+
8
+ - package-ecosystem: "pip"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
@@ -3,8 +3,23 @@ name: CI & Coverage
3
3
  on:
4
4
  push:
5
5
  branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
6
8
 
7
9
  jobs:
10
+ lint:
11
+ name: Lint & Format
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v6
15
+ - uses: actions/setup-python@v6
16
+ with:
17
+ python-version: '3.11'
18
+ cache: pip
19
+ - run: pip install ruff
20
+ - run: ruff check src/ tests/
21
+ - run: ruff format --check src/ tests/
22
+
8
23
  tests:
9
24
  name: Tests (Python ${{ matrix.python-version }})
10
25
  runs-on: ubuntu-latest
@@ -15,12 +30,12 @@ jobs:
15
30
 
16
31
  steps:
17
32
  - name: Checkout
18
- uses: actions/checkout@v4
33
+ uses: actions/checkout@v6
19
34
  with:
20
35
  fetch-depth: 0
21
36
 
22
37
  - name: Set up Python ${{ matrix.python-version }}
23
- uses: actions/setup-python@v5
38
+ uses: actions/setup-python@v6
24
39
  with:
25
40
  python-version: ${{ matrix.python-version }}
26
41
  cache: pip
@@ -30,6 +45,12 @@ jobs:
30
45
  python -m pip install --upgrade pip
31
46
  pip install tox
32
47
 
48
+ - name: Cache tox environments
49
+ uses: actions/cache@v5
50
+ with:
51
+ path: .tox
52
+ key: tox-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml', 'tox.ini') }}
53
+
33
54
  - name: Install build dependencies
34
55
  run: |
35
56
  sudo apt-get update
@@ -58,7 +79,7 @@ jobs:
58
79
  needs: tests
59
80
  steps:
60
81
  - name: Checkout (for repo context)
61
- uses: actions/checkout@v4
82
+ uses: actions/checkout@v6
62
83
 
63
84
  - name: Download all coverage artifacts
64
85
  uses: actions/download-artifact@v4
@@ -0,0 +1,28 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+ schedule:
9
+ - cron: '0 6 * * 1'
10
+
11
+ jobs:
12
+ analyze:
13
+ name: Analyze (Python)
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ security-events: write
17
+ contents: read
18
+
19
+ steps:
20
+ - uses: actions/checkout@v6
21
+
22
+ - name: Initialize CodeQL
23
+ uses: github/codeql-action/init@v4
24
+ with:
25
+ languages: python
26
+
27
+ - name: Perform CodeQL Analysis
28
+ uses: github/codeql-action/analyze@v4
@@ -29,11 +29,11 @@ jobs:
29
29
  if: github.event_name == 'pull_request'
30
30
  runs-on: ubuntu-latest
31
31
  steps:
32
- - uses: actions/checkout@v4
32
+ - uses: actions/checkout@v6
33
33
  with:
34
34
  fetch-depth: 0
35
35
 
36
- - uses: actions/setup-python@v5
36
+ - uses: actions/setup-python@v6
37
37
  with:
38
38
  python-version: '3.11'
39
39
  cache: 'pip'
@@ -51,7 +51,7 @@ jobs:
51
51
  pip install linkchecker
52
52
  python -m http.server --directory site 8000 &
53
53
  sleep 3
54
- linkchecker http://127.0.0.1:8000 --check-extern || true
54
+ linkchecker http://127.0.0.1:8000 --check-extern
55
55
 
56
56
  deploy:
57
57
  if: github.event_name != 'pull_request'
@@ -61,11 +61,11 @@ jobs:
61
61
  url: ${{ steps.deployment.outputs.page_url }}
62
62
 
63
63
  steps:
64
- - uses: actions/checkout@v4
64
+ - uses: actions/checkout@v6
65
65
  with:
66
66
  fetch-depth: 0
67
67
 
68
- - uses: actions/setup-python@v5
68
+ - uses: actions/setup-python@v6
69
69
  with:
70
70
  python-version: '3.11'
71
71
  cache: 'pip'
@@ -12,12 +12,12 @@ jobs:
12
12
  contents: read
13
13
 
14
14
  steps:
15
- - uses: actions/checkout@v4
15
+ - uses: actions/checkout@v6
16
16
  with:
17
17
  fetch-depth: 0
18
18
 
19
19
  - name: Set up Python
20
- uses: actions/setup-python@v5
20
+ uses: actions/setup-python@v6
21
21
  with:
22
22
  python-version: '3.x'
23
23
 
@@ -27,10 +27,22 @@ jobs:
27
27
  - name: Build package
28
28
  run: python -m build
29
29
 
30
+ - name: Reject non-clean versions (.dev / .post)
31
+ run: |
32
+ python - <<'PY'
33
+ import glob, sys
34
+ whl = sorted(glob.glob('dist/*.whl'))[0]
35
+ ver = whl.split('-')[1]
36
+ print(f"Built version: {ver}")
37
+ if 'dev' in ver or 'post' in ver:
38
+ sys.exit(f"::error::Refusing to publish non-clean version '{ver}'. "
39
+ "Create the GitHub Release from an exact version tag (e.g. v0.4.0).")
40
+ PY
41
+
30
42
  - name: Publish to PyPI
31
43
  uses: pypa/gh-action-pypi-publish@release/v1
32
44
  with:
33
45
  skip-existing: true
34
46
  verify-metadata: true
35
- attestations: false
47
+ attestations: true
36
48
 
@@ -18,10 +18,10 @@ jobs:
18
18
 
19
19
  steps:
20
20
  - name: Checkout Repository
21
- uses: actions/checkout@v4
21
+ uses: actions/checkout@v6
22
22
 
23
23
  - name: Set up Python
24
- uses: actions/setup-python@v4
24
+ uses: actions/setup-python@v6
25
25
  with:
26
26
  python-version: '3.11'
27
27
 
@@ -35,9 +35,10 @@ src/pico_sqlalchemy/
35
35
  - **Propagation modes**: REQUIRED, REQUIRES_NEW, MANDATORY, NEVER, NOT_SUPPORTED, SUPPORTS
36
36
  - **Priority chain**: `@transactional` > `@query` (read-only) > `@repository` (read-write)
37
37
  - **`SessionManager`**: Created by `SqlAlchemyFactory` (not `@component`). Manages engine, sessions, transactions
38
- - **`_tx_context` ContextVar**: Holds `TransactionContext` for session propagation. Separate from pico-ioc's "transaction" scope (which is for DI caching)
38
+ - **`_tx_context` ContextVar**: Holds `TransactionContext` (the session) for propagation across nested calls the *session* side of a transaction
39
+ - **`"transaction"` DI scope**: `TransactionalInterceptor` activates pico-ioc's `"transaction"` scope (with `cleanup=True`) whenever a *new* transaction starts (REQUIRES_NEW, or REQUIRED with no enclosing tx). So a `scope="transaction"` component is one instance per transaction (Unit-of-Work / identity-map), released with its `@cleanup` hooks when the tx ends. The session ContextVar and the DI scope are two facets of one boundary
39
40
  - **`get_session(manager)`**: Returns current session from active transaction context
40
- - **Non-transactional paths** (NEVER, NOT_SUPPORTED, SUPPORTS without tx): Still set `TransactionContext` so `get_session()` works
41
+ - **Non-transactional paths** (NEVER, NOT_SUPPORTED, SUPPORTS without tx): Still set `TransactionContext` so `get_session()` works, but open no DI `"transaction"` scope (resolving a `scope="transaction"` component there raises `ScopeError`)
41
42
 
42
43
  ## Code Style
43
44
 
@@ -59,4 +60,4 @@ src/pico_sqlalchemy/
59
60
 
60
61
  - Do not modify `_version.py`
61
62
  - Do not add `@component` to `SessionManager` (factory creates it)
62
- - `_tx_context` ContextVar is intentional and separate from pico-ioc scope system
63
+ - `_tx_context` (session propagation) and the pico-ioc `"transaction"` DI scope are bound to one boundary by `TransactionalInterceptor` — keep them coordinated; do not reintroduce a second, independent transaction concept
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.h
7
7
 
8
8
  ---
9
9
 
10
+ ## [0.4.0] - 2026-06-07
11
+
12
+ ### Added
13
+ - **Transaction-scoped DI**: `TransactionalInterceptor` now binds pico-ioc's `"transaction"` DI scope to the database transaction boundary. When a *new* transaction starts (`REQUIRES_NEW`, or `REQUIRED` with no enclosing transaction) it activates a fresh `"transaction"` scope (via `container.scope(..., cleanup=True)`) for the duration of the call, so components registered with `scope="transaction"` live exactly one transaction and run their `@cleanup` hooks when it ends. Joins reuse the enclosing scope. Requires **pico-ioc >= 2.2.6**.
14
+ - `tests/test_transaction_scope.py`: covers one-instance-per-transaction, sharing within a transaction, `REQUIRES_NEW` scope push/restore, fail-fast resolution outside a transaction, and `@cleanup` on transaction end.
15
+
16
+ ### Changed
17
+ - Bumped `pico-ioc` dependency to `>= 2.2.6`.
18
+
19
+ ---
20
+
21
+ ## [0.3.0] - 2026-02-20
22
+
23
+ ### Changed
24
+ - **Breaking:** Renamed `DatabaseConfigurer.configure(engine)` to `configure_database(engine)` to avoid protocol collision with `FastApiConfigurer.configure(app)` in structural typing.
25
+
26
+ ---
27
+
10
28
  ## [0.2.0] - 2026-02-06
11
29
 
12
30
  ### Added
@@ -0,0 +1,19 @@
1
+ Read and follow ./AGENTS.md for project conventions.
2
+
3
+ ## Pico Ecosystem Context
4
+
5
+ pico-sqlalchemy provides SQLAlchemy integration for pico-ioc. It uses:
6
+ - `@factory` + `@provides` for SessionManager creation
7
+ - `@configured` for DatabaseSettings
8
+ - `MethodInterceptor` for both `TransactionalInterceptor` and `RepositoryQueryInterceptor`
9
+ - Auto-discovered via `pico_boot.modules` entry point
10
+
11
+ ## Key Reminders
12
+
13
+ - pico-ioc dependency: `>= 2.2.6` (needs `container.scope(..., cleanup=True)`)
14
+ - **NEVER change `version_scheme`** in pyproject.toml. It MUST remain `"post-release"`. Changing it to `"guess-next-dev"` causes `.dev0` versions to leak to PyPI. This was already fixed once — do not revert it.
15
+ - requires-python >= 3.11
16
+ - Commit messages: one line only
17
+ - `@transactional` works both with and without parentheses (like `@repository`)
18
+ - `SessionManager` has NO `@component` decorator - it's created by the factory
19
+ - `_tx_context` ContextVar is the *session* side of a transaction (propagation across nested calls). `TransactionalInterceptor` binds pico-ioc's `"transaction"` DI scope to the *same* boundary: when a new transaction starts (REQUIRES_NEW, or REQUIRED with no enclosing tx) it activates a fresh `"transaction"` scope (with `cleanup=True`) for the call, so `scope="transaction"` components live exactly one transaction. They are two facets of one boundary, not separate mechanisms.
@@ -0,0 +1,31 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone.
7
+
8
+ ## Our Standards
9
+
10
+ Examples of behavior that contributes to a positive environment:
11
+
12
+ * Using welcoming and inclusive language
13
+ * Being respectful of differing viewpoints and experiences
14
+ * Gracefully accepting constructive criticism
15
+ * Focusing on what is best for the community
16
+
17
+ Examples of unacceptable behavior:
18
+
19
+ * Trolling, insulting or derogatory comments, and personal or political attacks
20
+ * Public or private harassment
21
+ * Publishing others' private information without explicit permission
22
+
23
+ ## Enforcement
24
+
25
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
26
+ reported to **dperezcabrera@gmail.com**. All complaints will be reviewed
27
+ and investigated promptly and fairly.
28
+
29
+ ## Attribution
30
+
31
+ This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1.
@@ -0,0 +1,34 @@
1
+ # Contributing to Pico-SQLAlchemy
2
+
3
+ ## Development Setup
4
+
5
+ ```bash
6
+ python -m venv .venv
7
+ source .venv/bin/activate
8
+ pip install -e ".[test]"
9
+ pip install ruff
10
+ ```
11
+
12
+ ## Running Tests
13
+
14
+ ```bash
15
+ pytest tests/ -v # Run tests
16
+ tox # Full matrix (3.11-3.14)
17
+ ```
18
+
19
+ ## Code Style
20
+
21
+ - Python 3.11+
22
+ - Format with `ruff format src/ tests/`
23
+ - Lint with `ruff check src/ tests/`
24
+
25
+ ## Pull Requests
26
+
27
+ 1. Fork the repository
28
+ 2. Create a feature branch
29
+ 3. Ensure tests pass and code is formatted
30
+ 4. Submit a PR with a clear description
31
+
32
+ ## Reporting Issues
33
+
34
+ Use [GitHub Issues](https://github.com/dperezcabrera/pico-sqlalchemy/issues) for bugs and feature requests.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pico-sqlalchemy
3
- Version: 0.2.1.dev0
3
+ Version: 0.4.0
4
4
  Summary: Pico-ioc integration for SQLAlchemy. Adds Spring-style transactional support, configuration, and helpers.
5
5
  Author-email: David Perez Cabrera <dperezcabrera@gmail.com>
6
6
  License: MIT License
@@ -28,6 +28,8 @@ License: MIT License
28
28
  Project-URL: Homepage, https://github.com/dperezcabrera/pico-sqlalchemy
29
29
  Project-URL: Repository, https://github.com/dperezcabrera/pico-sqlalchemy
30
30
  Project-URL: Issue Tracker, https://github.com/dperezcabrera/pico-sqlalchemy/issues
31
+ Project-URL: Documentation, https://dperezcabrera.github.io/pico-sqlalchemy/
32
+ Project-URL: Changelog, https://github.com/dperezcabrera/pico-sqlalchemy/blob/main/CHANGELOG.md
31
33
  Keywords: ioc,di,dependency injection,sqlalchemy,transaction,orm,inversion of control,asyncio
32
34
  Classifier: Development Status :: 4 - Beta
33
35
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
@@ -38,12 +40,14 @@ Classifier: Programming Language :: Python :: 3.11
38
40
  Classifier: Programming Language :: Python :: 3.12
39
41
  Classifier: Programming Language :: Python :: 3.13
40
42
  Classifier: Programming Language :: Python :: 3.14
43
+ Classifier: Intended Audience :: Developers
41
44
  Classifier: License :: OSI Approved :: MIT License
42
45
  Classifier: Operating System :: OS Independent
46
+ Classifier: Typing :: Typed
43
47
  Requires-Python: >=3.11
44
48
  Description-Content-Type: text/markdown
45
49
  License-File: LICENSE
46
- Requires-Dist: pico-ioc>=2.2.0
50
+ Requires-Dist: pico-ioc>=2.2.6
47
51
  Requires-Dist: sqlalchemy>=2.0
48
52
  Provides-Extra: async
49
53
  Requires-Dist: asyncpg>=0.29.0; extra == "async"
@@ -53,7 +57,7 @@ Requires-Dist: pytest-asyncio>=0.23.5; extra == "test"
53
57
  Requires-Dist: pytest-cov>=5; extra == "test"
54
58
  Dynamic: license-file
55
59
 
56
- # 📦 pico-sqlalchemy
60
+ # pico-sqlalchemy
57
61
 
58
62
  [![PyPI](https://img.shields.io/pypi/v/pico-sqlalchemy.svg)](https://pypi.org/project/pico-sqlalchemy/)
59
63
  [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dperezcabrera/pico-sqlalchemy)
@@ -64,6 +68,7 @@ Dynamic: license-file
64
68
  [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-sqlalchemy\&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-sqlalchemy)
65
69
  [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-sqlalchemy\&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-sqlalchemy)
66
70
  [![Docs](https://img.shields.io/badge/Docs-pico--sqlalchemy-blue?style=flat&logo=readthedocs&logoColor=white)](https://dperezcabrera.github.io/pico-sqlalchemy/)
71
+ [![Interactive Lab](https://img.shields.io/badge/Learn-online-green?style=flat&logo=python&logoColor=white)](https://dperezcabrera.github.io/pico-learn/)
67
72
 
68
73
  # Pico-SQLAlchemy
69
74
 
@@ -71,14 +76,14 @@ Dynamic: license-file
71
76
 
72
77
  It brings constructor-based dependency injection, **implicit transaction management**, and powerful **declarative queries** using pure Python and SQLAlchemy’s Async ORM.
73
78
 
74
- > 🐍 **Requires Python 3.11+**
75
- > 🚀 **Async-Native:** Built entirely on `AsyncSession` and `create_async_engine`.
76
- > **Zero-Boilerplate:** Repositories are transactional by default.
77
- > 🔍 **Declarative Queries:** Define SQL or expressions in decorators; the library executes them for you.
79
+ > **Requires Python 3.11+**
80
+ > **Async-Native:** Built entirely on `AsyncSession` and `create_async_engine`.
81
+ > **Zero-Boilerplate:** Repositories are transactional by default.
82
+ > **Declarative Queries:** Define SQL or expressions in decorators; the library executes them for you.
78
83
 
79
84
  ---
80
85
 
81
- ## 🎯 Why pico-sqlalchemy?
86
+ ## Why pico-sqlalchemy?
82
87
 
83
88
  Most Python apps suffer from manual session handling (`async with session...`), scattered transaction logic, and verbose repository patterns.
84
89
 
@@ -94,7 +99,7 @@ Most Python apps suffer from manual session handling (`async with session...`),
94
99
 
95
100
  ---
96
101
 
97
- ## 🧱 Core Features
102
+ ## Core Features
98
103
 
99
104
  * **Implicit Transactions:** Methods inside `@repository` are automatically **Read-Write** transactional.
100
105
  * **Declarative Queries:** Use `@query` to run SQL or Expressions automatically (defaults to **Read-Only**).
@@ -104,7 +109,7 @@ Most Python apps suffer from manual session handling (`async with session...`),
104
109
 
105
110
  ---
106
111
 
107
- ## 📦 Installation
112
+ ## Installation
108
113
 
109
114
  ```bash
110
115
  pip install pico-sqlalchemy
@@ -119,7 +124,7 @@ pip install asyncpg # for PostgreSQL
119
124
 
120
125
  -----
121
126
 
122
- ## 🚀 Quick Example
127
+ ## Quick Example
123
128
 
124
129
  ### 1\. Define Model
125
130
 
@@ -214,7 +219,7 @@ if __name__ == "__main__":
214
219
 
215
220
  -----
216
221
 
217
- ## Transaction Hierarchy & Rules
222
+ ## Transaction Hierarchy & Rules
218
223
 
219
224
  Pico-SQLAlchemy applies a "Best Effort" strategy to determine transaction configuration. The priority order (highest wins) is:
220
225
 
@@ -232,7 +237,7 @@ Pico-SQLAlchemy applies a "Best Effort" strategy to determine transaction config
232
237
  async def update_user(self): ...
233
238
  ```
234
239
 
235
- 👉 **Result:** Active Read-Write Transaction (Implicit from `@repository`).
240
+ **Result:** Active Read-Write Transaction (Implicit from `@repository`).
236
241
 
237
242
  2. **Query Method:**
238
243
 
@@ -241,7 +246,7 @@ Pico-SQLAlchemy applies a "Best Effort" strategy to determine transaction config
241
246
  async def get_data(self): ...
242
247
  ```
243
248
 
244
- 👉 **Result:** Active Read-Only Transaction (Implicit from `@query`).
249
+ **Result:** Active Read-Only Transaction (Implicit from `@query`).
245
250
 
246
251
  3. **Manual Override:**
247
252
 
@@ -250,11 +255,29 @@ Pico-SQLAlchemy applies a "Best Effort" strategy to determine transaction config
250
255
  async def complex_report(self): ...
251
256
  ```
252
257
 
253
- 👉 **Result:** Active Read-Only Transaction (Explicit override).
258
+ **Result:** Active Read-Only Transaction (Explicit override).
259
+
260
+ ### Transaction-scoped components *(v0.4.0+)*
261
+
262
+ Beyond managing the SQLAlchemy session, the interceptor binds pico-ioc's **`"transaction"` DI scope** to the same boundary. A component registered with `scope="transaction"` is instantiated **once per database transaction** and torn down (running its `@cleanup` hooks) when that transaction ends:
263
+
264
+ ```python
265
+ @component(scope="transaction")
266
+ class UnitOfWorkAudit:
267
+ def __init__(self):
268
+ self.events: list[str] = []
269
+
270
+ @cleanup
271
+ def flush(self):
272
+ # runs exactly when the enclosing transaction ends
273
+ ...
274
+ ```
275
+
276
+ A **new** transaction (`REQUIRES_NEW`, or `REQUIRED` with no enclosing transaction) opens a fresh scope; **joins reuse** the enclosing one — so the session boundary and the DI lifetime are two facets of a single transaction. Requires **pico-ioc ≥ 2.2.6**.
254
277
 
255
278
  -----
256
279
 
257
- ## 🔍 Declarative Queries in Depth
280
+ ## Declarative Queries in Depth
258
281
 
259
282
  The `@query` decorator eliminates boilerplate for common fetches.
260
283
 
@@ -289,7 +312,7 @@ async def find_active(self, page: PageRequest) -> Page[User]: ...
289
312
 
290
313
  -----
291
314
 
292
- ## 🧪 Testing
315
+ ## Testing
293
316
 
294
317
  Testing is simple because you can override the configuration or the components easily using Pico-IoC.
295
318
 
@@ -307,7 +330,7 @@ async def test_service():
307
330
 
308
331
  -----
309
332
 
310
- ## 💡 Architecture Overview
333
+ ## Architecture Overview
311
334
 
312
335
  ```
313
336
  ┌─────────────────────────────┐
@@ -333,19 +356,26 @@ async def test_service():
333
356
 
334
357
  -----
335
358
 
336
- ## 🤖 Claude Code Skills
359
+ ## AI Coding Skills
360
+
361
+ Install [Claude Code](https://code.claude.com) or [OpenAI Codex](https://openai.com/index/introducing-codex/) skills for AI-assisted development with pico-sqlalchemy:
362
+
363
+ ```bash
364
+ curl -sL https://raw.githubusercontent.com/dperezcabrera/pico-skills/main/install.sh | bash -s -- sqlalchemy
365
+ ```
337
366
 
338
- This project includes pre-designed skills for [Claude Code](https://claude.ai/claude-code), enabling AI-assisted development with pico-sqlalchemy patterns.
367
+ | Command | Description |
368
+ |---------|-------------|
369
+ | `/add-repository` | Add SQLAlchemy entities and repositories with transactions |
370
+ | `/add-component` | Add components, factories, interceptors, settings |
371
+ | `/add-tests` | Generate tests for pico components |
339
372
 
340
- | Skill | Command | Description |
341
- |-------|---------|-------------|
342
- | **Pico SQLAlchemy Repository** | `/pico-sqlalchemy` | Creates models, repositories and services with DI |
343
- | **Pico Test Generator** | `/pico-tests` | Generates tests for pico-framework components |
373
+ All skills: `curl -sL https://raw.githubusercontent.com/dperezcabrera/pico-skills/main/install.sh | bash`
344
374
 
345
- See [Skills documentation](docs/skills.md) for full details and installation instructions.
375
+ See [pico-skills](https://github.com/dperezcabrera/pico-skills) for details.
346
376
 
347
377
  ---
348
378
 
349
- ## 📝 License
379
+ ## License
350
380
 
351
381
  MIT