pydantic-marshmallow 1.0.0__tar.gz → 1.1.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 (88) hide show
  1. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/.github/instructions/Default.instructions.md +27 -1
  2. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/.github/instructions/Git.instructions.md +2 -2
  3. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/.github/instructions/Implementation.instructions.md +13 -2
  4. pydantic_marshmallow-1.1.0/.github/workflows/ci.yml +210 -0
  5. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/.github/workflows/release.yml +3 -6
  6. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/.gitignore +4 -0
  7. pydantic_marshmallow-1.1.0/.pre-commit-config.yaml +55 -0
  8. pydantic_marshmallow-1.1.0/.releaserc.json +107 -0
  9. pydantic_marshmallow-1.1.0/.vscode/settings.json +40 -0
  10. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/CAPABILITY_MATRIX.md +13 -5
  11. {pydantic_marshmallow-1.0.0/src/pydantic_marshmallow.egg-info → pydantic_marshmallow-1.1.0}/PKG-INFO +152 -9
  12. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/README.md +145 -1
  13. pydantic_marshmallow-1.1.0/SECURITY.md +15 -0
  14. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/benchmarks/__init__.py +1 -0
  15. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/benchmarks/benchmark_framework.py +124 -53
  16. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/benchmarks/run_benchmarks.py +7 -8
  17. pydantic_marshmallow-1.1.0/codecov.yml +31 -0
  18. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/examples.md +1 -1
  19. pydantic_marshmallow-1.1.0/docs/getting-started/installation.md +84 -0
  20. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/examples/usage.py +15 -0
  21. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/mkdocs.yml +0 -1
  22. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/pydantic-marshmallow.code-workspace +36 -0
  23. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/pyproject.toml +40 -28
  24. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/src/pydantic_marshmallow/__init__.py +11 -5
  25. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/src/pydantic_marshmallow/bridge.py +326 -98
  26. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/src/pydantic_marshmallow/field_conversion.py +28 -7
  27. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/src/pydantic_marshmallow/type_mapping.py +67 -30
  28. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0/src/pydantic_marshmallow.egg-info}/PKG-INFO +152 -9
  29. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/src/pydantic_marshmallow.egg-info/SOURCES.txt +4 -1
  30. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/src/pydantic_marshmallow.egg-info/requires.txt +5 -6
  31. pydantic_marshmallow-1.1.0/tests/compatibility/conftest.py +250 -0
  32. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/compatibility/test_flask_marshmallow.py +12 -49
  33. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/compatibility/test_flask_rebar.py +12 -6
  34. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/compatibility/test_webargs.py +1 -12
  35. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_advanced_hooks.py +1 -6
  36. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_combinations.py +18 -15
  37. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_compatibility.py +10 -15
  38. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_error_handling.py +1 -5
  39. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_extended_coverage.py +1 -10
  40. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_partial_and_unknown.py +6 -8
  41. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_schema_parameters.py +1 -6
  42. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/uv.lock +125 -74
  43. pydantic_marshmallow-1.0.0/.github/workflows/ci.yml +0 -91
  44. pydantic_marshmallow-1.0.0/.releaserc.json +0 -37
  45. pydantic_marshmallow-1.0.0/SECURITY.md +0 -21
  46. pydantic_marshmallow-1.0.0/docs/changelog.md +0 -37
  47. pydantic_marshmallow-1.0.0/docs/getting-started/installation.md +0 -43
  48. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/.github/instructions/Change_Size.instructions.md +0 -0
  49. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/.github/instructions/Compatibility_Analysis.instructions.md +0 -0
  50. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/.github/instructions/Coverage.instructions.md +0 -0
  51. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/.github/workflows/docs.yml +0 -0
  52. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/LICENSE +0 -0
  53. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/api/errors.md +0 -0
  54. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/api/hybrid.md +0 -0
  55. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/api/index.md +0 -0
  56. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/api/schema.md +0 -0
  57. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/api/validators.md +0 -0
  58. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/getting-started/quickstart.md +0 -0
  59. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/guide/basic-usage.md +0 -0
  60. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/guide/ecosystem.md +0 -0
  61. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/guide/field-options.md +0 -0
  62. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/guide/hooks.md +0 -0
  63. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/guide/nested-models.md +0 -0
  64. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/docs/index.md +0 -0
  65. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/setup.cfg +0 -0
  66. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/src/pydantic_marshmallow/errors.py +0 -0
  67. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/src/pydantic_marshmallow/py.typed +0 -0
  68. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/src/pydantic_marshmallow/validators.py +0 -0
  69. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/src/pydantic_marshmallow.egg-info/dependency_links.txt +0 -0
  70. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/src/pydantic_marshmallow.egg-info/top_level.txt +0 -0
  71. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/__init__.py +0 -0
  72. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/compatibility/__init__.py +0 -0
  73. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/compatibility/test_apispec.py +0 -0
  74. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/compatibility/test_connexion.py +0 -0
  75. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/compatibility/test_flask_smorest.py +0 -0
  76. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/compatibility/test_marshmallow_dataclass.py +0 -0
  77. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/compatibility/test_oneofschema.py +0 -0
  78. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/compatibility/test_sqlalchemy.py +0 -0
  79. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/conftest.py +0 -0
  80. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_bridge.py +0 -0
  81. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_computed_fields.py +0 -0
  82. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_dump_options.py +0 -0
  83. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_edge_cases.py +0 -0
  84. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_extended_performance.py +0 -0
  85. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_hooks.py +0 -0
  86. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_performance.py +0 -0
  87. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_return_instance.py +0 -0
  88. {pydantic_marshmallow-1.0.0 → pydantic_marshmallow-1.1.0}/tests/test_validation.py +0 -0
