-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathpyproject.toml
More file actions
431 lines (380 loc) · 16.3 KB
/
Copy pathpyproject.toml
File metadata and controls
431 lines (380 loc) · 16.3 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
[project]
name = "process-improve"
version = "1.77.0"
description = 'Designed Experiments; Latent Variables (PCA, PLS, multivariate methods with missing data); Process Monitoring; Batch data analysis.'
readme = "README.md"
license = "MIT"
requires-python = ">=3.10"
keywords = ["Designed Experiments", "Latent Variables", "PCA", "PLS", "Multivariate Data Analysis", "Batch data analysis"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Science/Research",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Information Analysis",
]
authors = [
{ name = "Kevin Dunn", email = "kgdunn@gmail.com" },
]
dependencies = [
# ENG-13 (#295): the runtime closure is intentionally trimmed to the
# minimum every package in process_improve unconditionally needs.
# Optional surfaces (plotting, experiments / DOE, batch image-IO,
# MCP server, JIT speedups) live in extras; install
# ``process-improve[all]`` to reproduce the pre-1.24.11 closure.
"numpy>=2.2.6",
# Upper-bounded below pandas 3.0: pandas 3.0.x segfaults in CI when numba
# (the `fast` extra) is also installed, a numba/llvmlite vs numpy ABI
# interaction. Revisit once a numba build supports the pandas 3 / numpy 2.4
# stack.
"pandas>=2.3.3,<3.0",
"patsy>=1.0.2",
"pydantic>=2.12.5",
"pyyaml>=6.0",
"scikit-learn>=1.7.2",
"statsmodels>=0.14.6",
"tqdm>=4.67.1",
]
[project.optional-dependencies]
# ENG-13 (#295): every public-API surface that pulls in heavy optional
# dependencies is gated by an extra. The matching ImportError raised by
# ``process_improve._extras.require`` tells the caller which extra to
# install.
# Plotting backends (Plotly + matplotlib + seaborn + ridgeplot).
plotting = [
"matplotlib>=3.10.8",
"plotly>=6.5.2",
"ridgeplot>=0.5.0",
"seaborn>=0.13.2",
]
# Designed-experiments helpers that need ``pyDOE3``.
expt = [
"pyDOE3>=1.0",
]
# Batch process data analysis: image-IO + Excel readers used by the
# batch alignment / fixture loaders.
batch = [
"openpyxl>=3.1.5",
"scikit-image>=0.25.2",
]
# MCP server entry-point. Requires the 2.x SDK: the server registers tools
# through ``mcp.server.mcpserver.MCPServer`` (renamed from 1.x's FastMCP).
mcp = ["mcp>=2.0"]
# JIT-compiled inner loops in ``process_improve.batch.alignment_helpers``.
# Without numba the module still imports and runs; the ``@jit`` decorator
# falls back to a no-op so the function executes as plain Python.
fast = ["numba>=0.63.1"]
# Integer-programming OMARS design generator (generate_omars). PuLP bundles the
# CBC solver in its wheels, so no system package is required.
ilp = ["pulp>=2.8"]
# NOTE: ``pyoptex`` (coordinate-exchange I-/A-optimal and split-plot designs in
# ``experiments.designs_optimal``) is intentionally *not* a declared extra. Its
# latest release (1.2.1) pins ``plotly~=5.24`` (i.e. < 6), which conflicts with
# this project's ``plotly>=6.5.2`` floor in the ``plotting``/``all`` extras. A
# single environment cannot satisfy both, so declaring a ``pyoptex`` extra would
# make ``uv sync --all-extras`` (used by CI) unresolvable. Install pyoptex
# separately in its own environment; without it, D-optimal still works via the
# built-in point-exchange fallback.
# Meta extra: reproduces the pre-ENG-13 install closure.
all = [
"matplotlib>=3.10.8",
"mcp>=2.0",
"numba>=0.63.1",
"openpyxl>=3.1.5",
"plotly>=6.5.2",
"pulp>=2.8",
"pyDOE3>=1.0",
"ridgeplot>=0.5.0",
"scikit-image>=0.25.2",
"seaborn>=0.13.2",
]
dev = [
"coverage>=7.13.1",
"hypothesis>=6.100",
"matplotlib-stubs>=0.3.11",
"mypy>=1.19.1,<2.4",
"pandas-stubs>=2.3.3.260113",
"plotly-stubs>=0.0.6",
"pre-commit>=4.5.1",
"pytest>=9.0.2",
"pytest-benchmark>=4.0.0",
"pytest-cov>=7.0.0",
"pytest-xdist>=3.8.0",
"pydata-sphinx-theme>=0.16.1",
"ruff>=0.11.0,<0.17", # upper-bound so a future ruff release cannot silently break the lint gate (see mypy)
"sphinx>=8.1.3",
"nbsphinx>=0.9.5",
"ipykernel>=6.29",
"tqdm-stubs>=0.2.1",
"watchdog>=6.0.0",
]
[project.scripts]
process-improve-mcp = "process_improve.mcp_server:main"
[project.urls]
Homepage = "https://github.com/kgdunn/process_improve"
Repository = "https://github.com/kgdunn/process_improve"
Issues = "https://github.com/kgdunn/process_improve/issues"
[build-system]
requires = ["uv_build>=0.7.2,<0.13"]
build-backend = "uv_build"
[dependency-groups]
dev = [
"coverage>=7.13.1",
"hypothesis>=6.100",
"matplotlib-stubs>=0.3.11",
"mypy>=1.19.1,<2.4",
"pandas-stubs>=2.3.3.260113",
"plotly-stubs>=0.0.6",
"pre-commit>=4.5.1",
# Coordinate-exchange optimal-design backend exercised by the pyoptex
# test paths in tests/test_design_generation.py and
# tests/test_designs_optimal_pyoptex.py. Dev-group only, NOT a published
# extra: pip cannot apply the [tool.uv] override-dependencies below, so
# advertising pyoptex in wheel metadata would make e.g. [expt]+[plotting]
# unresolvable for pip users until upstream ships relaxed pins.
"pyoptex>=1.2.1",
"pytest>=9.0.2",
"pytest-benchmark>=4.0.0",
"pytest-cov>=7.0.0",
"pytest-xdist>=3.8.0",
"pydata-sphinx-theme>=0.16.1",
"ruff>=0.11.0,<0.17", # upper-bound so a future ruff release cannot silently break the lint gate (see mypy)
"sphinx>=8.1.3",
"nbsphinx>=0.9.5",
"ipykernel>=6.29",
"tqdm-stubs>=0.2.1",
"watchdog>=6.0.0",
]
[tool.uv]
# pyoptex 1.2.1 (PyPI) pins plotly~=5.24 and numba~=0.61, which conflict with
# the `plotting` (plotly>=6.5.2) and `fast` (numba>=0.63.1) extras. The plotly
# relaxation is merged upstream (github.com/mborn1/pyoptex, plotly>=5.24,<7)
# but not yet released; numba is still pinned strictly upstream. These
# overrides match this project's own floors, so they change nothing else.
# Drop the plotly override once a pyoptex release ships the relaxed pin.
override-dependencies = [
"plotly>=6.5.2",
"numba>=0.63.1",
]
[tool.mypy]
ignore_missing_imports = true
disallow_untyped_defs = false
# Disable import-untyped warnings
warn_unused_ignores = false
# Specifically disable import-untyped errors
disable_error_code = ["import-untyped"]
# Example scripts under examples/ are not production code and are already
# exempted from many strict ruff rules; they pull in notebook-flavoured
# patterns (untyped locals, dynamic axis manipulation) that are noise under
# type checking.
exclude = [
"examples/",
]
[tool.ruff]
line-length = 120
exclude = [
".git",
".mypy_cache",
".ruff_cache",
"__pypackages__",
]
[tool.ruff.format]
# ruff 0.16 began formatting Python snippets inside Markdown fenced code blocks.
# The examples in README.md / CONTRIBUTING.md / CHANGELOG.md align their trailing
# comments deliberately, and the formatter strips that alignment. Markdown was
# never formatted before 0.16, so keep it that way rather than reflow the docs
# and have the gate depend on the installed ruff version (see CPY001 above).
exclude = ["*.md"]
[tool.ruff.lint]
# Enable ALL Pyflakes codes by default.
select = ["ALL"]
ignore = [
# Copyright notices are managed in the repo's own "# (c) Kevin Dunn" house
# style, not via ruff. CPY001 is a preview rule with a default regex that
# requires the literal word "Copyright"; once a ruff release promoted it to
# stable it fired on nearly every file. Keep it off so the lint gate does not
# depend on the installed ruff version.
"CPY001", # Missing copyright notice at top of file.
"C408", # Unnecessary <dict/list/tuple> call - rewrite as a literal. Disagree with this.
# Arguments
"ARG001", # Unusued argument
# Annotations not required
"ANN002", # Missing type annotation for `*args`
"ANN003", # Missing type annotation for `**kwargs`
"ANN204", # Missing return type annotation for special method `__init__`
# Docstrings
"D100", # Missing docstring in public module.
"D101", # don't require docstrings everywhere.
"D107",
"D202",
"D203",
"D205", # KGD: added this: the style of starting immediately is tough to read
"D212",
"D213",
"D402",
"D405", # Section name should be properly capitalized ("RETURN"): confused with Cypher queries
"D407", # Missing dashed underline after section ("RETURN"): confused with Cypher queries
"D413",
"D415",
"D416",
"D417",
"N803", # we don't mind mixed case variable names
"N806", # we don't mind mixed case variable names
"RET505", # Unnecessary `else` after `return` statement. Not convinced this is bad style.
# Pandas:
"PD011", # Don't agree that .values is bad style.
# Commented out code
"ERA001", # This is tough-one: commented out code does have its uses in debugging/testing
# Boolean traps. I don't necessarily agree that these are traps in Python.
"FBT001",
"FBT002",
"FBT003",
# Controversial: but let's exclude assert testing. It is useful for unit testing,
# and disabling ruff on all files that start with `**/*test_*.py` means many other useful
# checks are disabled.
"S101", # Use of assert detected.
# Testing
"TID252", # we do need relative imports for the unit tests
# Refactoring
"PLR2004", # Don't agree that this is a bad style. It leads to overly verbose code in many cases.
# PLR0917 is the preview sibling of PLR0913 (too many ARGUMENTS), which this
# repo already accepts case by case via `# noqa: PLR0913` on the wide
# scientific signatures. ruff 0.16 began reporting PLR0917 on every one of
# those same functions, so the two rules must be handled the same way or the
# lint gate would depend on the installed ruff version (see CPY001 above).
"PLR0917", # Too many positional arguments: same signatures PLR0913 already covers.
# Stop it with the trailing commas.
"COM812", # Trailing comma is not always needed - doesn't lead to more readable code.
# Ignore certain flake8-type-checking (TCH) codes.
"TC001", # Don't agree that this is a bad style. It leads to overly verbose code.
"TC002", # Don't agree that this is a bad style. It leads to overly verbose code.
"TC003", # Don't agree that this is a bad style. It leads to overly verbose code.
# Access private functions.
"SLF001", # Sometimes we need to access private functions
# Don't require that Exceptions have string literals
"EM101", # Ugly redundant code otherwise
# Issues and TODO
"TD002", # Not necessary that every todo has a username,
"TD003", # Not necessary that every todo has an issuelink
"TD004", # Not necessary that every todo has a colon
"TD005", # Not necessary that every todo has a description
"FIX002", # Not necessary that every fixme has to be removed
# OK to use f-strings in errors as far as we are concerned here
"TRY003",
"EM102",
]
# Note: exclude list is in [tool.ruff] section above
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
[tool.ruff.lint.pydocstyle]
# Docstrings follow the NumPy style; see CONTRIBUTING.md.
convention = "numpy"
[tool.ruff.lint.per-file-ignores]
"tests/**" = [
"ANN001", # Type annotations not needed in tests
# ruff 0.15 reports S310 for urllib.request.Request(), ruff 0.16 only for
# urlopen(), so an inline `# noqa: S310` is required by one version and
# reported as an unused directive (RUF100) by the other. The URLs here are
# hard-coded https literals in network-gated tests, so scope the rule off
# for tests rather than let the lint gate depend on the ruff version.
"S310", # Audit URL open: test URLs are hard-coded https literals
"ANN201", # Return type annotations not needed in tests
"ANN202", # Return type annotations not needed in tests
"D102", # Docstrings not needed in test methods
"D103", # Docstrings not needed in test functions
"PLC0415", # Inline imports are common in tests for isolation
]
"tests/fixtures/**" = [
"INP001", # __init__.py not needed for standalone fixture scripts
"T201", # print() is expected when these scripts are run manually
]
"scripts/**" = [
"ANN001", # Type annotations not needed in helper scripts
"ANN201", # Return type annotations not needed in helper scripts
"D103", # Docstrings not needed in one-off analysis scripts
"INP001", # __init__.py not needed for standalone scripts
"RET504", # Pre-return assignment kept for readability
"RUF046", # Cast-already-int OK in helper scripts
"S108", # /tmp paths are fine for local dev caches in helper scripts
"T201", # print() is expected progress output in helper scripts
]
"skills/**" = [
# Skill scripts are user-facing CLI entry points shipped inside the Claude
# Skill bundle, not library code. Their whole job is to print a report, and
# they import process_improve lazily so that a missing optional extra
# produces an install hint rather than a traceback at module load.
"ANN401", # Any is the honest annotation for a JSON payload crossing the boundary
"INP001", # __init__.py would make no sense in a skill bundle
"PLC0415", # Deliberate lazy imports: optional extras and startup cost
"T201", # print() is the output channel for a CLI script
]
"tools/**" = [
"ANN001", # Type annotations not needed in audit / tooling scripts
"ANN201", # Return type annotations not needed in audit / tooling scripts
"D103", # Docstrings not needed in tooling scripts
"INP001", # __init__.py not needed for standalone tooling scripts
"T201", # print() is expected output in audit / tooling scripts
"PLR0913", # Tooling scripts allowed many kwargs
]
"examples/**" = [
"T201", # print() is expected in example scripts and notebooks
"ANN001", # Type annotations not needed in examples
"ANN201", # Return type annotations not needed in examples
"D103", # Docstrings not needed in example scripts
"E501", # Line length less important in examples
"INP001", # __init__.py not needed in example directories
"N802", # Naming conventions relaxed in examples
"N816", # Naming conventions relaxed in examples
"PLR0915", # Complexity checks relaxed in examples
"PLR0913", # Too many arguments relaxed in examples
"A004", # Shadowing builtins OK in examples
"B905", # zip strict not needed in examples
"B011", # assert False OK in examples
"PLW2901", # Loop var overwrite OK in examples
"RUF046", # Relaxed in examples
"RUF005", # Relaxed in examples
"PT015", # Relaxed in examples
"D104", # Missing __init__.py docstring OK in examples
]
"docs/conf.py" = [
"INP001", # Sphinx conf.py is intentionally not in a package
]
"docs/user_guide/case_studies/**" = [
"T201", # print() expected in case-study notebooks
"ANN001", # Type annotations not required in didactic code
"ANN201", # Return type annotations not required
"ANN202", # Return type annotations not required
"D103", # Function docstrings not required
"D104", # __init__.py docstrings not required
"E501", # Long lines OK in narrative cells
"INP001", # No __init__.py needed
"N802", # Relaxed naming
"N816", # Relaxed naming
"PD901", # `df` is fine
"PLR0915", # Complexity relaxed
"PLR0913", # Argument count relaxed
]
"docs/applied_doe/**" = [
"T201", # print() expected in tutorial notebooks
"ANN001", # Type annotations not required in didactic code
"ANN201", # Return type annotations not required
"ANN202", # Return type annotations not required
"D103", # Function docstrings not required
"D104", # __init__.py docstrings not required
"E501", # Long lines OK in narrative cells
"INP001", # No __init__.py needed
"N802", # Relaxed naming (factor symbols A, B, T, S, etc.)
"N816", # Relaxed naming
"PD901", # `df` is fine
"PLR0915", # Complexity relaxed
"PLR0913", # Argument count relaxed
]
[tool.ruff.lint.flake8-quotes]
docstring-quotes = "double"
[tool.ruff.lint.isort]
known-third-party=["pytest", "pandas"]