-
Notifications
You must be signed in to change notification settings - Fork 39
Expand file tree
/
Copy pathpyproject.toml
More file actions
150 lines (140 loc) · 6.47 KB
/
Copy pathpyproject.toml
File metadata and controls
150 lines (140 loc) · 6.47 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
# uv-managed tooling for building and checking the book's examples.
# This is not a distributable package (package = false); it only pins the
# Python version and the dev tools the harness and CI use.
#
# Common commands:
# uv sync # create .venv with the dev tools
# uv run python tools/run_examples.py # run any harness script
# uv run ty check build/examples # type-check
# make ci # the full local gate (uses uv)
#
# pandoc is a system package (see tools/README.md), not a Python dependency.
[project]
name = "thinking-in-python"
version = "0"
description = "Build and verification tooling for the book Thinking in Python."
requires-python = ">=3.15"
[dependency-groups]
dev = [
"ty",
"pytest",
"pytest-xdist",
"ruff",
"codespell>=2.4.2",
"time-machine",
"pyspellchecker",
"hypothesis>=6.155.7",
# The effect system used by the Stateless chapter. Its examples are
# type-checked by the gate, so it must be installed, not illustrative.
"stateless>=0.6.1",
# Chapter 18's vectorize_numpy.py is a real gated listing; the Numba
# sections stay illustrative until numba supports the pinned Python.
"numpy>=2.5.2",
# tools/make_cover.py's art mode: JPEG encoding, grayscale
# derivation, and resizing for the composited book covers.
"pillow>=12.3.0",
# tools/help_picker.py: the arrow-key and mouse picker that `make`
# and `make help` open in a terminal. Pure Python, so it installs on
# the pinned Python; without it `make help` prints the static listing.
"prompt-toolkit>=3.0.53",
]
[tool.uv]
package = false
# Spell checking for the book prose (and code comments). codespell uses a
# curated misspelling dictionary, so it is low-noise even over code. Words it
# flags wrongly (design-pattern terms, foreign quotes, deliberate code strings)
# live in tools/data/codespell-ignore.txt. Run with `make spell`.
[tool.codespell]
ignore-words = "tools/data/codespell-ignore.txt"
skip = "./.git,./.venv,./build,./resources,./uv.lock,*.gif,*.png"
# PEP 8 linting for the examples. line-length is 60 so listings fit
# small screens (phones, e-ink readers) without wrapping, not ruff's
# default 88. Ruff's E501 silently exempts a line whose overflow comes
# from a trailing pragma (`# type: ignore`), which is also the book's
# one sanctioned overflow. The `widths` check in tools/check_all.py
# enforces the same 60 on the Markdown itself, covering what ruff
# never sees: fragment blocks and `#:` output markers.
[tool.ruff]
line-length = 60
# target-version is inferred from requires-python (>=3.15); don't duplicate it.
[tool.ruff.lint]
# The "A" (flake8-builtins) family flags a builtin used as an identifier: a
# variable or function name (A001), argument (A002), class attribute (A003),
# import alias (A004), module/filename (A005), or lambda argument (A006).
select = ["E", "W", "F", "N", "I", "UP", "A"]
# N818: exception names need not end in "Error" (author preference).
ignore = ["N818"]
# Keep imports grouped and sorted, but drop the blank line between groups so
# listings stay dense (the book favors fewer blank lines in print and online).
[tool.ruff.lint.isort]
no-lines-before = [
"future", "standard-library", "third-party", "first-party", "local-folder",
]
lines-after-imports = 1
[tool.ruff.lint.per-file-ignores]
# This example deliberately demonstrates printf-style % formatting.
"**/string_formatting.py" = ["UP031"]
# Decorators written as classes use the lowercase decorator naming
# convention (@trace, @count_calls, @repeat), not CapWords.
"**/trace_class.py" = ["N801"]
"**/count_calls.py" = ["N801"]
"**/repeat_class.py" = ["N801"]
"**/trace_counting.py" = ["N801"]
"**/banner_cm.py" = ["N801"]
"**/singleton_class.py" = ["N801"]
"**/method_decoration.py" = ["N801"]
# These context manager classes are named like functions because you use
# them like one, matching contextlib.suppress's own naming.
"**/exceptions.py" = ["N801"]
"**/ignore_missing.py" = ["N801"]
"**/ignore_one.py" = ["N801"]
"**/ch15_ignore_types.py" = ["N801"]
# This example exists to show that importing a module runs its top-level
# code; the imported name is intentionally unused.
"**/import_module.py" = ["F401"]
# This example deliberately demonstrates assigning a lambda to a name.
"**/lambdas.py" = ["E731"]
# These examples deliberately capture into a name that looks like a
# constant, which is the mistake they exist to show.
"**/value_patterns.py" = ["N806"]
"**/ch13_fallback_capture.py" = ["N806"]
# These listings wrap a from-import in packed parenthesized form to
# fit the 60-character listing width. Ruff accepts only its
# one-name-per-line vertical style for a wrapped import, which would
# add five to nine scaffolding lines to a dense listing, so import
# formatting is waived for exactly these files; their imports stay
# hand-sorted in isort order.
"**/test_pizza_decorator.py" = ["I001"]
"**/chain.py" = ["I001"]
"**/strategy.py" = ["I001"]
"**/adapter_variations.py" = ["I001"]
"**/test_box_observer.py" = ["I001"]
"**/test_filesystem.py" = ["I001"]
"**/recycle_rtti.py" = ["I001"]
"**/test_trash.py" = ["I001"]
"**/two_way_generator.py" = ["I001"]
"**/catch_score.py" = ["I001"]
"**/casts.py" = ["I001"]
"**/fetch_guarded.py" = ["I001"]
"**/itertools_selections.py" = ["I001"]
"**/38_Patterns--Simulation/exercise_4.py" = ["I001"]
"**/46_Effects--Stateless/exercise_8.py" = ["I001"]
"**/46_Effects--Stateless/exercise_10.py" = ["I001"]
"**/46_Effects--Stateless/exercise_11.py" = ["I001"]
"**/test_ch46_ask_and_greet.py" = ["I001"]
"**/test_ch46_audit_log.py" = ["I001"]
# Examples run with cwd set to their chapter dir; adding the tree's utils/
# directory to the import path lets test files import shared helpers
# (display.py) kept there. ty needs the same path told to it separately:
# it does not read pytest's pythonpath, and its own first-party resolution
# only walks up a checked file's ancestor directories, so a sibling like
# utils/ is otherwise invisible to it.
[tool.pytest.ini_options]
pythonpath = ["build/examples/utils"]
# The second ty path is chapter 6's own directory. Its a_package/module4.py
# uses a relative import (`from .module1 import ...`), which needs a_package
# to be resolvable as a top-level package. The chapter directory is not a
# package itself (and "06_..." is not an identifier), so ty cannot establish
# module4's parent package without being handed the directory.
[tool.ty.environment]
extra-paths = ["build/examples/utils", "build/examples/06_Foundations--Modules_and_Packages"]