@@ -35,6 +35,7 @@ ruff format src/ tests/
35
35
  **Before committing:** Run `pytest tests/ -v && mypy src/ && ruff check src/ tests/`
36
36
 
37
37
  See [Git.instructions.md](Git.instructions.md) for full CI/CD workflow.
38
+ See [Performance.instructions.md](Performance.instructions.md) for benchmark guidelines.
38
39
 
39
40
  ## Architecture
40
41
 
@@ -132,9 +133,34 @@ This ensures field filtering works correctly with dynamically generated fields.
132
133
 
133
134
  **Runtime:**
134
135
  - pydantic >= 2.0
135
- - marshmallow >= 3.18
136
+ - marshmallow >= 3.18 (supports both 3.x and 4.x)
136
137
 
137
138
  **Development:**
138
139
  - pytest, pytest-cov
139
140
  - mypy
140
141
  - ruff
142
+
143
+ ## Marshmallow Version Compatibility
144
+
145
+ The library supports both Marshmallow 3.x and 4.x. Key differences handled internally:
146
+ - **MA 4.x**: `context` parameter removed from `Schema.__init__` (use `contextvars` instead)
147
+ - **MA 4.x**: `@validates_schema(pass_many=True)` renamed to `pass_collection=True`
148
+ - **MA 4.x**: `unknown` parameter required in internal processor methods
149
+
150
+ **Testing both versions locally:**
151
+ ```bash
152
+ # Create separate venvs
153
+ python -m venv .venv-ma3
154
+ python -m venv .venv-ma4
155
+
156
+ # Install with specific versions
157
+ .\.venv-ma3\Scripts\pip install -e ".[dev]" "marshmallow>=3.18,<4"
158
+ .\.venv-ma4\Scripts\pip install -e ".[dev]" "marshmallow>=4" "flask-rebar>=3.4.0"
159
+
160
+ # Run tests
161
+ .\.venv-ma3\Scripts\python -m pytest tests/ -v
162
+ .\.venv-ma4\Scripts\python -m pytest tests/ -v
163
+ ```
164
+
165
+ **Ecosystem version requirements:**
166
+ - flask-rebar ≥ 3.4.0 required for MA 4.x swagger generation support
@@ -38,9 +38,9 @@ ruff check src/ tests/
38
38
  1. **Push changes** - Never merge uncommitted work
39
39
  2. **Wait for CI** - Check GitHub Actions status
40
40
  3. **All checks must pass**:
