Repository navigation
Expand file tree
/
Copy pathpyproject.toml
More file actions
133 lines (117 loc) · 4.1 KB
/
Copy pathpyproject.toml
File metadata and controls
133 lines (117 loc) · 4.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
[tool.black]
line-length = 120
extend-exclude = '''
/(
mobile/.*/ephemeral
)/
'''
[tool.isort]
profile = "black"
line_length = 120
skip = [".eggs", ".git", ".hg", ".mypy_cache", ".tox", ".venv", "venv", "_build", "buck-out", "build", "dist", "migrations"]
[tool.pylint.messages_control]
disable = [
"C0111", # missing-docstring
"C0103", # invalid-name
"R0903", # too-few-public-methods
"R0913", # too-many-arguments
]
[tool.pylint.format]
max-line-length = 120
[tool.bandit]
exclude_dirs = ["tests", "migrations", "venv", ".venv"]
# B101: assert_used in app code is intentional in a few validation paths.
# B104: false positive when comparing hostnames to the literal "0.0.0.0"
# (not binding a socket to all interfaces).
skips = ["B101", "B104"]
[tool.coverage.run]
source = ["app"]
omit = [
"*/tests/*",
"*/test_*.py",
"*/__pycache__/*",
"*/venv/*",
"*/env/*",
"*/migrations/*",
"app/utils/pdf_generator.py",
"app/utils/pdf_generator_fallback.py",
]
[tool.coverage.report]
precision = 2
show_missing = true
skip_covered = false
exclude_lines = [
"pragma: no cover",
"def __repr__",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
"@abstractmethod",
]
[tool.mypy]
python_version = "3.11"
# warn_return_any is intentionally OFF: SQLAlchemy 1.x-style ``Model.query`` and
# ``.first()`` / ``.all()`` return ``Any``, so wrapping them in a typed return
# yields hundreds of false positives until/unless the codebase migrates to
# SQLAlchemy 2.x ``Mapped[X]`` annotations.
warn_return_any = false
warn_unused_configs = true
disallow_untyped_defs = false
ignore_missing_imports = true
# Restore pre-mypy-0.991 implicit Optional so ``def foo(x: str = None)`` is not
# flagged. The codebase uses this Flask-style idiom in many places.
implicit_optional = true
disable_error_code = [
# ``if SomeClass:`` truthy-class checks are used as import-guards across
# routes/services; their meaning is intentional.
"truthy-function",
"truthy-bool",
]
exclude = [
"migrations/",
"tests/",
"venv/",
".venv/",
]
# Flask-SQLAlchemy models defined as ``class Foo(db.Model)`` are not understood
# by mypy without a dedicated plugin. Skip them rather than chase ~150 false
# positives of "Name 'db.Model' is not defined".
[[tool.mypy.overrides]]
module = "app.models.*"
ignore_errors = true
# Repositories use ``TypeVar("ModelType")`` which mypy cannot bind to the
# Flask-SQLAlchemy ``.query`` / ``joinedload(rel)`` runtime API. The patterns
# are correct at runtime; suppress the documented limitation.
[[tool.mypy.overrides]]
module = "app.repositories.*"
disable_error_code = ["arg-type", "attr-defined"]
# Generic base service uses ``RepositoryType`` TypeVar; same limitation as
# repositories — methods exist at runtime via the bound class.
[[tool.mypy.overrides]]
module = "app.services.base_crud_service"
disable_error_code = ["attr-defined"]
# ``Query.paginate`` is added by Flask-SQLAlchemy and is missing from the
# SQLAlchemy stubs. Suppress this single attr-defined case in helpers that
# wrap pagination.
[[tool.mypy.overrides]]
module = ["app.utils.pagination", "app.services.project_service"]
disable_error_code = ["attr-defined"]
# SQLAlchemy joinedload(rel) accepts ``RelationshipProperty`` at runtime but
# is typed as ``QueryableAttribute``. This pattern is used pervasively in
# services and is correct.
[[tool.mypy.overrides]]
module = ["app.services.task_service", "app.services.quote_service", "app.services.invoice_service", "app.services.expense_service", "app.services.scheduled_report_service"]
disable_error_code = ["arg-type"]
# Pytest config is in pytest.ini (single source of truth to avoid duplicate config warning)
[tool.ruff]
line-length = 120
target-version = "py311"
extend-exclude = ["migrations", "venv", ".venv", "htmlcov", "node_modules"]
[tool.ruff.lint]
# Prefer extend-select so default rules stay off until CI adopts full ruff.
# S110 flags try/except/pass (silent exception swallowing).
extend-select = ["S110"]
[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S110"]
"scripts/**" = ["S110"]