-
-
Notifications
You must be signed in to change notification settings - Fork 96
Expand file tree
/
Copy pathpyproject.toml
More file actions
686 lines (644 loc) · 27.2 KB
/
Copy pathpyproject.toml
File metadata and controls
686 lines (644 loc) · 27.2 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
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
# region ----> project <----
[project]
name = "air"
version = "0.42.0"
description = "The new Python web framework by the authors of Two Scoops of Django. Built with FastAPI, Starlette, and Pydantic."
authors = [
{ name = "Audrey M. Roy Greenfeld", email = "audrey@feldroy.com" },
{ name = "Daniel Roy Greenfeld", email = "daniel@feldroy.com" }
]
maintainers = [
{ name = "pygarap", email = "pygarap@gmail.com" }
]
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.13,<3.15"
urls.Homepage = "https://github.com/feldroy/air"
urls.Repository = "https://github.com/feldroy/air"
urls.Docs = "https://feldroy.github.io/air/"
urls.Issues = "https://github.com/feldroy/air/issues"
urls.Changelog = "https://github.com/feldroy/air/blob/main/CHANGELOG.md"
urls.Sponsor = "https://github.com/sponsors/feldroy"
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Web Environment",
"Framework :: FastAPI",
"Framework :: Pydantic",
"Framework :: Pydantic :: 2",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows",
"Operating System :: OS Independent",
"Operating System :: Unix",
"Programming Language :: JavaScript",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Internet",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: HTTP Servers",
"Topic :: Internet :: WWW/HTTP :: WSGI",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Server",
"Topic :: Software Development",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Libraries :: Application Frameworks",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Text Processing",
"Topic :: Text Processing :: Markup",
"Topic :: Text Processing :: Markup :: HTML",
"Typing :: Typed",
]
keywords = [
"air",
"air-tags",
"api",
"async",
"backend",
"css",
"fastapi",
"fasthtml",
"framework",
"frontend",
"fullstack",
"html",
"javascript",
"jinja",
"jinja2",
"openapi",
"pydantic",
"python",
"rest",
"restapi",
"restful",
"server",
"templates",
"uvicorn",
"web",
]
dependencies = [
"fastapi[standard]>=0.119.1",
"itsdangerous>=2.2.0",
"Jinja2>=3.1.6",
"minify-html>=0.18.1",
"python-multipart>=0.0.20",
"lxml>=6.0.1",
"rich>=14.2.0",
"nh3>=0.3.2",
"frozendict>=2.4.7",
"pygments>=2.19.2",
"selectolax>=0.4.6",
"typer>=0.20.0",
"pydantic-settings>=2.12.0",
"cookiecutter>=2.6.0",
"jinja2-time>=0.2.0",
]
# endregion project
[project.scripts]
air = "air.cli:app"
# region ----> dependencies <----
# Runtime extras you want users to install from PyPI
# [project.optional-dependencies]
# Make `air[standard]` install FastAPI’s own “standard” extras,
# so *users* can do: uv pip install "air[standard]".
# standard = [
# # Re-install FastAPI with its “standard” extra.
# ]
# Groups are for contributors; install with: uv sync --group NAME
# Developer-only deps under [dependency-groups],
# so uv sync can install them for contributors.
# (Groups are not published to PyPI (meaning: they’re not visible to end users).)
[dependency-groups]
# umbrella group that pulls in all dev-time groups
dev = [
{ include-group = "devtools" }, # core developer tools
{ include-group = "lint" }, # linting and type-checking toolchain
{ include-group = "test" }, # test runner and helpers
{ include-group = "docs" }, # documentation build toolchain
]
devtools = [
"uvicorn>=0.34.0", # run full example apps
"typer>=0.19.1" # For running of scripts
]
lint = [
"codespell>=2.4.1",
"pyrefly>=0.29.1", # A fast type checker
"ruff>=0.11.13", # Linting and formatting
"ty>=0.0.1a16", # for checking types
"types-lxml>=2025.11.25",
"types-Markdown>=3.8.0", # Types for the markdown library
"types-pygments>=2.19.0.20251121",
"typos>=1.38.1",
]
test = [
"coverage[toml]>=7.8.2", # Measure how much of the code is covered by tests
"httpx>=0.28.1", # For the test client
"pytest>=8.4.0", # The pytest framework
"pytest-cov>=6.2.1", # Pytest plugin for measuring coverage.
"pytest-pretty>=1.3.0", # Provides richer test session output.
"pytest-github-actions-annotate-failures>=0.3.0", # Annotates test failures in GitHub Actions logs
"pytest-asyncio>=1.1.0", # Adds asyncio support for pytest
"diff-cover>=9.6.0", # Run coverage and linting reports on diffs
"pytest-benchmark>=5.1.0",
"pytest-env>=1.1.5", # for setting env vars in tests
"pyinstrument>=5.1.1",
"full-match>=0.0.3",
]
docs = [
"click==8.3.1", # Necessary to allow live reload to work
"mkdocs-material[imaging]>=9.6.17", # MkDocs theme
"mkdocstrings[python]>=0.30.0", # generate API docs from docstrings automatically
"mkdocs-autorefs>=1.4.2", # automatic cross-references between pages
"mkdocs>=1.6.1", # Static site generator for project documentation
"mkdocs-exclude>=1.0.2", # Plugin to exclude files from MkDocs build
"mkdocs-llmstxt>=0.3.1", # Plugin for embedding LLM-readable text
"mkdocs-redirects>=1.2.2", # Plugin to create redirects between pages
"mkdocstrings-python>=1.16.12", # Python handler for mkdocstrings
"mkdocs-jupyter>=0.25.1",
]
# endregion dependencies
# region ----> uv <----
# uv’s own config block for this project (not PyPI metadata).
[tool.uv]
required-version = ">=0.9.8"
# Whether to enable experimental, preview features.
preview = true
# Treat this repo as an installable *package*, not just a “virtual” project.
# Result: `uv sync` / `uv run` will install *this library itself* into the venv in
# editable (meaning: linked to your working tree) mode, not only its dependencies.
# This enables entry points (meaning: auto-created CLI scripts), plugin discovery,
# and proper distribution metadata (meaning: standard package info used by tools).
package = true
# Use uv’s default: include the "dev" group by default.
# 'uv run' will auto-install and use dev (unless you choose groups yourself).
# 'uv sync' also includes dev by default; change this by passing explicit --group flags.
default-groups = ["dev"]
# ---------------------------------------------------------------------------
# OPTION FOR LATER (comments only; not active):
# Disable uv's implicit dev default (the default is default-groups = ["dev"]).
# Ensure 'uv run' will not auto-install dev; it will only use groups you pass.
# 'uv sync' can still add dev with: --group dev
# To enable this option, set:
# default-groups = []
# ---------------------------------------------------------------------------
# Cache “hints” you (or CI) can hash to decide when to rebuild an editable install
# or reuse a cached environment. uv doesn’t read these at runtime; they’re for automation
# (meaning: your own scripts/CI pipelines).
cache-keys = [
{ file = "pyproject.toml" }, # Rebuild if project config changes.
{ file = "uv.lock" }, # Rebuild if exact dependency versions change.
{ dir = "src" }, # Rebuild on library source edits.
{ dir = "tests" }, # Rebuild on test edits (keeps test env fresh).
{ file = "README.md" }, # Rebuild if docs used in build change.
]
# Declare rules that block certain dependency combos,
# This lets one lockfile cover both setups while resolving them separately.
conflicts = []
# uv group metadata (constraints, conflicts) — disabled for now
# Dev tools may require modern Python, while the library itself can support older
# versions. This avoids installing heavy tooling on older interpreters used only
# to consume the library.
#[tool.uv.dependency-groups]
#dev = { requires-python = ">=3.13" }
# Control where uv resolves packages from.
[tool.uv.sources]
# Always use the local workspace copy of "air" instead of a PyPI release.
# In mono-repo (meaning: multiple projects in one repo) or local dev, this guarantees
# uv uses your checked-out code.
air = { workspace = true }
# -------- uv build backend --------
# PEP 517/518: tells installers (pip/uv) how to build/install this project.
# For Python libraries, an editable install is the standard:
# it enables scripts, plugins, metadata, compiled code, and proper src/ behavior.
# uv follows these standards and installs your package by default, ensuring everything “just works.”
[build-system]
# Ensure the chosen backend is present. A version range keeps CI reproducible
# (meaning: stable over time) while allowing safe updates.
requires = ["uv_build>=0.9.0,<0.10.0"]
# Use uv’s build backend. It is fast and strict, supports PEP 660 editable installs,
# and produces correct distribution metadata for tooling.
build-backend = "uv_build"
# Settings specific to uv_build.
[tool.uv.build-backend]
# Declare the “src/” layout so imports come from the installed package, not the repo root.
# Prevents path leaks (meaning: accidental local imports) and matches end-user installs.
module-root = "src"
# The single top-level package name under ./src. The backend validates this structure
# to catch layout mistakes early.
module-name = "air"
# endregion uv
# region ----> ruff <----
[tool.ruff]
# Enforce a requirement on the version of Ruff, to enforce at runtime.
# If the version of Ruff does not meet the requirement, Ruff will exit with an error.
required-version = ">=0.13.3"
# Enable preview features.
preview = true
# Enumerate all fixed violations.
show-fixes = true
# Enable application of unsafe fixes.
# If excluded, a hint will be displayed when unsafe fixes are available.
# If set to false, the hint will be hidden.
unsafe-fixes = false
# Keep file discovery identical whether you pass "." or not
respect-gitignore = true # default, shown for clarity
force-exclude = true # apply excludes even for explicit paths like "."
src = ["src"]
line-length = 120
indent-width = 4
# Exclude a variety of commonly ignored directories.
exclude = [
".git",
".github",
".pytest_cache",
".ruff_cache",
".venv",
".vscode",
".cursor",
".idea",
"__pypackages__",
"build",
"dist",
"site-packages",
"docs"
]
[tool.ruff.format]
indent-style = "space" # match EditorConfig
line-ending = "lf" # enforce LF newlines
quote-style = "double" # keep quotes in sync with flake8-quotes
# Docstring code formatting
docstring-code-format = true # format Python code blocks in docstrings
docstring-code-line-length = "dynamic" # int | "dynamic" (used only if above is true)
# Trailing-comma behavior (Black's “magic comma”)
skip-magic-trailing-comma = false # leave multi-line when trailing comma present
# Formatter-only file excludes (extra to top-level exclude/extend-exclude)
exclude = []
# Opt into preview (experimental) formatting style
preview = true
[tool.ruff.lint]
# Opt into preview (experimental) linting style
preview = true
# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []
select = [
# TODO -> Uncomment all commented prefix
# prefix
"ERA", # https://docs.astral.sh/ruff/rules/#eradicate-era
"FAST", # https://docs.astral.sh/ruff/rules/#fastapi-fast
"ANN", # https://docs.astral.sh/ruff/rules/#flake8-annotations-ann
"ASYNC", # https://docs.astral.sh/ruff/rules/#flake8-async-async
# "S", # https://docs.astral.sh/ruff/rules/#flake8-bandit-s
"BLE", # https://docs.astral.sh/ruff/rules/#flake8-blind-except-ble
"FBT", # https://docs.astral.sh/ruff/rules/#flake8-boolean-trap-fbt
"B", # https://docs.astral.sh/ruff/rules/#flake8-bugbear-b
# "A", # https://docs.astral.sh/ruff/rules/#flake8-builtins-a
"C4", # https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4
"EM", # https://docs.astral.sh/ruff/rules/#flake8-errmsg-em
# "FIX", # https://docs.astral.sh/ruff/rules/#flake8-fixme-fix
"FA", # https://docs.astral.sh/ruff/rules/#flake8-future-annotations-fa
"ISC", # https://docs.astral.sh/ruff/rules/#flake8-implicit-str-concat-isc
"INP", # https://docs.astral.sh/ruff/rules/#flake8-no-pep420-inp
"PIE", # https://docs.astral.sh/ruff/rules/#flake8-pie-pie
"T20", # https://docs.astral.sh/ruff/rules/#flake8-print-t20
"PT", # https://docs.astral.sh/ruff/rules/#flake8-pytest-style-pt
"RSE", # https://docs.astral.sh/ruff/rules/#flake8-raise-rse
"RET", # https://docs.astral.sh/ruff/rules/#flake8-return-ret
"SIM", # https://docs.astral.sh/ruff/rules/#flake8-simplify-sim
# "SLOT", # https://docs.astral.sh/ruff/rules/#flake8-slots-slot
# "ARG", # https://docs.astral.sh/ruff/rules/#flake8-unused-arguments-arg
"PTH", # https://docs.astral.sh/ruff/rules/#flake8-use-pathlib-pth
"FLY", # https://docs.astral.sh/ruff/rules/#flynt-fly
"I", # https://docs.astral.sh/ruff/rules/#isort-i
"C90", # https://docs.astral.sh/ruff/rules/#mccabe-c90
"PERF", # https://docs.astral.sh/ruff/rules/#perflint-perf
"E", "W", # https://docs.astral.sh/ruff/rules/#pycodestyle-e-w
"DOC", # https://docs.astral.sh/ruff/rules/#pydoclint-doc
# "D", # https://docs.astral.sh/ruff/rules/#pydocstyle-d
"F", # https://docs.astral.sh/ruff/rules/#pyflakes-f
"PGH", # https://docs.astral.sh/ruff/rules/#pygrep-hooks-pgh
# "PL", # https://docs.astral.sh/ruff/rules/#pylint-pl
"PLC", # https://docs.astral.sh/ruff/rules/#convention-plc
"UP", # https://docs.astral.sh/ruff/rules/#pyupgrade-up
"FURB", # https://docs.astral.sh/ruff/rules/#refurb-furb
"RUF", # https://docs.astral.sh/ruff/rules/#ruff-specific-rules-ruf
"TRY", # https://docs.astral.sh/ruff/rules/#tryceratops-try
# Full rule code
"ICN003", # https://docs.astral.sh/ruff/rules/banned-import-from
"TC004", # https://docs.astral.sh/ruff/rules/runtime-import-in-type-checking-block
"TC005", # https://docs.astral.sh/ruff/rules/empty-type-checking-block
"TC008", # https://docs.astral.sh/ruff/rules/quoted-type-alias
"TC010", # https://docs.astral.sh/ruff/rules/runtime-string-union
]
ignore = [
"D100", # ignore missing docstring in module
"D102", # ignore missing docstring in public method
"D104", # ignore missing docstring in public package
"D105", # ignore missing docstring in magic methods
"D107", # ignore missing docstring in __init__ methods
"D206", # docstring-tab-indentation (formatter handles indentation)
"D300", # triple-single-quotes (formatter enforces double quotes)
"ERA001", # commented-out code
"PLC0414", # keep explicit alias
# TODO -> Remove the rules below this line
"RUF029", # Function is declared `async`, but doesn't `await` or use `async` features.
"ANN401", # https://docs.astral.sh/ruff/rules/any-type
]
# A list of mappings from file pattern to rule codes or prefixes to exclude,
# when considering any matching files. An initial '!' negates the file pattern.
[tool.ruff.lint.per-file-ignores]
"examples/samples/**.py" = [
"F403", # https://docs.astral.sh/ruff/rules/undefined-local-with-import-star
"F405", # https://docs.astral.sh/ruff/rules/undefined-local-with-import-star-usage
"E501", # https://docs.astral.sh/ruff/rules/line-too-long
]
"examples/**.py" = [
"T20", # https://docs.astral.sh/ruff/rules/#flake8-print-t20
]
"scripts/copy_src_example_to_callable.py" = ["C901"]
"src/air/tags/utils.py" = ["PLC0415"]
"src/air/tags/models/base.py" = ["PLC0415"]
"tests/test_templating.py" = ["PLC2701"]
"tests/test_responses.py" = ["PLC0415"]
"examples/airblog/airblog.py" = ["INP001"]
"examples/airblog/test_airblog.py" = ["INP001"]
"tests/benchmarks/test_memory_tag_cleanup.py" = ["RUF052"]
[tool.ruff.lint.flake8-import-conventions]
# Declare the banned `from` imports.
banned-from = []
[tool.ruff.lint.isort]
combine-as-imports = true # group aliases coming from the same module
force-wrap-aliases = true # keep the multi-line, parenthesised layout
# Help Ruff classify your own package as first-party (very important for stable sorting)
known-first-party = ["air"]
# Extra safety: mark imports from the same package as first-party when inside it
detect-same-package = true
# Keep the standard section order; set explicitly for clarity
section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"]
# Keep type-based ordering (default, but set explicitly)
order-by-type = true
# Do NOT set these (formatter conflicts):
# force-single-line, lines-after-imports, lines-between-types, split-on-trailing-comma
[tool.ruff.lint.pycodestyle]
ignore-overlong-task-comments = true
max-doc-length = 120
max-line-length = 120
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.ruff.lint.mccabe]
max-complexity = 10 # set the C901 threshold explicitly
[tool.ruff.lint.flake8-type-checking]
# Do NOT auto-quote annotations; prefer normal annotations.
quote-annotations = false
# These must exist at runtime (annotations are read/used), so don't gate their imports
runtime-evaluated-base-classes = [
"pydantic.BaseModel",
]
runtime-evaluated-decorators = [
"dataclasses.dataclass",
"pydantic.validate_call",
"fastapi.FastAPI.get",
]
# Modules that are always safe to import (never gate)
exempt-modules = ["typing", "typing_extensions"]
# endregion ruff
# region ----> ty <----
[tool.ty.src]
# Lock what gets checked so "ty check" and "ty check ." act the same
include = ["src", "tests", "examples", "docs"] # keep discovery stable
# Keep Ty aligned with .gitignore and friends (default = true; shown for clarity).
respect-ignore-files = true
[tool.ty.environment]
# Make first-party resolution stable and priority-ordered.
root = ["./src", "."]
# Freeze analysis semantics across dev/CI.
# If your project table already has `requires-python`, Ty will infer the min;
# setting explicitly keeps things deterministic.
python-version = "3.14"
# For cross-platform libraries, analyze as if code may run anywhere.
python-platform = "all"
[tool.ty.terminal]
# Fail the run on any warning.
error-on-warning = true
# Verbose output; switch to "concise" when you want minimal output.
output-format = "full"
# Promote every non-error rule to error (strict).
[tool.ty.rules]
# Defaults = warn:
ambiguous-protocol-member = "error" # https://docs.astral.sh/ty/reference/rules/#ambiguous-protocol-member
deprecated = "error" # https://docs.astral.sh/ty/reference/rules/#deprecated
invalid-ignore-comment = "error" # https://docs.astral.sh/ty/reference/rules/#invalid-ignore-comment
possibly-missing-attribute = "error" # https://docs.astral.sh/ty/reference/rules/#possibly-missing-attribute
possibly-missing-implicit-call = "error" # https://docs.astral.sh/ty/reference/rules/#possibly-missing-implicit-call
possibly-missing-import = "error" # https://docs.astral.sh/ty/reference/rules/#possibly-missing-import
redundant-cast = "error" # https://docs.astral.sh/ty/reference/rules/#redundant-cast
undefined-reveal = "error" # https://docs.astral.sh/ty/reference/rules/#undefined-reveal
ignore-comment-unknown-rule = "error" # https://docs.astral.sh/ty/reference/rules/#ignore-comment-unknown-rule
unresolved-global = "error" # https://docs.astral.sh/ty/reference/rules/#unresolved-global
unsupported-base = "error" # https://docs.astral.sh/ty/reference/rules/#unsupported-base
useless-overload-body = "error" # https://docs.astral.sh/ty/reference/rules/#useless-overload-body
# Defaults = ignore:
division-by-zero = "error" # https://docs.astral.sh/ty/reference/rules/#division-by-zero
possibly-unresolved-reference = "error" # https://docs.astral.sh/ty/reference/rules/#possibly-unresolved-reference
unused-ignore-comment = "error" # https://docs.astral.sh/ty/reference/rules/#unused-ignore-comment
# Tests often import optional dev deps or use dynamic patterns.
[[tool.ty.overrides]]
include = ["tests/**", "**/test_*.py", "**/*_test.py", "examples/airblog/**"]
[tool.ty.overrides.rules]
# TODO -> Remove all error code below
unresolved-import = "ignore"
possibly-unresolved-reference = "ignore"
invalid-argument-type = "ignore"
too-many-positional-arguments = "ignore"
unresolved-attribute = "ignore"
possibly-missing-attribute = "ignore"
# endregion ty
# region ----> pyrefly <----
[tool.pyrefly]
# keep discovery stable
project-includes = ["src", "tests", "examples", "docs"]
project-excludes = [
"**/__pycache__",
"**/*venv/**/*",
]
use-ignore-files = true
#### configuring what to type check and where to import from
search-path = ["src", "docs"]
python-version = "3.14"
# Keep resolution stable
disable-search-path-heuristics = true
# Should Pyrefly ignore errors based on annotations from other tools,
# pyre-ignore or # mypy: ignore? By default, respects # pyrefly: ignore and # type: ignore.
permissive-ignores = true
# When the table is empty, all errors are enabled by default
# setting <error-code> = true is the same as having no error code configuration present,
# which means the error will be shown. Setting <error-code> = false,
# will disable the error for type checking.
[tool.pyrefly.errors]
# TODO -> Remove all error code below
bad-override = false
no-matching-overload = false
not-callable = false
bad-assignment = false
bad-argument-type = false
bad-return = false
not-iterable = false
bad-unpacking = false
bad-index = false
missing-import = false
implicit-import = false
bad-argument-count = false
bad-param-name-override = false
missing-attribute = false
# endregion pyrefly
# region ----> pytest <----
[tool.pytest.ini_options]
# Keep imports simple (src/ layout)
pythonpath = ["src"]
# Only look here for tests
testpaths = ["tests", "examples/src"]
# Fail on most warnings
filterwarnings = ["error"] # equals: -W error
# pytest-asyncio
asyncio_mode = "auto"
# Custom markers
markers = [
"memory: marks tests as memory-focused (deselect with '-m \"not memory\"')"
]
addopts = [
"--color=yes",
"--cov-context=test", # record per-test contexts
"--cov-config=pyproject.toml", # be explicit about the config source
# TODO -> Uncomment this line, when https://github.com/ipython/ipython/issues/14620 is solved:
# "--pdbcls=IPython.terminal.debugger:Pdb",
]
# Set the directory basename patterns to avoid when recursing for test discovery.
# The individual (fnmatch-style) patterns are applied to the basename of a directory,
# to decide if to recurse into it.
norecursedirs = [
"tests/benchmarks",
"tests/templates",
]
[tool.pytest_env]
# Test value for the SUPER_SECRET_KEY environment variable
DATABASE_URL = "sqlite:///:memory:"
[tool.coverage.run]
source = ["src", "scripts"]
branch = true
parallel = true
sigterm = true
relative_files = true
data_file = ".coverage" # default “.coverage"
omit = ["tests/*", ".venv/*", "venv/*"]
[tool.coverage.report]
fail_under = 95
show_missing = true
skip_covered = true
ignore_errors = true
precision = 0
sort = "miss"
exclude_lines = [
# Pragmas explicitly telling Coverage to skip:
'pragma: no cover', # skip lines marked not to cover
'pragma: lax no cover', # skip lines marked lax not to cover
# TYPE_CHECKING guards:
'^\s*if\s+TYPE_CHECKING\s*:', # runtime-false typing gate
'^\s*if\s+typing\.TYPE_CHECKING\s*:', # runtime-false typing gate (qualified)
# Imports (declarations, not behavior):
'^\s*import\s+', # bare import lines
'^\s*from\s+\S+\s+import\s+', # from-import lines
# Typing/decorators/protocol markers:
'^\s*from\s+__future__\s+import\s+annotations\s*$', # future annotations import
'@overload', # typing overload stub
'@typing\.overload', # typing overload stub (qualified)
'@abstractmethod', # abstract method decorator
'@deprecated', # deprecated decorator marker
'\(Protocol\):$', # Protocol base class line
# Typing helpers and asserts:
'^\s*typing\.cast\(', # typing cast helper
'^\s*reveal_type\(', # static type reveal helper
'^\s*assert_never\(', # assert_never helper
'typing\.assert_never', # qualified assert_never
'^\s*[A-Za-z_][A-Za-z0-9_]*\s*:\s*[^=]+$', # pure annotation (no assignment)
# Main guards:
"^if __name__ == '__main__':", # entrypoint guard (single quotes)
'^if __name__ == "__main__":', # entrypoint guard (double quotes)
# Intentional stub exceptions:
'^\s*raise\s+NotImplementedError', # explicit unimplemented stub
# Common non-runtime noise:
'^\s*except\s+ImportError\s+as\s+_import_error\s*:', # optional import shim branch
'^\s*pass$', # no-op pass
'^\s*assert\s+False\b', # hard stop assertion
# Ellipsis placeholders:
'^\s*\.\.\.\s*(#.*)?$', # bare ellipsis
'^\s*return\s+\.\.\.\s*(#.*)?$', # return ellipsis
'^\s*[A-Za-z_][A-Za-z0-9_]*\s*:\s*[^=]+=\s*\.\.\.\s*$', # annotated ellipsis assignment
'^\s*(?:async\s+)?def\s+\w+\s*\(.*\)\s*(?:->[^:]+)?\s*:\s*\.\.\.$' # function body ellipsis
]
[tool.coverage.html]
directory = "htmlcov" # default “htmlcov”
[tool.coverage.xml]
output = "coverage.xml" # default “coverage.xml”
# Helpful for path normalization across OS/CI workers
[tool.coverage.paths]
source = ["src"]
# endregion pytest
# region ----> spell checker <----
[tool.codespell]
# Fail loud: print everything
quiet-level = 0
count = false
summary = false
interactive = 0
enable-colors = true
# Check more things
check-filenames = true
check-hidden = true
hard-encoding-detection = true
# Use extra built-in dictionaries for stricter wording
builtin = 'clear,rare,usage,informal,names,code'
# Avoid noisy or binary paths, but keep the set lean so we still catch issues
skip = '''
.idea,.git,.svn,.hg,site,.tox,.venv,venv,node_modules,dist,build,.mypy_cache,.pytest_cache,.ruff_cache,
coverage*,target,out,*.toml,*.png,*.jpg,*.jpeg,*.gif,*.bmp,*.ico,*.svg,*.pdf,*.zip,*.gz,*.tgz,
*.bz2,*.xz,*.7z,*.min.js,*.min.css,*.lock,*.pyc,.DS_Store,.coverage,.cov_html,htmlcov,.benchmarks,.cache
'''
# Ignore typos inside URLs/emails to avoid breaking links
uri-ignore-words-list = '*'
# Your project-specific words (file: one word per line)
ignore-words = '.codespellignore'
# Ignore Markdown bolding forms like **L**anguage
ignore-regex = '\*\*[A-Z]\*\*[a-z]+\b'
# Skip fenced code blocks in Markdown (reduces false positives)
ignore-multiline-regex = '```.*?```'
[tool.typos]
# Strict, safe config for English repositories
[tool.typos.files]
ignore-hidden = false # check dotfiles too
ignore-files = true # respect .gitignore etc.
ignore-dot = true # respect .ignore
ignore-vcs = true # skip .git/
ignore-global = true # respect global ignores
ignore-parent = true # respect parent ignores
extend-exclude = [
".git", ".svn", ".hg", "CHANGELOG.md",
".tox", ".venv", "venv",
"node_modules", "dist", "build", "target", "out",
".mypy_cache", ".pytest_cache", ".ruff_cache", "coverage*",
"*.png", "*.jpg", "*.jpeg", "*.gif", "*.bmp", "*.ico", "*.svg",
"*.pdf", "*.zip", "*.gz", "*.tgz", "*.bz2", "*.xz", "*.7z",
"*.min.js", "*.min.css", "*.map", "*.lock", "*.pyc"
]
[tool.typos.default]
binary = false
check-filename = true
check-file = true
unicode = true
locale = "en-us"
# endregion spell checker