41
- - Tests pass on Python 3.9, 3.10, 3.11, 3.12, 3.13, 3.14
41
+ - Tests pass on Python 3.10, 3.11, 3.12, 3.13, 3.14
42
42
  - mypy type checking passes
43
- - ruff and flake8 linting passes
43
+ - ruff linting passes
44
44
  4. **Only merge after CI success** - The `ci-passed` job gates all merges
45
45
 
46
46
  ## Checking CI Status
@@ -150,11 +150,22 @@ class BridgeValidationError(ValidationError):
150
150
 
151
151
  ### Benchmarking
152
152
 
153
+ **See [Performance.instructions.md](Performance.instructions.md) for full guidelines.**
154
+
155
+ **Critical:** Always verify dependency versions before benchmarking:
156
+ ```python
157
+ # ALWAYS run this before any benchmark
158
+ python -c "import marshmallow; print(marshmallow.__file__); from importlib.metadata import version; print('Version:', version('marshmallow'))"
159
+ ```
160
+
161
+ Basic benchmark example:
153
162
  ```python
154
163
  # In benchmarks/
155
- from benchmark_framework import benchmark, compare_baseline
164
+ from benchmark_framework import BenchmarkSuite
165
+
166
+ suite = BenchmarkSuite("my_benchmarks", iterations=1000, runs=3)
156
167
 
157
- @benchmark(iterations=1000)
168
+ @suite.add("bench_simple_load")
158
169
  def bench_simple_load():
159
170
  schema.load({"name": "test", "age": 30})
160
171
  ```
