-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathpyproject.toml
More file actions
342 lines (318 loc) · 10.6 KB
/
Copy pathpyproject.toml
File metadata and controls
342 lines (318 loc) · 10.6 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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
[project]
name = "oold"
description = "Linked data class python package"
authors = [{ name = "OpenSemanticWorld", email = "team@opensemantic.world" }]
readme = "README.md"
license = "Apache-2.0"
license-files = ["LICENSE"]
keywords = ['python', 'linked-data', 'json-ld', 'pydantic', 'oo-ld']
requires-python = ">=3.10,<4.0"
# Version is managed by python-semantic-release (see [tool.semantic_release]).
# Do not edit by hand; it is bumped automatically on merge to main.
version = "2.2.0"
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"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",
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = [
"pydantic>=2.0.0",
"datamodel-code-generator>=0.51.0,<0.55.0",
"typing_extensions",
"pyld",
"rdflib",
"sparqlwrapper",
"jsondiff",
"pyyaml",
]
[project.urls]
Homepage = "https://OO-LD.github.io/oold-python/"
Documentation = "https://OO-LD.github.io/oold-python/"
Repository = "https://github.com/OO-LD/oold-python"
Download = "https://pypi.org/project/oold/#files"
[project.scripts]
oold = "oold.cli:main"
# The JS-compatible name, bound to the same implementation, so `oold-validate <dir>` works the
# same way as `npx --yes github:OO-LD/oold-schema oold-validate <dir>`. Bound through oold.cli
# rather than at the click command so it keeps the missing-extra guard that `oold` has.
oold-validate = "oold.cli:validate_main"
[project.optional-dependencies]
# The validator needs a JSON Schema implementation and a CLI framework. pyld and rdflib are
# already core dependencies, so the whole JSON-LD half of it costs nothing extra.
#
# jsonschema's `format-nongpl` extra, not its `format` extra, supplies the format checkers: the
# `format` extra pulls in rfc3987, which is GPLv3+, into a package that is Apache-2.0.
validation = [
"jsonschema[format-nongpl]>=4.20",
"referencing>=0.30",
"click>=8.1",
]
mcp = [
"mcp>=1.2",
"jsonschema[format-nongpl]>=4.20",
"referencing>=0.30",
"click>=8.1",
]
UI-panel = [
"panel",
"jupyter_bokeh",
"param",
]
UI-jupyter = [
"anywidget",
"ipykernel",
"traitlets",
"ipython",
]
UI-nicegui = [
"nicegui",
]
UI = [
"panel",
"jupyter_bokeh",
"param",
"anywidget",
"ipykernel",
"traitlets",
"ipython",
"nicegui",
]
all = [
"panel",
"jupyter_bokeh",
"param",
"anywidget",
"ipykernel",
"traitlets",
"ipython",
"nicegui",
"jsonschema[format-nongpl]>=4.20",
"referencing>=0.30",
"click>=8.1",
"mcp>=1.2",
]
[dependency-groups]
dev = [
# The validation extras are dev dependencies too, so `make test` and `make check` see them
# without `--all-extras`.
"jsonschema[format-nongpl]>=4.20",
"referencing>=0.30",
"click>=8.1",
"mcp>=1.2",
"pytest",
"pytest-cov>=7.0.0",
"pytest-benchmark",
"pytest-playwright",
"jsondiff",
"panel",
"pre-commit>=4.5.1",
"tox-uv>=1.33.4",
"deptry>=0.25.1",
"ty>=0.0.24",
"ruff>=0.15.7",
"zensical>=0.0.26",
"mkdocstrings-python>=1.0.3",
"python-semantic-release>=10.0.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/oold"]
[tool.semantic_release]
# python-semantic-release owns the version and changelog. On merge to main it
# reads the conventional commits, bumps the static version in the files below,
# updates the changelog, commits, and tags. The v-prefixed tag namespace is
# preserved (matches the existing 32 releases).
commit_parser = "conventional"
tag_format = "v{version}"
commit_message = "chore(release): v{version} [skip ci]"
allow_zero_version = true
build_command = "uv lock"
version_toml = ["pyproject.toml:project.version"]
version_variables = ["CITATION.cff:version"]
exclude_commit_patterns = ['''chore\(release\):.*''']
# uv.lock pins oold's own version, so re-lock (build_command) and include it in
# the release commit to keep `uv sync --frozen` consistent on the next run.
assets = ["uv.lock"]
[tool.semantic_release.changelog]
mode = "update"
insertion_flag = "<!-- version list -->"
[tool.semantic_release.changelog.default_templates]
changelog_file = "CHANGELOG.md"
[tool.ty.environment]
python = "./.venv"
python-version = "3.10"
# src layout: without this ty cannot resolve `oold.*` from tests, and every
# import there silently becomes Unknown - which makes those checks vacuous rather
# than failing, so it is not visible in the output. Note that an incomplete
# ./.venv has the same effect on third-party imports, and an unresolved pydantic
# then reports a spurious conflicting-metaclass on every model.
extra-paths = ["src"]
[tool.ty.src]
# Excluded from type checking:
# - tests/data: generated (datamodel-code-generator) pydantic models
# - src/oold/drafts: draft/experimental code (also excluded from ruff)
# - src/oold/ui: optional UI integrations that import optional, un-installed
# packages (panel, anywidget, nicegui, traitlets, ...)
#
# `examples` is checked: they are the documented way to declare a link, and
# excluding them let a broken import and the wrong static type for
# `Model[Model.field == x]` sit there unnoticed.
exclude = [
"tests/data",
"src/oold/drafts",
"src/oold/ui",
]
[tool.ty.rules]
# oold builds pydantic models dynamically (create_model), exposes runtime-only
# attributes (e.g. __iris__) and offers a dynamic subscript/query API
# (Model["iri"], obj.links[Field == ...]). The following checks fire on these
# intentional, runtime-valid metaprogramming patterns rather than real bugs, so
# they are downgraded to keep `ty check` meaningful without mass inline ignores.
unresolved-attribute = "ignore"
not-subscriptable = "ignore"
# Assigning an IRI to a link field is no longer a reason for this one: the
# Link[T] / LinkList[T] annotations type both directions, and the override below
# re-enables the rule for the file that asserts that contract. What remains are
# unrelated sites (json_tools, the codegen spike) not yet cleaned up.
invalid-argument-type = "ignore"
invalid-assignment = "ignore"
unknown-argument = "ignore"
invalid-return-type = "ignore"
unsupported-operator = "ignore"
no-matching-overload = "ignore"
invalid-method-override = "ignore"
not-iterable = "ignore"
invalid-type-form = "ignore"
missing-argument = "ignore"
call-non-callable = "ignore"
too-many-positional-arguments = "ignore"
subclass-of-final-class = "ignore"
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--cov --cov-config=pyproject.toml --cov-report=term-missing"
markers = [
# Opt-in parity tests against a local oold-schema checkout; see
# tests/test_validation/test_parity_live.py. They skip unless OOLD_SCHEMA_DIR is set.
"parity: compares this port against the reference harness",
]
[tool.deptry]
# The anywidget notebook only runs in the browser (pyodide) and imports
# `micropip`, which is not a project dependency.
extend_exclude = ["src/oold/ui/anywidget/.*\\.ipynb"]
[tool.deptry.package_module_name_map]
# The `ipython` distribution is imported as `IPython`.
ipython = "IPython"
# Optional UI extras are not installed in the lint/type environment, so declare
# their import-module names explicitly instead of letting deptry guess.
jupyter_bokeh = "jupyter_bokeh"
anywidget = "anywidget"
ipykernel = "ipykernel"
traitlets = "traitlets"
nicegui = "nicegui"
[tool.deptry.per_rule_ignores]
# stdlib from 3.14 (PEP 649); deptry resolves against the running interpreter,
# which is older, so it reads the version-gated import as a missing dependency.
DEP001 = ["annotationlib"]
# Declared in UI extras and required at runtime by the panel/jupyter
# integrations, but not imported directly from `src`.
DEP002 = ["jupyter_bokeh", "ipykernel"]
# pydantic_core ships with (and is pinned by) pydantic; importing it directly
# is intentional and does not warrant a separate top-level dependency.
DEP003 = ["pydantic_core"]
[tool.ruff]
target-version = "py310"
line-length = 120
fix = true
# Generated (datamodel-code-generator output) and draft/experimental code are
# excluded from linting, mirroring the project's previous flake8 configuration.
extend-exclude = [
"tests/data",
"src/oold/drafts",
]
[tool.ruff.lint]
select = [
# flake8-2020
"YTT",
# flake8-bandit
"S",
# flake8-bugbear
"B",
# flake8-builtins
"A",
# flake8-comprehensions
"C4",
# flake8-debugger
"T10",
# flake8-simplify
"SIM",
# isort
"I",
# mccabe
"C90",
# pycodestyle
"E", "W",
# pyflakes
"F",
# pygrep-hooks
"PGH",
# pyupgrade
"UP",
# ruff
"RUF",
# tryceratops
"TRY",
]
ignore = [
# LineTooLong
"E501",
# DoNotAssignLambda
"E731",
# Mutable default value for class attribute: false positive on pydantic /
# param model fields, where ClassVar-annotating would change model semantics.
"RUF012",
# Avoid specifying long messages outside the exception class: the "fix" is a
# large custom-exception-class refactor that would change the public API.
"TRY003",
# `<function>` is too complex (mccabe): the schema/model transformation code
# is inherently branchy; refactoring purely for the metric risks regressions.
"C901",
# Variable/argument shadows a Python builtin: `property`, `id`, `input` are
# used as domain-meaningful local names (JSON-Schema property, JSON-LD id);
# renaming them reduces readability for no functional benefit.
"A001",
"A002",
]
[tool.ruff.lint.per-file-ignores]
# Tests and examples use literal credentials/tokens and broad exception asserts
# on purpose; the bandit/bugbear security rules are noise there.
"tests/*" = ["S101", "S105", "S106", "B017"]
# Examples and spikes are runnable demos: they self-check with `assert` and
# re-invoke themselves via subprocess to isolate measurements.
"examples/*" = ["S101", "S105", "S106", "S603", "TRY300"]
"src/oold/experimental/*" = ["S101"]
[tool.ruff.format]
preview = true
[tool.coverage.report]
skip_empty = true
[tool.coverage.run]
branch = true
source = ["src"]
[[tool.ty.overrides]]
# The static contract of the link and query API is asserted here, so the rules
# it exercises must actually run - the repo-wide downgrades above would
# otherwise make every assert_type in it vacuous.
include = ["tests/typing/**"]
[tool.ty.overrides.rules]
invalid-argument-type = "error"
invalid-assignment = "error"
unresolved-attribute = "error"
not-subscriptable = "error"