Repository navigation
Expand file tree
/
Copy pathpyproject.toml
More file actions
528 lines (492 loc) · 22.2 KB
/
Copy pathpyproject.toml
File metadata and controls
528 lines (492 loc) · 22.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
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================
# Root pyproject.toml - Development environment configuration
# =============================================================================
# This file defines:
# - Tool configurations (ruff, mypy, ty)
# - Development dependency groups
#
# The streamlit package itself is defined in lib/pyproject.toml.
# Test-specific configs are in lib/pyproject.toml and e2e_playwright/pytest.ini.
# =============================================================================
[project]
name = "streamlit-dev"
version = "0.0.0"
description = "Development environment for Streamlit"
requires-python = ">=3.11"
# The published package metadata remains in lib/pyproject.toml. This requirement
# makes its runtime dependencies part of the development lock graph, while the
# source mapping below keeps the package editable.
dependencies = ["streamlit"]
[tool.uv]
# The development toolchain is the default local environment.
default-groups = ["dev"]
# Keep this floor compatible with Dependabot's bundled uv and downstream CI
# consumers that create environments from this repository.
# Check their compatibility before raising it.
required-version = ">=0.11.8"
# Resolve the development lock only for supported Python and runtime environments.
# The bound is exclusive: keep it one minor version above the newest supported Python.
environments = ["python_version < '3.16' and sys_platform != 'emscripten'"]
# Exclude packages published in the last 24 hours to lower risk from supply chain attacks
exclude-newer = "24 hours"
# Pandas 3.x is the current major on every supported Python. Keep the dev lock
# there; the published package still allows older pandas releases.
override-dependencies = [
"pandas>=3.0.0,<4",
# A marker on an override replaces every PyArrow requirement, so both sides
# are listed. Below 3.15, keep <24 so the dev lock stays on 23.0.1.
# snowflake-connector-python 4.8.0's pandas extra requires PyArrow <24 on
# Python >=3.14. The <3.15 override also covers 3.11-3.13, where that extra
# does not cap PyArrow. Drop the <24 side once that extra allows PyArrow >=24.
# On 3.15, require >=26. Earlier releases have no CPython 3.15 wheels, and
# the pandas extra would otherwise lock 23.0.1. E2E runs on 3.15, so
# regenerate st.table snapshots on this interpreter: PyArrow 26 prints
# list-of-dict keys in insertion order, and Python <3.15 (PyArrow 23) does not.
"pyarrow>=10.0.1,!=25.0.0,<24; python_version < '3.15'",
"pyarrow>=26,<27; python_version >= '3.15'",
]
[tool.uv.sources]
streamlit = { path = "lib", editable = true }
# =============================================================================
# Dependency Groups (PEP 735)
# =============================================================================
# These are development/CI-only dependencies (this package is never published).
# uv.lock is the source of truth for the exact versions that get installed, so we
# use bare package names by default and let the lock own the versions. We only add
# a version constraint when it is functionally required:
# - Exact pins (==) for tools we deliberately hold back and let Dependabot bump on
# its own PRs (ty, mypy, ruff, playwright).
# - Upper caps (<) for versions known to break us (numpy, pytest);
# these are mirrored by `ignore` entries in .github/dependabot.yml.
# - `!=` exclusions of a single known-broken release (pytest-rerunfailures,
# pytest-github-actions-annotate-failures); these need no dependabot.yml entry,
# since Dependabot targets the latest allowed version and never proposes the
# excluded release.
# Avoid lower-bound floors here: they don't affect what gets installed (the lock
# does), and Dependabot ratchets them up on every update, creating pointless
# manifest churn. NOTE: This does NOT apply to lib/pyproject.toml, whose ranges are
# the published package's contract with users and feed the min-version CI job.
[dependency-groups]
# Dependencies used by lightweight CI and release automation scripts.
# Keep this group small so those workflows do not need the complete dev environment.
automation = [
"packaging",
"requests",
"semver",
]
# Development dependencies - includes test group
dev = [
{ include-group = "test" },
"pre-commit",
# We fix ty to a version since its still in beta and likely breaks our CI on updates:
"ty==0.0.89",
# We fix ruff to a version to be in sync with the pre-commit hook:
"ruff==0.17.1",
# We fix mypy to a version to avoid breaking our CI on updates,
# and have dependabot handle the updates instead.
"mypy==2.4.0",
# Pin NumPy by Python version:
# - Below 3.15, stay under 2.5. NumPy 2.5 stubs use Python 3.12 syntax that
# mypy cannot parse while Streamlit type-checks as 3.11, the oldest
# supported version. The 3.15 CI leg skips make python-types for that reason.
# - On 3.15 and newer, require at least 2.5. Earlier releases declare 3.15
# support and publish a source distribution, but no CPython 3.15 wheel, so
# uv would lock 2.4.6.
"numpy<2.5; python_version < '3.15'",
"numpy>=2.5,<3; python_version >= '3.15'",
"mypy-protobuf",
"semver",
"setuptools",
"build",
"twine",
"wheel",
"pytz",
# mypy type stubs
"types-protobuf",
"types-pytz",
"types-requests",
"types-setuptools",
"types-Authlib",
"pandas-stubs",
]
# Test dependencies
test = [
# Testing infrastructure dependencies:
# pytest >= 9.1.0 is causing issues and is not yet supported.
"pytest<9.1.0",
"pytest-cov",
"hypothesis",
"parameterized",
"requests-mock",
"testfixtures",
# Install the same optional dependency sets users get from these extras, so tests
# exercise the real extra dependency graphs instead of a hand-maintained copy:
# - auth -> Authlib, httpx
# - charts -> matplotlib, graphviz, plotly, orjson
# - pdf -> streamlit-pdf
# - performance -> httptools, orjson, uvloop
"streamlit[auth,charts,pdf,performance]",
# Test-only packages not provided by any extra:
"seaborn",
# watchdog is skipped on macOS by the core deps; install it here so CI also
# exercises the watchdog-based file watcher on macOS.
"watchdog",
# Improved exception formatting (only bundled in the `all` extra):
"rich",
# Used by vega-lite / altair e2e tests:
"vega_datasets",
# httpx2 is used by starlette's TestClient (>=1.2); httpx (from the auth extra
# above) is still required by authlib's httpx_client integration used in the auth
# route tests.
"httpx2",
# Playwright and E2E test dependencies:
# We pin playwright to an exact version to avoid new browser versions breaking our CI.
"playwright==1.64.0",
"pytest-playwright",
"pixelmatch",
"pytest-xdist",
# pytest-rerunfailures 16.0 is breaking our CI:
# https://github.com/pytest-dev/pytest-rerunfailures/issues/302
"pytest-rerunfailures!=16.0",
# 0.4.0 regressed annotation behavior with pytest-rerunfailures (only the final
# failure of a flaky test was annotated); fixed in 0.4.1, which also dedupes
# annotations under pytest-xdist. So we only exclude the broken 0.4.0 release.
# See https://github.com/pytest-dev/pytest-github-actions-annotate-failures/issues/132
"pytest-github-actions-annotate-failures!=0.4.0",
"pytest-benchmark",
"pytest-repeat",
"pytest-timeout",
# Used for memory tracking in E2E test statistics:
"psutil",
"types-psutil",
]
# Integration test dependencies
integration = [
{ include-group = "test" },
# Snowflake dependencies (matches the `snowflake` extra users install):
"streamlit[snowflake]",
# Additional dataframe formats for testing:
"polars",
"xarray",
"dask",
"duckdb",
# Used for testing of st.connection:
"sqlalchemy[mypy]",
# Used by audio test:
"scipy",
# Used to ensure pydantic is supported:
"pydantic",
# Used by type_util tests:
"sympy",
]
# =============================================================================
# Ruff Configuration
# =============================================================================
[tool.ruff]
# Oldest supported Python. Keep in sync with mypy and ty.
target-version = "py311"
line-length = 88
extend-exclude = [
# Autogenerated files:
"lib/streamlit/proto",
"lib/streamlit/emojis.py",
"lib/streamlit/material_icon_names.py",
# File with an expected compilation error:
"e2e_playwright/compilation_error_dialog.py",
# Ignore frontend directory:
"frontend/**",
]
exclude = [
# pympler is a vendored dependency that doesn't conform to our linting rules:
"lib/streamlit/vendor/**",
]
[tool.ruff.format]
docstring-code-format = true
docstring-code-line-length = "dynamic"
line-ending = "lf"
[tool.ruff.lint]
preview = true
explicit-preview-rules = false
# We activate all rules and only ignore the rules that we don't want to enforce
# or that are not relevant for our codebase.
select = ["ALL"]
ignore = [
# Rules planned to be supported in the future:
"EM101", # Checks for the use of string literals in exception constructors.
"EM102", # Checks for the use of f-strings in exception constructors.
"TRY003", # Checks for exception messages that are not defined in the exception class itself.
# Ignored rule sets:
"DTZ", # Checks for usage of unsafe naive datetime class.
"PTH", # Enforces usage of pathlib.
"C90", # Checks for McCabe complexity.
"FBT", # Forbids boolean positional arguments.
"SLF", # Checks unexpected for private member access.
"BLE", # Checks for blind except statements.
"CPY", # Checks for copyright statement.
# DOC rules for enforcing docstring completeness (too noisy):
"DOC201", # Checks for missing return documentation.
"DOC402", # Checks for missing yield documentation.
"DOC501", # Checks for missing exception documentation.
"DOC502", # Checks for extraneous exception documentation.
# Ignored rules:
"A002", # Checks if function argument shadows a Python builtin.
"ANN401", # Checks that `any` is not used as an annotation.
"B904", # Checks for raise statements in exception handlers that lack a from clause.
"COM812", # Checks for absence of trailing commas. Not recommended with formatter.
"COM819", # Checks for presence of prohibited trailing commas. Not recommended with formatter.
"D100", # Checks for missing docstring in public module.
"D101", # Checks for missing docstring in public class.
"D102", # Checks for missing docstring in public method.
"D103", # Checks for missing docstring in public function.
"D104", # Checks for missing docstring in public package.
"D105", # Checks for missing docstring in magic method.
"D106", # Checks for missing docstring in public nested class.
"D107", # Checks for missing docstring in __init__.
"D202", # Checks for no-blank line after docstring.
"D205", # Checks for missing blank line after docstring summary.
"D401", # Checks for docstring to start with imperative mood.
"E266", # Checks for multiple leading hashes in block comments.
"FIX002", # Checks todo comments (which we want to allow).
"FURB101", # Checks for open and read calls that can be replaced by pathlib.
"FURB103", # Checks for open and write calls that can be replaced by pathlib.
"FURB113", # Checks for repeated append calls that can be replaced by extend.
"FURB152", # Checks for math constants that could use math module.
"PD009", # Checks for usage of pd.DataFrame.iat.
"PGH003", # Checks for blanket type ignore.
"PLC0415", # Enforces imports to be at the top-level of the file.
"PLC1901", # Checks for comparisons to empty string.
"PLC2701", # Checks for imports of private names.
"PLR0904", # Checks for classes with too many public methods.
"PLR0911", # Checks for functions with too many return statements.
"PLR0912", # Checks for functions with too many branches.
"PLR0913", # Checks for functions with too many arguments.
"PLR0914", # Checks for functions with too many local variables.
"PLR0915", # Checks for functions with too many statements.
"PLR0916", # Checks for too many boolean expressions in if statements.
"PLR0917", # Checks for functions with too many positional arguments.
"PLR1702", # Checks for functions with too many nested blocks.
"PLR2004", # Checks for numerical values that could be put into a constant.
"PLR6301", # Checks for methods that do not use self.
"PLW0108", # Checks for lambdas that can be replaced by existing functions.
"PLW0717", # Checks for try clauses with too many statements (new in ruff 0.15.14).
"PLW3201", # Checks for bad dunder method names.
"PT012", # Checks for pytest.raises context managers with multiple statements.
"PT019", # Checks for tests that should use @pytest.mark.usefixtures (incompatible with unittest.patch)
"PYI041", # Checks for parameter annotations that contain redundant unions between builtin numeric types (e.g., int | float).
"PYI051", # Checks for redundant unions between a Literal and a builtin supertype of that Literal.
"RET504", # Checks for assignments that immediately precede a return of the assigned variable (too opinionated).
"RSE102", # Checks for unnecessary parentheses on raised exceptions.
"RUF052", # Checks for dummy variables that are used.
"RUF067", # Checks for non empty __init__ modules.
"RUF075", # Checks for context managers that don't catch exceptions (new preview rule in ruff 0.15.14).
"SIM105", # Enforces use of contextlib.suppress.
"SIM108", # Enforces ternary operators instead of if-else.
"SIM115", # Enforces context manager for opening files.
"SIM117", # Enforces single with statement with multiple contexts.
"SIM905", # Enforces list instead of st.split.
"TD002", # Checks for missing author in TODO comment.
"TD003", # Checks for missing issue link in TODO comment.
"TRY300", # Checks for return statements in try blocks.
# New preview rules in ruff 0.15.22 that would migrate our existing
# `# noqa` comments and rule codes to the unstable `ruff:ignore` syntax and
# human-readable names. We keep the established conventions for now.
"RUF105", # Checks for legacy `# noqa` comments (migrates them to `# ruff:ignore`).
"RUF106", # Checks for rule codes in suppression comments (migrates to human-readable names).
"RUF201", # Checks for rule codes in config selectors (migrates to human-readable names).
# New code-less preview rule in ruff 0.16.5 (pedantic category). Autouse
# fixtures are intentional in our pytest and e2e test setup.
"pytest-fixture-autouse",
]
extend-safe-fixes = ["TC002", "TC003"]
[tool.ruff.lint.per-file-ignores]
# Only add ignores for entire folders here. To ignore rules in individual
# files, use the noqa ignore comment on top of the given file.
"e2e_playwright/**" = [
"B018", # Allow useless expressions (e.g., for side effects in tests).
"DOC", # Ignore docstring correctness rules.
"N999", # Allow invalid module names (test files use descriptive names).
"NPY002", # Allow legacy numpy random generation.
"PD", # Ignore pandas-vet rules (test data manipulation patterns).
"PERF", # Ignore performance rules (clarity over speed in tests).
"RUF029", # Allow async functions without await (intentional for testing async behavior).
"S", # Ignore bandit security rules (test code doesn't need security hardening).
"T20", # Allow print statements (useful for test debugging).
"TRY", # Ignore tryceratops rules (simpler exception handling in tests).
]
"lib/tests/**" = [
"ANN", # Ignore annotation rules (test functions don't need full typing).
"ARG", # Allow unused arguments (common in test fixtures and mocks).
"D", # Ignore docstring rules.
"DOC", # Ignore docstring correctness rules.
"FURB118", # Allow all operators (tests may use operator module intentionally).
"FURB189", # Allow subclassing of builtin types (for test mocking).
"INP", # Allow implicit namespace packages (test directories).
"N", # Ignore naming conventions (test names can be descriptive/long).
"NPY002", # Allow legacy numpy random generation.
"PD", # Ignore pandas-vet rules (test data manipulation patterns).
"PERF", # Ignore performance rules (clarity over speed in tests).
"PLC2801", # Allow dunder calls (e.g., object.__setattr__ for frozen dataclasses).
"RUF029", # Allow async functions without await (test fixtures, mocks, ASGI callables).
"RUF069", # Allow float equality checks in test assertions.
"S", # Ignore bandit security rules (test code doesn't need security hardening).
"TID251", # Allow direct hash constructors in test fixtures and FIPS policy probes.
"TRY", # Ignore tryceratops rules (simpler exception handling in tests).
]
"scripts/**" = ["T20", "INP", "PERF", "S", "TRY002"]
"lib/streamlit/.agents/**" = [
# Each template is a standalone app, not a package. Adding __init__.py would
# misrepresent them as importable modules.
"INP",
]
[tool.ruff.lint.flake8-tidy-imports]
# Disallow all relative imports.
ban-relative-imports = "all"
[tool.ruff.lint.flake8-tidy-imports.banned-api]
"hashlib.md5".msg = "Use streamlit.util.create_fast_hasher for non-security hashing."
"hashlib.sha1".msg = "Use an approved constructor or streamlit.util.create_fast_hasher; only use SHA-1 directly when a protocol requires it."
"hashlib.blake2b".msg = "Use streamlit.util.create_fast_hasher for non-security hashing."
"hashlib.blake2s".msg = "Use streamlit.util.create_fast_hasher for non-security hashing."
"hashlib.new".msg = "Use a named approved constructor or streamlit.util.create_fast_hasher."
[tool.ruff.lint.isort]
known-first-party = ["streamlit", "shared", "tests", "e2e_playwright"]
[tool.ruff.lint.pydocstyle]
convention = "numpy"
[tool.ruff.lint.pydoclint]
ignore-one-line-docstrings = true
[tool.ruff.lint.pycodestyle]
# Allow lines (e.g. comments) up to 120 characters instead of 88,
# which works well with Github.
max-line-length = 120
[tool.ruff.lint.flake8-comprehensions]
# Allow dict calls that make use of keyword arguments (e.g., dict(a=1, b=2)).
allow-dict-calls-with-keyword-arguments = true
[tool.ruff.lint.flake8-unused-arguments]
# Ignore unused variadic argument, like *args and **kwargs.
ignore-variadic-names = true
[tool.ruff.lint.flake8-annotations]
# Allow missing return annotation on functions that return None:
suppress-none-returning = true
# =============================================================================
# Mypy Configuration
# =============================================================================
[tool.mypy]
# Oldest supported Python. Keep in sync with ruff and ty.
python_version = "3.11"
cache_dir = ".mypy_cache"
incremental = true
files = [
"lib/streamlit/",
"lib/tests/streamlit/typing/",
"scripts/",
"e2e_playwright/",
]
exclude = [
# The compilation error test file breaks mypy because of the syntax error.
"^e2e_playwright/compilation_error_dialog\\.py$",
]
# Strict mode settings:
warn_unused_configs = true
disallow_any_generics = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
disallow_untyped_decorators = true
check_untyped_defs = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = true
no_implicit_reexport = true
strict_equality = true
extra_checks = true
# Other settings:
allow_redefinition = false
no_implicit_optional = true
strict_optional = true
warn_unreachable = true
warn_no_return = true
scripts_are_modules = true
namespace_packages = true
show_error_context = true
show_column_numbers = true
show_error_codes = true
pretty = true
[[tool.mypy.overrides]]
module = "e2e_playwright.*"
# We don't want to enforce return types for test functions
disallow_incomplete_defs = false
disallow_untyped_calls = false
disallow_untyped_defs = false
[[tool.mypy.overrides]]
module = "tests.*"
# Ignore all errors in unit tests
ignore_errors = true
[[tool.mypy.overrides]]
module = "tests.streamlit.typing.*"
# Explicitly enable type checking for the typing tests
ignore_errors = false
[[tool.mypy.overrides]]
module = [
"shared.*",
"vega_datasets.*",
"sympy.*",
"plotly.*",
"pydeck.*",
"pyarrow.*",
"graphviz.*",
"authlib.*",
"uvloop.*",
"polars.*",
# yfinance is a template-only dependency (used by dashboard-stock-peers) and has no stubs.
"yfinance.*",
# SQLAlchemy is optional and its stubs are only installed with integration extras
"sqlalchemy.*",
]
ignore_missing_imports = true
# =============================================================================
# ty Configuration
# =============================================================================
# Point the module-resolution root at ./lib (the real parent of the `streamlit`
# package) rather than ./lib/streamlit. This ensures files resolve under their
# true dotted paths (e.g. `streamlit.typing`), which is required so that
# `lib/streamlit/typing.py` does NOT shadow the standard-library `typing` module
# (a first-party top-level `typing` corrupts stdlib type resolution and panics ty).
[tool.ty.environment]
# Oldest supported Python. Keep in sync with ruff and mypy.
python-version = "3.11"
root = ["./lib"]
[tool.ty.src]
include = [
"lib/streamlit",
# Public-API typing tests; the type checkers run them, not pytest.
"lib/tests/streamlit/typing",
"e2e_playwright",
"scripts",
]
exclude = [
"e2e_playwright/compilation_error_dialog.py",
"lib/streamlit/vendor/**",
]
[tool.ty.analysis]
# Altair mark_* methods annotate return type as Self. ty currently resolves
# those as T@__call__, which falsely flags .encode/.add_params/etc. Treat
# Altair as Any until ty correctly binds Self on Altair's MarkMethodMixin.
replace-imports-with-any = ["altair.**"]
[tool.ty.rules]
unresolved-import = "ignore"
possibly-unresolved-reference = "error"
unused-ignore-comment = "ignore"
unused-type-ignore-comment = "ignore"