@@ -0,0 +1,210 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, develop]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ lint:
14
+ name: Lint & Type Check
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v5
21
+
22
+ - name: Set up Python
23
+ run: uv python install 3.11
24
+
25
+ - name: Install dependencies
26
+ run: uv sync --all-extras
27
+
28
+ - name: Lint with ruff
29
+ run: uv run ruff check src/pydantic_marshmallow/ tests/
30
+
31
+ - name: Type check with mypy
32
+ run: uv run mypy src/pydantic_marshmallow/
33
+
34
+ test:
35
+ name: Test (Py${{ matrix.python-version }}, ${{ matrix.os }}, MA${{ matrix.marshmallow-version }}, PD${{ matrix.pydantic-version }})
36
+ needs: [lint] # Only run tests after lint passes
37
+ runs-on: ${{ matrix.os }}
38
+ strategy:
39
+ fail-fast: false
40
+ matrix:
41
+ os: [ubuntu-latest, windows-latest, macos-latest]
42
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
43
+ marshmallow-version: ['latest'] # Default to latest Marshmallow (3.x from lock)
44
+ pydantic-version: ['latest'] # Default to latest Pydantic
45
+ include:
46
+ # === BASE VERSIONS (minimum supported) ===
47
+ # Marshmallow 3.18.0 + Pydantic 2.0.0 - minimum supported combo
48
+ - os: ubuntu-latest
49
+ python-version: '3.10'
50
+ marshmallow-version: '3.18.0'
51
+ pydantic-version: '2.0.0'
52
+ # Pydantic 2.0.0 with latest Marshmallow 3.x
53
+ - os: ubuntu-latest
54
+ python-version: '3.11'
55
+ marshmallow-version: 'latest'
56
+ pydantic-version: '2.0.0'
57
+
58
+ # === INTERMEDIATE VERSIONS ===
59
+ # Marshmallow 3.21.0 (last 3.x before 4.0) + Pydantic 2.5.x
60
+ - os: ubuntu-latest
61
+ python-version: '3.11'
62
+ marshmallow-version: '3.21.0'
63
+ pydantic-version: '2.5'
64
+ # Pydantic 2.5 (significant validation changes) with latest Marshmallow
65
+ - os: ubuntu-latest
66
+ python-version: '3.12'
67
+ marshmallow-version: 'latest'
68
+ pydantic-version: '2.5'
69
+
70
+ # === LATEST/BLEEDING EDGE ===
71
+ # Marshmallow 4.x latest on Ubuntu with Python 3.11 and 3.12
72
+ - os: ubuntu-latest
73
+ python-version: '3.11'
74
+ marshmallow-version: '4-latest'
75
+ pydantic-version: 'latest'
76
+ - os: ubuntu-latest
77
+ python-version: '3.12'
78
+ marshmallow-version: '4-latest'
79
+ pydantic-version: 'latest'
80
+ # Marshmallow 4.x + Pydantic 2.5 cross-version
81
+ - os: ubuntu-latest
82
+ python-version: '3.11'
83
+ marshmallow-version: '4-latest'
84
+ pydantic-version: '2.5'
85
+ exclude:
86
+ # Reduce matrix size - test all Python versions on Ubuntu, latest on others
87
+ - os: windows-latest
88
+ python-version: '3.10'
89
+ - os: windows-latest
90
+ python-version: '3.13'
91
+ - os: windows-latest
92
+ python-version: '3.14'
93
+ - os: macos-latest
94
+ python-version: '3.10'
95
+ - os: macos-latest
96
+ python-version: '3.13'
97
+ - os: macos-latest
98
+ python-version: '3.14'
99
+
100
+ steps:
101
+ - uses: actions/checkout@v4
102
+
103
+ - name: Install uv
104
+ uses: astral-sh/setup-uv@v5
105
+
106
+ - name: Set up Python ${{ matrix.python-version }}
107
+ run: uv python install ${{ matrix.python-version }}
108
+
109
+ - name: Install dependencies
110
+ run: uv sync --all-extras
111
+
112
+ - name: Override Marshmallow to 4.x latest
113
+ if: matrix.marshmallow-version == '4-latest'
114
+ run: uv add --dev "marshmallow>=4.0.0"
115
+
116
+ - name: Upgrade flask-rebar for Marshmallow 4.x compatibility
117
+ if: matrix.marshmallow-version == '4-latest'
118
+ run: uv add --dev "flask-rebar>=3.4.0"
119
+
120
+ - name: Override Marshmallow to specific version
121
+ if: matrix.marshmallow-version != 'latest' && matrix.marshmallow-version != '4-latest'
122
+ run: uv add --dev "marshmallow==${{ matrix.marshmallow-version }}"
123
+
124
+ - name: Override Pydantic to 2.5.x
125
+ if: matrix.pydantic-version == '2.5'
126
+ run: uv add --dev "pydantic>=2.5.0,<2.6.0"
127
+
128
+ - name: Override Pydantic to specific version
129
+ if: matrix.pydantic-version == '2.0.0'
130
+ run: uv add --dev "pydantic>=2.0.0,<2.1.0"
131
+
132
+ - name: Verify installed versions
133
+ run: |
134
+ echo "=== Installed Versions ==="
135
+ uv run python -c "from importlib.metadata import version; print(f'Marshmallow: {version(\"marshmallow\")}')"
136
+ uv run python -c "from importlib.metadata import version; print(f'Pydantic: {version(\"pydantic\")}')"
137
+ uv run python -c "import sys; print(f'Python: {sys.version}')"
138
+
139
+ - name: Verify Marshmallow 4.x installed
140
+ if: matrix.marshmallow-version == '4-latest'
141
+ run: |
142
+ uv run python -c "from importlib.metadata import version; v = version('marshmallow'); assert v.startswith('4.'), f'Expected MA 4.x, got {v}'"
143
+
144
+ - name: Verify Marshmallow 3.x installed
145
+ if: matrix.marshmallow-version == '3.18.0' || matrix.marshmallow-version == '3.21.0'
146
+ run: |
147
+ uv run python -c "from importlib.metadata import version; v = version('marshmallow'); assert v == '${{ matrix.marshmallow-version }}', f'Expected MA ${{ matrix.marshmallow-version }}, got {v}'"
148
+
149
+ - name: Run tests
150
+ run: uv run pytest tests/ -v --tb=short
151
+
152
+ coverage:
153
+ name: Coverage
154
+ needs: [lint]
155
+ runs-on: ubuntu-latest
156
+ steps:
157
+ - uses: actions/checkout@v4
158
+ with:
159
+ fetch-depth: 0 # Fetch all history for diff-cover
160
+
161
+ - name: Install uv
162
+ uses: astral-sh/setup-uv@v5
163
+
164
+ - name: Set up Python
165
+ run: uv python install 3.11
166
+
167
+ - name: Install dependencies
168
+ run: uv sync --all-extras
169
+
170
+ - name: Run tests with coverage
171
+ run: |
172
+ uv run pytest tests/ --cov=src/pydantic_marshmallow --cov-report=xml --cov-report=term
173
+
174
+ - name: Upload coverage to Codecov
175
+ uses: codecov/codecov-action@v4
176
+ with:
177
+ files: ./coverage.xml
178
+ fail_ci_if_error: false # Don't fail if Codecov is down
179
+ verbose: true
180
+ env:
181
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
182
+
183
+ - name: Check diff coverage (changed lines)
184
+ run: |
185
+ uv run diff-cover coverage.xml --compare-branch=origin/main --fail-under=80
186
+ continue-on-error: true # Warn but don't fail initially
187
+
188
+ # This job is used as the required status check for branch protection
189
+ # Configure GitHub: Settings > Branches > Branch protection > Require "CI Passed"
190
+ ci-passed:
191
+ name: CI Passed
192
+ runs-on: ubuntu-latest
193
+ needs: [lint, test, coverage]
194
+ if: always()
195
+ steps:
196
+ - name: Check all jobs passed
197
+ run: |
198
+ if [[ "${{ needs.lint.result }}" != "success" ]]; then
199
+ echo "❌ Lint job failed"
200
+ exit 1
201
+ fi
202
+ if [[ "${{ needs.test.result }}" != "success" ]]; then
203
+ echo "❌ Test job failed"
204
+ exit 1
205
+ fi
206
+ if [[ "${{ needs.coverage.result }}" != "success" ]]; then
207
+ echo "❌ Coverage job failed"
208
+ exit 1
209
+ fi
210
+ echo "✅ All CI checks passed!"
@@ -1,9 +1,6 @@
1
1
  name: Release
