-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathpyproject.toml
More file actions
200 lines (186 loc) · 7.89 KB
/
Copy pathpyproject.toml
File metadata and controls
200 lines (186 loc) · 7.89 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
[build-system]
requires = ["setuptools>=68.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "petbox-dca"
version = "2.2.0"
description = "Decline Curve Library"
readme = {file = "README.rst", content-type = "text/x-rst"}
license = "MIT"
requires-python = ">=3.10"
authors = [
{name = "David S. Fulford", email = "petbox-dev@gmail.com"},
]
keywords = [
"petbox-dca", "dca", "decline curve", "type curve",
"production forecast", "production data analysis",
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Science/Research",
"Intended Audience :: Education",
"Intended Audience :: Developers",
"Natural Language :: English",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Mathematics",
"Topic :: Software Development :: Libraries",
"Typing :: Typed",
]
dependencies = [
"numpy>=2.1",
"scipy>=1.13",
]
[project.urls]
Homepage = "https://github.com/petbox-dev/dca"
[project.optional-dependencies]
# Split so the CI jobs can install only what they need. The test matrix is 4 Pythons x 3
# operating systems, and matplotlib is a heavy dependency that no collected test module imports
# -- only the figure scripts and mypy do. `dev` remains the one-stop group for a human.
test = [
"hypothesis>=6.14.8",
# THM's five transient_* functions import it lazily and raise without it, so the test that
# pins that behaviour needs it present in order to block it.
"mpmath>=1.3.0",
"pytest>=6.2.4",
"pytest-cov>=2.12.1",
]
lint = [
# Includes `test`: the lint job type-checks tests/, and mypy cannot analyse a module whose
# own imports it cannot resolve -- without pytest installed, tests/test_perf.py is
# `import-not-found` plus an untyped-decorator error per @pytest.mark. This group is
# installed once, on one runner; the matrix is what benefits from staying lean.
"petbox-dca[test]",
"mypy>=1.0",
"ruff>=0.4.0",
# Needed to type-check, not to run. tests/doc_examples.py and both docs/*_validation.py
# scripts import matplotlib, so `mypy --strict tests docs` cannot resolve them otherwise --
# and it was in no dependency group at all, meaning a fresh clone could not regenerate the
# figures in docs/img either. matplotlib ships py.typed, so no stub package is needed.
"matplotlib>=3.8",
# scipy ships no py.typed and no inline annotations. Without these the scipy imports in
# base.py and primary.py are `import-untyped` under strict, and `gammainc` returning Any
# makes SE._Nfn a no-any-return. Not optional: a machine that happens to have scipy-stubs
# installed passes while CI does not, which is exactly how that was missed.
"scipy-stubs",
]
dev = [
"petbox-dca[test,lint]",
"attrs>=19.2.0",
"coverage>=5.1",
"wheel>=0.34.2",
]
docs = [
"Sphinx<7.0.0",
"sphinx-rtd-theme==1.2.2",
]
[tool.setuptools.packages.find]
include = ["petbox.dca"]
[tool.setuptools.package-data]
"petbox.dca" = ["py.typed"]
[tool.ruff]
line-length = 120
target-version = "py310"
exclude = [
".git",
"__pycache__",
"old",
"build",
"dist",
]
[tool.ruff.lint]
select = [
"E",
"W",
"F",
"I",
"UP",
"B",
"SIM",
"TC",
"RUF",
'C90',
]
# SIM108 ("use a ternary") is the one SIM rule whose benefit inverts as the line
# limit grows: at line-length 120 it argues for ternaries up to 115 characters
# chaining several calls, which read worse than the if/else they replace. It did
# not fire at 100 because those ternaries did not fit. The rest of SIM stays on.
ignore = ["SIM108"]
[tool.ruff.lint.mccabe]
max-complexity = 20
# `strict = true` rather than a hand-listed set of flags. The list it replaced had drifted to 12
# of strict's 14, so `mypy petbox/dca` passed while `mypy --strict petbox/dca` did not.
#
# Two consequences of strict that constrain how this package is written, and that are easy to
# undo by accident:
# - no_implicit_reexport: a name merely imported into petbox/dca/__init__.py is not
# re-exported. Since the package ships py.typed, an unlisted name is invisible to any
# type-checked consumer -- `dca.MH(...)` fails in THEIR build, not ours. New public names
# must go in `__all__`.
# - warn_return_any: numpy and typeshed hand back `Any` more often than they look like they
# do (`float ** float` is Any, because a negative base with a fractional exponent is
# complex; np.where/np.diff/np.log yield dtype[Any]). A function declared `-> NDFloat` has
# to pin the type rather than pass one of those through.
[tool.mypy]
# Deliberately NO `python_version` pin. Setting it to "3.10" to match `requires-python` looks
# right and breaks: numpy >= 2.3 writes its own stubs with PEP 695 `type` statements, so mypy
# targeting 3.10 rejects numpy/__init__.pyi itself with "Type statement is only supported in
# Python 3.12 and greater". mypy therefore checks against whatever interpreter runs it, and code
# here must satisfy every version in the CI matrix -- which means not relying on a
# `# type: ignore` whose necessity varies by typeshed version. Subclass the protocol you are
# implementing instead; see `BlockMpmath(MetaPathFinder)` in tests/test_dca.py.
strict = true
warn_unreachable = true
warn_no_return = true
disallow_any_unimported = true
# No `plugins = ["numpy.typing.mypy_plugin"]`: deprecated in NumPy 2.3 and slated for removal,
# and it emits a DeprecationWarning on every run. numpy ships its own annotations, so the plugin
# no longer adds anything.
# Two modules mypy cannot resolve, declared here rather than as `# type: ignore` comments so
# the reasons live in one place and `warn_unused_ignores` can still police every inline ignore.
#
# mpmath -- 1.3.0 ships neither stubs nor a py.typed marker, so the lazy import in
# `THM._transDfn` is unanalyzable. Drop it if mpmath ever ships typing.
# data -- `tests/doc_examples.py` is the figure-generating script, run from `tests/` so
# `data.py` is a sibling on sys.path. Its `from data import ...` line is also
# rendered into docs/examples.rst by a literalinclude, so it has to keep the form a
# reader can copy; a relative `from .data import` would be wrong in both places.
#
# `mypy petbox/dca` prints `note: unused section(s): module = ['data']`, because the package
# never imports it and `warn_unused_configs` is on. That note is expected and exits 0. Two
# alternatives were tried and are worse: `mypy_path = ["tests"]` does make mypy resolve `data`,
# but then tests/data.py is reachable as both `data` and `tests.data` and mypy aborts with
# "Source file found twice under different module names"; and excluding `doc_examples.py`
# outright would stop type-checking code that is published as documentation.
[[tool.mypy.overrides]]
module = [
"mpmath.*",
"data"
]
ignore_missing_imports = true
[tool.pytest.ini_options]
# `tests` belongs in testpaths, not addopts. pytest ignores testpaths as soon as paths are
# given on the command line, so bare `pytest` still runs the suite while
# `pytest tests/test_dca.py::test_name` runs just that test. With it in addopts the
# directory was appended to every invocation, so a node ID silently ran all 143 tests.
addopts = "--cov=petbox.dca --cov-report=term-missing --cov-report=lcov:coverage.lcov --cov-config=pyproject.toml --hypothesis-show-statistics -v"
testpaths = ["tests"]
[tool.coverage.run]
# branch = true
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self\\.debug",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
]
ignore_errors = true
[tool.coverage.html]
directory = "tests/htmlcov"