-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathpyproject.toml
More file actions
223 lines (209 loc) · 10.1 KB
/
Copy pathpyproject.toml
File metadata and controls
223 lines (209 loc) · 10.1 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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
[build-system]
# Must allow the uv version python-sdk-publish.yml's build job pins, so releases
# build with that uv's built-in backend. Bumped by hand with it; Dependabot
# ignores uv_build (see .github/dependabot.yml).
requires = ["uv_build>=0.12.17,<0.13"]
build-backend = "uv_build"
[project]
name = "permit"
version = "3.0.0"
description = "Permit.io python sdk"
readme = "README.md"
requires-python = ">=3.10"
license = "Apache-2.0"
license-files = ["LICENSE"]
authors = [{ name = "Permit.io", email = "support@permit.io" }]
classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Typing :: Typed",
]
# Open ranges on purpose: this is a library, and consumers resolve these
# against their own tree. The floors are the real exposure, which is why
# .github/scripts/audit-deps.sh scans them with --resolution lowest-direct.
dependencies = [
"aiohttp>=3.14.3,<4",
# 0.7.3 is the first loguru release that imports without a DeprecationWarning on
# Python 3.14: earlier ones call asyncio.iscoroutinefunction, which 3.16 removes.
"loguru>=0.7.3,<1",
# pydantic has one line per Python range, updated by hand: Dependabot ignores
# pydantic (see .github/dependabot.yml). Why each version is excluded:
# - CVE-2024-3772 (ReDoS in email validation) affects pydantic 1.x before
# 1.10.13. Under pydantic 2, permit validates emails with the pydantic.v1 copy
# that pydantic 2 bundles, and only 2.4.2 and later bundle the fixed 1.10.13:
# 2.0.1 bundles 1.10.11, and 2.4.0 and 2.4.1 bundle 1.10.12. So 2.0-2.3, 2.4.0
# and 2.4.1 are excluded on every Python.
# - pydantic 2.0 also fails every API call that parses a response: its
# pydantic.v1.parse_obj_as builds the model with pydantic 2, which rejects the
# `__root__` field.
# - Below Python 3.14 the pydantic 1 floor is 1.10.18. Type checkers read
# permit's models from the pydantic.v1 package, which pydantic 1 first ships
# in 1.10.17, and 1.10.13-1.10.17 emit about 2,400 DeprecationWarnings on
# `import permit` under Python 3.13 (typing._eval_type called without
# type_params).
# - On Python 3.13 the pydantic 2 floor is 2.8.0: 2.4.2-2.7.x require a
# pydantic-core release with no Python 3.13 wheels. 2.8.0 is the first to
# require one that has them (pydantic-core 2.20.0).
# - On Python 3.14, pydantic 1.x before 1.10.25 and 2.x before 2.13 (whose
# pydantic.v1 predates 1.10.25) crash on `import permit` with "unable to
# infer type for attribute". pydantic 2.0-2.11 also have no Python 3.14
# builds.
# uv_build writes these markers to the wheel and sdist as python_full_version
# ranges, and a pre-release sorts below its final release, so a 3.14.0 alpha,
# beta or release candidate matches none of the three lines and gets no
# pydantic requirement. Every final release matches exactly one line.
'pydantic[email]>=1.10.18,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.0,!=2.4.1; python_version < "3.13"',
'pydantic[email]>=1.10.18,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*; python_version == "3.13"',
'pydantic[email]>=1.10.25,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,!=2.10.*,!=2.11.*,!=2.12.*; python_version >= "3.14"',
# 4.14.0 is the lowest release that works on every supported Python: releases
# before 4.6 break `import permit` on 3.12+, before 4.12 on 3.13+, and 4.12-4.13
# lose TypedDict keys on 3.14.
"typing-extensions>=4.14.0,<5",
]
[project.urls]
Homepage = "https://permit.io"
Documentation = "https://docs.permit.io/sdk/python/quickstart-python"
Repository = "https://github.com/permitio/permit-python"
[dependency-groups]
# Exact pins, so every developer, CI lane and the dev-ceiling audit tree
# resolve the same versions. Dependabot raises them. A pin also gives the CVE
# scan a version to evaluate: a spec with no bound has none, so a package listed
# that way is absent from every audit. The ruff and mypy hooks in
# .pre-commit-config.yaml install their own copies at their revs, and those are
# what CI lints and type-checks with. Dependabot bumps the ruff and mypy pins
# here but not the hook revs, so the two can differ.
# aioresponses is left out on purpose. No test imports it, and its latest
# release (0.7.9) is incompatible with the aiohttp 3.14.3 floor: every mocked
# request raises "ClientResponse.__init__() missing 1 required keyword-only
# argument: 'stream_writer'". Offline HTTP tests use pytest-httpserver, which
# asserts on real request bodies.
dev = [
# tests/test_typing_surface.py runs mypy on tests/type_check/consumer.py;
# 1.11.2 passes it on Python 3.10-3.14 with either pydantic major.
"mypy==1.11.2",
# Imported directly by the offline tests, which evaluate the version markers
# in [project].dependencies the way an installer does.
"packaging==26.3",
"pre-commit==4.6.2",
# 9.x rather than 8.x: the old 8.3.0 floor is affected by CVE-2025-71176
# (insecure temporary directory handling), fixed in 9.0.3. Caught by this
# repo's own audit gate.
"pytest==9.1.1",
"pytest-asyncio==1.4.0",
"pytest-httpserver==1.1.5",
"ruff==0.6.9",
# The offline tests and the migration skill's tests read [project].dependencies
# from this file, and tomllib is in the standard library only from Python 3.11.
# The marker says == "3.10" rather than < "3.11", which is the same under
# requires-python, because Dependabot skips a requirement whose marker has `<`.
'tomli==2.4.1; python_version == "3.10"',
# The uv version CI runs: every setup-uv step reads it from uv.lock
# (version-file), except the publish build job, which pins its own version
# and checksum. Dependabot bumps it like any other pin. The uv-lock pre-commit
# hook runs the uv on PATH, which under `uv run` (as in CI) is this one. Run
# this version locally so uv.lock comes out the same.
"uv==0.12.17",
# Imported directly by the offline tests (Request/Response are used to assert
# on what the SDK actually put on the wire), as well as backing
# pytest-httpserver. Keep it at 3.1.6 or later, the highest fixed version
# across the six advisories that affected the old >=2.3.8 floor
# (CVE-2024-34069, CVE-2024-49766, CVE-2024-49767, CVE-2025-66221,
# CVE-2026-21860, CVE-2026-27199).
"werkzeug==3.1.8",
]
# The SDK supports both pydantic majors (permit/utils/pydantic_version.py), and
# CI runs the suite once per major. Each lane is a group so both resolutions
# live in uv.lock: `uv sync --group pydantic-v1` / `--group pydantic-v2`.
pydantic-v1 = ["pydantic<2"]
pydantic-v2 = ["pydantic>=2"]
[tool.uv]
# The oldest uv that may run here, not the version CI runs: that is the `uv`
# pin in the dev group above, which Dependabot updates. A floor rather than an
# exact pin, because Dependabot runs `uv lock` with its own bundled uv and an
# exact pin fails every one of its updates once that uv differs.
required-version = ">=0.12.17"
# Publish-age cooldown for `uv lock`, matching Dependabot's 7-day cooldown: a
# release is most likely to be a compromised upload in its first days. A security
# fix younger than that is locked with an exclude-newer-package entry here (see
# CONTRIBUTING.md, "Dependencies").
exclude-newer = "7 days"
conflicts = [[{ group = "pydantic-v1" }, { group = "pydantic-v2" }]]
[tool.uv.build-backend]
# Flat layout: the package lives at ./permit, not ./src/permit.
module-root = ""
# The wheel holds the permit package and nothing else, so tests/ and the local
# harness/ tool cannot end up in a consumer's site-packages. The published
# permit==2.8.3 installs a TOP-LEVEL `tests` package there, which shadows the
# consumer's own `tests` module.
# Every file under permit/ goes in, not only .py files. That includes py.typed,
# which tells type checkers to read permit's annotations (PEP 561), and
# _sync_types.pyi, which is how they see the blocking client. CI checks that the
# built wheel and sdist have both.
# The sdist also carries the top-level Markdown files, the migration guide
# among them.
source-include = ["*.md"]
[tool.pytest]
asyncio_mode = "auto"
# The SDK's tests. The migration skill's tests in skills/tests run on their own,
# with skills/tests/pytest.ini (see skills/tests/README.md).
testpaths = ["tests"]
markers = [
'e2e: needs PDP_API_KEY (or another credential), the Permit API and a running PDP. Deselect with -m "not e2e".',
]
[tool.ruff]
line-length = 120
src = ["permit"]
exclude = ["permit/api/models.py"]
target-version = "py310"
[tool.ruff.lint]
select = [
"E", # pycodestyle
"W", # pycodestyle
"F", # pyflakes
"N", # pep8
"I", # isort
"BLE", # flake8 blind except
"FBT", # flake8 boolean trap
"B", # flake8 bug bear
"C4", # flake8 comprehensions
"PIE", # flake8 pie
"T20", # flake8 print
"SIM", # flake8 simplify
"ARG", # flake8 unused arguments
"PTH", # flake8 pathlib
"ASYNC", # flake8 Asyncio rules
# "UP", # pyupgrade
"ERA", # comment out code
"RUF", # ruff rules
"FAST", # FastAPI rules
]
[tool.ruff.lint.flake8-tidy-imports]
ban-relative-imports = "all"
[tool.ruff.lint.per-file-ignores]
# These are standalone CLI programs, not library code: writing the rendered
# report to stdout IS their interface, so the "no print" rule does not apply.
".github/scripts/*.py" = ["T201"]
[tool.mypy]
python_version = "3.10"
packages = ["permit"]
# The SDK's models are pydantic v1 models under both pydantic majors, and type
# checkers see them through pydantic.v1. pydantic.mypy is the v2 plugin under
# pydantic 2 and does not recognise v1 models, so use the v1 plugin.
plugins = ["pydantic.v1.mypy"]
check_untyped_defs = true
warn_unused_configs = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_unreachable = true
[[tool.mypy.overrides]]
module = ["permit.api.models"]
ignore_errors = true
[[tool.mypy.overrides]]
module = ["tests"]
ignore_errors = true