2
2
 
3
3
  on:
4
- push:
5
- branches:
6
- - main
7
4
  workflow_dispatch:
8
5
  inputs:
9
6
  dry_run:
@@ -39,7 +36,7 @@ jobs:
39
36
  id: semantic
40
37
  uses: cycjimmy/semantic-release-action@v4
41
38
  with:
42
- dry_run: ${{ inputs.dry_run || false }}
39
+ dry_run: ${{ inputs.dry_run }}
43
40
  extra_plugins: |
44
41
  conventional-changelog-conventionalcommits
45
42
  env:
@@ -48,7 +45,7 @@ jobs:
48
45
  build:
49
46
  name: Build Package
50
47
  needs: release
51
- if: needs.release.outputs.new_release_published == 'true' && (inputs.dry_run == false || inputs.dry_run == null)
48
+ if: needs.release.outputs.new_release_published == 'true' && inputs.dry_run == false
52
49
  runs-on: ubuntu-latest
53
50
  steps:
54
51
  - name: Checkout
@@ -72,7 +69,7 @@ jobs:
72
69
  publish:
73
70
  name: Publish to PyPI
74
71
  needs: [release, build]
75
- if: needs.release.outputs.new_release_published == 'true' && (inputs.dry_run == false || inputs.dry_run == null)
72
+ if: needs.release.outputs.new_release_published == 'true' && inputs.dry_run == false
76
73
  runs-on: ubuntu-latest
77
74
  environment: pypi # Requires approval if configured in GitHub Settings
78
75
  permissions:
@@ -141,6 +141,7 @@ celerybeat.pid
141
141
  env/
142
142
  venv/
143
143
  ENV/
144
+ .venv-*/
144
145
  env.bak/
145
146
  venv.bak/
146
147
 
@@ -154,6 +155,9 @@ venv.bak/
154
155
  # mkdocs documentation
155
156
  /site
156
157
 
158
+ # Docker (local dev only)
159
+ docker/
160
+
157
161
  # mypy
158
162
  .mypy_cache/
159
163
  .dmypy.json
