-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
185 lines (171 loc) · 7.71 KB
/
Copy pathpyproject.toml
File metadata and controls
185 lines (171 loc) · 7.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
[project]
name = "convert-python-sdk"
dynamic = ["version"]
description = "Convert Experiences FullStack SDK for Python — server-side A/B testing, feature flags, and personalizations."
readme = "README.md"
license = "Apache-2.0"
authors = [
{ name = "Convert.com", email = "support@convert.com" }
]
requires-python = ">=3.9"
# Runtime dependencies declare compatible-release bounds, never exact pins
# (qs-09 dependency-bounds-verification). httpx is the SDK's only runtime
# dependency: the >=0.28,<1.0 bound follows httpx's 0.x SemVer commitment
# (no breaking changes within 0.x minors), avoiding frequent upper-bound bumps
# (qs-09 F-060). Confirm the httpx changelog before widening.
dependencies = [
"httpx>=0.28,<1.0",
]
[project.urls]
Homepage = "https://www.convert.com"
Repository = "https://github.com/convertcom/python-sdk"
Changelog = "https://github.com/convertcom/python-sdk/releases"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
# Single-source the version from src/convert_sdk/version.py (qs-01). The
# pyproject [project].version is declared dynamic and resolved by hatch from
# the module attribute below, so the version lives in exactly one place.
[tool.hatch.version]
path = "src/convert_sdk/version.py"
[tool.hatch.build.targets.wheel]
# Import package (convert_sdk) differs from the distribution name
# (convert-python-sdk) by design — see qs-01 canonical naming. Point hatch at
# the src/ layout explicitly so py.typed and all modules ship in the wheel.
packages = ["src/convert_sdk"]
[tool.hatch.build.targets.sdist]
include = [
"src/convert_sdk",
"README.md",
"pyproject.toml",
# Ship the runnable quickstart examples in the source distribution so the
# onboarding path travels with the package (Story 1.6).
"examples",
# demo/ is intentionally excluded from the sdist (and from the wheel via the
# packages = ["src/convert_sdk"] wheel target above): it is a manual
# verification harness, not part of the published SDK surface (F-066).
]
exclude = [
# Hatchling's sdist builder auto-includes README-style files found via VCS
# traversal even when an explicit `include` list is set. Exclude demo/ and
# other non-shipping directories explicitly so the produced sdist is clean.
"demo",
"scripts",
"tests",
"ci",
".github",
# Node release tooling — dev-only, never ships in the sdist.
"package.json",
"release.config.mjs",
".yarnrc.yml",
"yarn.lock",
"node_modules",
]
[tool.pytest.ini_options]
# Put the project root on sys.path so the runnable quickstart examples in
# examples/ are importable as the `examples` package from the drift-protection
# tests (tests/test_examples.py), without requiring PYTHONPATH to be set in CI.
pythonpath = ["."]
testpaths = ["tests"]
# ---------------------------------------------------------------------------
# Ruff lint (qs-02). Story 5.1 STANDS UP the lint gate. The rule set is the
# substantive E/W/F/B/SIM/RUF selection (qs-02 / Story DAR); UP and I are
# intentionally NOT enabled to avoid forcing unrelated stylistic refactors of
# the existing codebase. line-length is set to 100 to match the codebase's
# established line convention (it was authored to ~100, not the 88 default) —
# this enforces the gate on real lines without churning every wrapped string.
# ---------------------------------------------------------------------------
[tool.ruff]
line-length = 100
target-version = "py39"
src = ["src", "tests", "scripts"]
[tool.ruff.lint]
select = ["E", "W", "F", "B", "SIM", "RUF"]
[tool.ruff.lint.per-file-ignores]
# Tests and dev scripts are NOT shippable package code. They follow test-side
# conventions that the gate intentionally does not enforce, keeping the gate
# strict on src/ (the shippable surface) without churning the 687-test baseline
# or the reused Story-3.5 parity-fixture generator (F-017 — reuse, don't
# refactor). Scoped-out findings:
# B017 - tests assert against broad Exception by design
# RUF002- docstrings copy JS contract prose with EN-DASH/typographic chars
# E501 - long literal fixtures / copied prose lines
# B904 - the fixture generator re-raises setup errors without chaining
# SIM118/RUF059 - test-local style choices
"tests/**" = ["B017", "RUF002", "E501", "SIM118", "RUF059"]
"scripts/**" = ["B017", "B904", "E501"]
# Build-time-generated TypedDict stubs (qs-13). These are produced by the
# backend serving-spec codegen (generate-pyi.js) and committed verbatim — never
# hand-edited (enforced by scripts/check_generated_pyi_header.py). Their line
# length is content-dependent (e.g. the 10-value goal_type Literal exceeds 100
# cols); generated artifacts are not held to the hand-written style gate, the
# same way scripts/ and tests/ are scoped out above.
# E501 - generated discriminator Literal lines exceed line-length
"src/convert_sdk/_generated/**" = ["E501"]
# ---------------------------------------------------------------------------
# mypy strict (qs-02). The gate runs strict on the shippable package. Story 5.1
# fixed the trivial annotation gaps so strict is genuinely green at the gate.
# ---------------------------------------------------------------------------
[tool.mypy]
python_version = "3.9"
strict = true
files = ["src/convert_sdk"]
# Only type-check the shippable package; do not descend into third-party deps
# (dev tools like click may use newer-than-3.9 syntax that mypy would otherwise
# flag under our py39 target). httpx ships inline types, so the SDK's own httpx
# usage is still strictly checked.
follow_imports = "silent"
follow_imports_for_stubs = false
[[tool.mypy.overrides]]
module = ["click.*", "anyio.*"]
ignore_missing_imports = true
follow_imports = "skip"
# ---------------------------------------------------------------------------
# Coverage (qs-03). Project floor 85%, evaluation floor 95% (enforced as a
# separate CI step / verify_release.py gate). Measured on the import package.
# ---------------------------------------------------------------------------
[tool.coverage.run]
source = ["convert_sdk"]
branch = false
omit = [
"*/tests/*",
"*/__pycache__/*",
]
[tool.coverage.report]
show_missing = true
fail_under = 85
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"raise NotImplementedError",
"\\.\\.\\.",
]
[dependency-groups]
dev = [
# pytest is split on an environment marker, not pinned to one line.
#
# GHSA-6w46-j5rx-g56g / CVE-2025-71176 (insecure temporary directory —
# `/tmp/pytest-of-{user}` is predictable, so a local user can pre-create or
# symlink it) affects EVERY pytest release up to 9.0.2 and is fixed only in
# 9.0.3. pytest 9 requires Python >=3.10, and NFR22 mandates the full
# CPython 3.9-3.13 matrix, so no single specifier is both patched and
# installable across the matrix.
#
# The marker takes the patched line everywhere it can run (3.10-3.13) and
# falls back to the last 3.9-compatible line on the bottom cell only. The
# 3.9 cell therefore carries a MODERATE, local-vector, dev-only advisory
# that no upstream release can clear; pytest never ships (the wheel is
# packages = ["src/convert_sdk"] and httpx is the only runtime dependency),
# so this is bounded to the runner executing the suite. Collapse the two
# lines into "pytest>=9.0.3" the moment the SDK's own requires-python
# floor moves to 3.10.
"pytest>=9.0.3,<10; python_version >= '3.10'",
"pytest>=8.4,<8.5; python_version < '3.10'",
# RESPX route-level HTTPX mocking for transport/config-fetch tests
# (qs-06 integration-test-harness pattern; no socket-level patching).
"respx>=0.21,<1.0",
# Release/CI quality gates (Story 5.1): coverage, lint, type-check.
"pytest-cov>=5,<6",
"ruff>=0.6,<1.0",
"mypy>=1.11,<2.0",
]