@@ -0,0 +1,55 @@
1
+ # Pre-commit hooks for pydantic-marshmallow
2
+ # Install: pre-commit install
3
+ # Run all: pre-commit run --all-files
4
+ # Update: pre-commit autoupdate
5
+
6
+ default_language_version:
7
+ python: python3.11
8
+
9
+ repos:
10
+ # Ruff - fast linter and formatter (replaces flake8, isort, black)
11
+ - repo: https://github.com/astral-sh/ruff-pre-commit
12
+ rev: v0.15.0
13
+ hooks:
14
+ - id: ruff
15
+ name: ruff (lint)
16
+ args: [--fix, --exit-non-zero-on-fix]
17
+ - id: ruff-format
18
+ name: ruff (format)
19
+
20
+ # Type checking with mypy
21
+ - repo: https://github.com/pre-commit/mirrors-mypy
22
+ rev: v1.19.0
23
+ hooks:
24
+ - id: mypy
25
+ name: mypy
26
+ additional_dependencies:
27
+ - marshmallow>=3.18.0
28
+ - pydantic>=2.0.0
29
+ - typing-extensions>=4.0.0
30
+ args: [--config-file=pyproject.toml]
31
+ pass_filenames: false
32
+ files: ^src/
33
+
34
+ # Standard pre-commit hooks
35
+ - repo: https://github.com/pre-commit/pre-commit-hooks
36
+ rev: v5.0.0
37
+ hooks:
38
+ - id: trailing-whitespace
39
+ exclude: ^(site/|.*\.md)$
40
+ - id: end-of-file-fixer
41
+ exclude: ^site/
42
+ - id: check-yaml
43
+ args: [--unsafe]
44
+ - id: check-toml
45
+ - id: check-added-large-files
46
+ args: [--maxkb=500]
47
+ - id: check-merge-conflict
48
+ - id: debug-statements
49
+ - id: mixed-line-ending
50
+ args: [--fix=lf]
51
+ exclude: \.ps1$
52
+
53
+ ci:
54
+ autoupdate_schedule: monthly
55
+ skip: [mypy] # Skip mypy in CI (run separately with full deps)
@@ -0,0 +1,107 @@
1
+ {
2
+ "branches": [
3
+ "main"
4
+ ],
5
+ "plugins": [
6
+ [
7
+ "@semantic-release/commit-analyzer",
8
+ {
9
+ "preset": "conventionalcommits",
10
+ "releaseRules": [
11
+ {
12
+ "type": "feat",
13
+ "release": "minor"
14
+ },
15
+ {
16
+ "type": "fix",
17
+ "release": "patch"
18
+ },
19
+ {
20
+ "type": "perf",
21
+ "release": "patch"
22
+ },
23
+ {
24
+ "type": "docs",
25
+ "release": false
26
+ },
27
+ {
28
+ "type": "style",
29
+ "release": false
30
+ },
31
+ {
32
+ "type": "refactor",
33
+ "release": "patch"
34
+ },
35
+ {
36
+ "type": "test",
37
+ "release": false
38
+ },
39
+ {
40
+ "type": "ci",
41
+ "release": false
42
+ },
43
+ {
44
+ "type": "chore",
45
+ "release": false
46
+ },
47
+ {
48
+ "breaking": true,
49
+ "release": "major"
50
+ }
51
+ ]
52
+ }
53
+ ],
54
+ [
55
+ "@semantic-release/release-notes-generator",
56
+ {
57
+ "preset": "conventionalcommits",
58
+ "presetConfig": {
59
+ "types": [
60
+ {
61
+ "type": "feat",
62
+ "section": "Features"
63
+ },
64
+ {
65
+ "type": "fix",
66
+ "section": "Bug Fixes"
67
+ },
68
+ {
69
+ "type": "perf",
70
+ "section": "Performance"
71
+ },
72
+ {
73
+ "type": "refactor",
74
+ "section": "Refactoring"
75
+ },
76
+ {
77
+ "type": "docs",
78
+ "section": "Documentation",
79
+ "hidden": true
80
+ },
81
+ {
82
+ "type": "style",
83
+ "section": "Styles",
84
+ "hidden": true
85
+ },
86
+ {
87
+ "type": "test",
88
+ "section": "Tests",
89
+ "hidden": true
90
+ },
91
+ {
92
+ "type": "ci",
93
+ "section": "CI",
94
+ "hidden": true
95
+ },
96
+ {
97
+ "type": "chore",
98
+ "section": "Chores",
99
+ "hidden": true
100
+ }
101
+ ]
102
+ }
103
+ }
104
+ ],
105
+ "@semantic-release/github"
106
+ ]
107
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "python.analysis.extraPaths": [
3
+ "src"
4
+ ],
5
+ "python.analysis.include": [
6
+ "src/**/*.py"
7
+ ],
8
+ "python.analysis.exclude": [
9
+ "tests/**",
10
+ "benchmarks/**",
11
+ "examples/**",
12
+ "**/__pycache__/**",
13
+ ".venv/**"
14
+ ],
15
+ "python.analysis.ignore": [
16
+ "tests/**",
17
+ "benchmarks/**",
18
+ "examples/**"
19
+ ],
20
+ "python.analysis.diagnosticMode": "workspace",
21
+ "mypy-type-checker.args": [
22
+ "src/pydantic_marshmallow"
23
+ ],
24
+ "flake8.args": [
25
+ "src/pydantic_marshmallow"
26
+ ],
27
+ "[python]": {
28
+ "editor.defaultFormatter": "charliermarsh.ruff",
29
+ "editor.formatOnSave": true,
30
+ "editor.codeActionsOnSave": {
31
+ "source.organizeImports": "explicit",
32
+ "source.fixAll.autopep8": "never",
33
+ "source.fixAll.ruff": "explicit"
34
+ }
35
+ },
36
+ "autopep8.enable": false,
37
+ "python.formatting.provider": "none",
38
+ "ruff.format.args": [],
39
+ "ruff.organizeImports": true
40
+ }
@@ -3,8 +3,8 @@
3
3
  This document maps features from both libraries and tracks bridge support.
4
4
 
5
5
  **Last Updated**: February 2026
6
- **Tested Versions**: Marshmallow 3.x, Pydantic 2.x
7
- **Test Suite**: 375+ tests
6
+ **Tested Versions**: Marshmallow 3.x/4.x, Pydantic 2.x
7
+ **Test Suite**: 515+ tests
8
8
 
9
9
  ## Legend
10
10
  - ✅ Fully supported and tested
@@ -296,19 +296,27 @@ This document maps features from both libraries and tracks bridge support.
296
296
 
297
297
  | Tool | Status | Notes |
298
298
  |:-----|:------:|:------|
299
- | Flask-Rebar | ✅ | Schema subclass |
299
+ | Flask-Rebar | ✅ | Schema subclass; requires ≥3.4.0 for MA 4.x swagger |
300
300
  | webargs | ✅ | Schema subclass |
301
301
  | apispec | ✅ | Schema subclass |
302
302
  | Flask-Marshmallow | ✅ | Schema subclass |
303
303
  | Flask-Smorest | ✅ | Schema subclass |
304
304
  | marshmallow-sqlalchemy | ✅ | Works alongside |
305
305
 
306
+ #### Flask-Rebar Version Notes
307
+ - **flask-rebar ≥ 3.4.0**: Full support for Marshmallow 4.x including swagger generation
308
+ - **flask-rebar < 3.4.0**: Works with Marshmallow 3.x; swagger generation fails on MA 4.x due to removed `ordered` attribute
309
+
306
310
  ---
307
311
 
308
312
  ## 4. Version Compatibility
309
313
 
310
314
  | pydantic-marshmallow | Marshmallow | Pydantic | Python |
311
315
  |:---------------------|:------------|:---------|:-------|
312
- | 0.1.x | 3.18+ | 2.0+ | 3.9-3.14 |
316
+ | 0.1.x | 3.18+ / 4.x | 2.0+ | 3.10-3.14 |
317
+
318
+ **Marshmallow Version Notes:**
319
+ - **MA 3.x**: Full feature support including `context` parameter
320
+ - **MA 4.x**: Full support; `context` parameter removed (use `contextvars` instead)
313
321
 
314
- **CI tests against:** Python 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 on Ubuntu/Windows/macOS
322
+ **CI tests against:** Python 3.10, 3.11, 3.12, 3.13, 3.14 on Ubuntu/Windows/macOS