python-skills 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. python_skills/__init__.py +10 -0
  2. python_skills/__main__.py +6 -0
  3. python_skills/adapters/__init__.py +48 -0
  4. python_skills/adapters/agent_skills.py +415 -0
  5. python_skills/adapters/aider_adapter.py +226 -0
  6. python_skills/adapters/base.py +153 -0
  7. python_skills/adapters/claude.py +474 -0
  8. python_skills/adapters/cline.py +332 -0
  9. python_skills/adapters/codex.py +24 -0
  10. python_skills/adapters/continue_adapter.py +198 -0
  11. python_skills/adapters/cursor.py +327 -0
  12. python_skills/adapters/gemini.py +26 -0
  13. python_skills/adapters/goose.py +26 -0
  14. python_skills/adapters/junie.py +25 -0
  15. python_skills/adapters/kiro.py +382 -0
  16. python_skills/adapters/opencode.py +27 -0
  17. python_skills/adapters/roo.py +25 -0
  18. python_skills/adapters/universal.py +203 -0
  19. python_skills/adapters/vscode.py +27 -0
  20. python_skills/adapters/windsurf.py +26 -0
  21. python_skills/adapters/zed.py +27 -0
  22. python_skills/cli.py +326 -0
  23. python_skills/config.py +160 -0
  24. python_skills/detector.py +152 -0
  25. python_skills/installer.py +163 -0
  26. python_skills/markers.py +115 -0
  27. python_skills/skills/__init__.py +14 -0
  28. python_skills/skills/loader.py +171 -0
  29. python_skills/skills/metadata.py +152 -0
  30. python_skills/skills/registry.py +101 -0
  31. python_skills/state.py +204 -0
  32. python_skills-1.0.0.dist-info/METADATA +99 -0
  33. python_skills-1.0.0.dist-info/RECORD +105 -0
  34. python_skills-1.0.0.dist-info/WHEEL +4 -0
  35. python_skills-1.0.0.dist-info/entry_points.txt +2 -0
  36. python_skills-1.0.0.dist-info/licenses/LICENSE +21 -0
  37. skills/advanced_python.md +239 -0
  38. skills/anti_patterns/index.md +406 -0
  39. skills/comprehensions.md +167 -0
  40. skills/control_flow.md +175 -0
  41. skills/data_structures.md +243 -0
  42. skills/debugging/common_bugs.md +222 -0
  43. skills/debugging/inspection_techniques.md +249 -0
  44. skills/debugging/root_cause.md +203 -0
  45. skills/engineering/application_logging.md +195 -0
  46. skills/engineering/cli_apps.md +207 -0
  47. skills/engineering/configuration.md +218 -0
  48. skills/engineering/database.md +240 -0
  49. skills/engineering/dependency_management.md +205 -0
  50. skills/engineering/http_clients.md +267 -0
  51. skills/engineering/modules_packages.md +211 -0
  52. skills/engineering/packaging.md +197 -0
  53. skills/engineering/project_structure.md +155 -0
  54. skills/engineering/pyproject_toml.md +302 -0
  55. skills/engineering/virtual_environments.md +206 -0
  56. skills/functions.md +244 -0
  57. skills/generation/async_concurrency.md +291 -0
  58. skills/generation/error_handling.md +276 -0
  59. skills/generation/protocols_generics.md +243 -0
  60. skills/generation/type_hints.md +290 -0
  61. skills/generation/validation_pipeline.md +274 -0
  62. skills/generation/workflow.md +190 -0
  63. skills/oop.md +228 -0
  64. skills/quality/abstractions.md +154 -0
  65. skills/quality/comments.md +177 -0
  66. skills/quality/documentation.md +176 -0
  67. skills/quality/duplication.md +137 -0
  68. skills/quality/maintainability.md +142 -0
  69. skills/quality/naming.md +171 -0
  70. skills/quality/quality_functions.md +245 -0
  71. skills/quality/readability.md +239 -0
  72. skills/quality/type_annotations.md +192 -0
  73. skills/refactoring/behavior_preservation.md +157 -0
  74. skills/refactoring/incremental.md +187 -0
  75. skills/refactoring/interface_stability.md +199 -0
  76. skills/refactoring/safe_refactoring.md +206 -0
  77. skills/security/auth_boundaries.md +200 -0
  78. skills/security/command_injection.md +207 -0
  79. skills/security/dependency_risks.md +282 -0
  80. skills/security/file_handling.md +156 -0
  81. skills/security/input_validation.md +190 -0
  82. skills/security/path_traversal.md +172 -0
  83. skills/security/secrets.md +171 -0
  84. skills/security/sql_injection.md +188 -0
  85. skills/security/unsafe_deserialization.md +164 -0
  86. skills/stdlib/argparse.md +178 -0
  87. skills/stdlib/collections.md +212 -0
  88. skills/stdlib/datetime.md +187 -0
  89. skills/stdlib/functools.md +238 -0
  90. skills/stdlib/itertools.md +183 -0
  91. skills/stdlib/json.md +162 -0
  92. skills/stdlib/logging.md +185 -0
  93. skills/stdlib/os_sys.md +184 -0
  94. skills/stdlib/pathlib.md +218 -0
  95. skills/stdlib/re.md +171 -0
  96. skills/stdlib/statistics.md +112 -0
  97. skills/stdlib/subprocess.md +211 -0
  98. skills/testing/async_tests.md +249 -0
  99. skills/testing/coverage.md +168 -0
  100. skills/testing/edge_cases.md +197 -0
  101. skills/testing/fixtures_mocks.md +203 -0
  102. skills/testing/organization.md +205 -0
  103. skills/testing/parameterized.md +174 -0
  104. skills/testing/regression_tests.md +165 -0
  105. skills/variables_types.md +107 -0
@@ -0,0 +1,164 @@
1
+ # Security: Unsafe Deserialization Prevention
2
+
3
+ **Purpose**: Prevent code execution via deserialization of untrusted data.
4
+
5
+ **When to use**: Loading pickles, YAML, JSON with custom decoders, any serialized data.
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### Never Deserialize Untrusted Data with Unsafe Formats
12
+ ```python
13
+ # NEVER — pickle executes arbitrary code
14
+ import pickle
15
+ data = pickle.loads(untrusted_bytes) # RCE!
16
+
17
+ # NEVER — yaml.load without SafeLoader
18
+ import yaml
19
+ data = yaml.load(untrusted_string) # RCE!
20
+
21
+ # NEVER — shelve (uses pickle)
22
+ import shelve
23
+ db = shelve.open(untrusted_file)
24
+
25
+ # NEVER — dill, cloudpickle, marshal
26
+ ```
27
+
28
+ ### Safe Alternatives
29
+ | Unsafe | Safe Replacement |
30
+ |--------|------------------|
31
+ | `pickle` | `json`, `msgpack`, `orjson`, `cbor2` |
32
+ | `yaml.load()` | `yaml.safe_load()` |
33
+ | `shelve` | `sqlite3` + `json` |
34
+ | Custom `__reduce__` | Don't accept serialized objects |
35
+
36
+ ### If You Must Use Pickle (Internal Only)
37
+ ```python
38
+ # ONLY for trusted internal data
39
+ # Add integrity verification
40
+ import hmac
41
+ import hashlib
42
+
43
+ def sign_data(data: bytes, key: bytes) -> bytes:
44
+ return hmac.new(key, data, hashlib.sha256).digest()
45
+
46
+ def verify_and_load(data: bytes, signature: bytes, key: bytes) -> Any:
47
+ if not hmac.compare_digest(sign(data, key), signature):
48
+ raise SecurityError("Invalid signature")
49
+ return pickle.loads(data) # Still risky if key compromised
50
+ ```
51
+
52
+ ### YAML Safe Loading
53
+ ```python
54
+ import yaml
55
+
56
+ # ALWAYS use safe_load
57
+ data = yaml.safe_load(untrusted_string)
58
+
59
+ # Or explicit SafeLoader
60
+ data = yaml.load(untrusted_string, Loader=yaml.SafeLoader)
61
+
62
+ # NEVER
63
+ data = yaml.load(untrusted_string) # Default Loader is unsafe!
64
+ data = yaml.load(untrusted_string, Loader=yaml.Loader) # Unsafe!
65
+ data = yaml.load(untrusted_string, Loader=yaml.FullLoader) # Still unsafe!
66
+ ```
67
+
68
+ ### JSON Safety
69
+ ```python
70
+ import json
71
+
72
+ # json module is SAFE — no code execution
73
+ data = json.loads(untrusted_string)
74
+
75
+ # But: watch for DoS (deeply nested, huge objects)
76
+ # Use limits if needed
77
+ import sys
78
+ json.loads(huge_string) # Can consume memory
79
+ ```
80
+
81
+ ### Custom Decoders (Risk)
82
+ ```python
83
+ # Dangerous if hook executes code
84
+ def dangerous_hook(d):
85
+ if "__class__" in d:
86
+ return globals()[d["__class__"]](**d) # RCE!
87
+ return d
88
+
89
+ json.loads(untrusted, object_hook=dangerous_hook) # NEVER
90
+
91
+ # Safe: only transform data, no execution
92
+ def safe_hook(d):
93
+ if "created_at" in d:
94
+ d["created_at"] = datetime.fromisoformat(d["created_at"])
95
+ return d
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Decision Rules
101
+
102
+ | Format | Trusted Internal | Untrusted External |
103
+ |--------|------------------|-------------------|
104
+ | JSON | ✓ | ✓ (with size limits) |
105
+ | YAML (safe_load) | ✓ | ✓ |
106
+ | MessagePack | ✓ | ✓ |
107
+ | CBOR | ✓ | ✓ |
108
+ | Pickle | ✓ (with signing) | ✗ NEVER |
109
+ | Shelve | ✓ | ✗ |
110
+ | Custom pickle | ✓ (with signing) | ✗ NEVER |
111
+
112
+ ---
113
+
114
+ ## Preferred Patterns
115
+
116
+ ```python
117
+ # Config loading — use safe format
118
+ def load_config(path: Path) -> Config:
119
+ if path.suffix == ".json":
120
+ return Config.model_validate(json.loads(path.read_text()))
121
+ elif path.suffix in (".yaml", ".yml"):
122
+ return Config.model_validate(yaml.safe_load(path.read_text()))
123
+ elif path.suffix == ".toml":
124
+ import tomllib
125
+ return Config.model_validate(tomllib.loads(path.read_text()))
126
+ else:
127
+ raise ValueError("Unsupported config format")
128
+
129
+ # Cache — use safe serialization
130
+ def cache_get(key: str) -> Any | None:
131
+ data = redis.get(key)
132
+ if data:
133
+ return json.loads(data)
134
+ return None
135
+
136
+ def cache_set(key: str, value: Any, ttl: int) -> None:
137
+ redis.setex(key, ttl, json.dumps(value, default=json_default))
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Avoid
143
+
144
+ - `pickle` for any external data
145
+ - `yaml.load()` without `SafeLoader`
146
+ - Custom `object_hook` that instantiates classes
147
+ - Storing serialized objects in database for later deserialization
148
+ - Assuming "internal" data stays internal forever
149
+
150
+ ---
151
+
152
+ ## Validation Considerations
153
+
154
+ - `bandit` B301, B506 checks
155
+ - Dependency scan for pickle usage
156
+ - Penetration testing deserialization endpoints
157
+
158
+ ---
159
+
160
+ ## Related Skills
161
+
162
+ - `security/input_validation.md`
163
+ - `stdlib/json.md`
164
+ - `engineering/configuration.md`
@@ -0,0 +1,178 @@
1
+ # Stdlib: argparse
2
+
3
+ **Purpose**: Command-line argument parsing.
4
+
5
+ **When to use**: CLI applications. For simple scripts, consider `sys.argv` or `click`/`typer` (external).
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### Basic Setup
12
+ ```python
13
+ import argparse
14
+
15
+ parser = argparse.ArgumentParser(
16
+ description="My CLI tool",
17
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter, # Shows defaults
18
+ )
19
+
20
+ # Positional argument
21
+ parser.add_argument("input", type=Path, help="Input file")
22
+
23
+ # Optional argument
24
+ parser.add_argument("-o", "--output", type=Path, help="Output file")
25
+ parser.add_argument("-v", "--verbose", action="count", default=0) # -v, -vv, -vvv
26
+
27
+ # Flag
28
+ parser.add_argument("--force", action="store_true")
29
+
30
+ # Choice
31
+ parser.add_argument("--format", choices=["json", "yaml", "txt"], default="json")
32
+
33
+ # Type with validation
34
+ def positive_int(s):
35
+ v = int(s)
36
+ if v <= 0:
37
+ raise argparse.ArgumentTypeError("Must be positive")
38
+ return v
39
+
40
+ parser.add_argument("--count", type=positive_int, default=10)
41
+
42
+ # Append (multiple values)
43
+ parser.add_argument("--tags", action="append", default=[])
44
+
45
+ # Mutually exclusive group
46
+ group = parser.add_mutually_exclusive_group(required=True)
47
+ group.add_argument("--fast", action="store_true")
48
+ group.add_argument("--thorough", action="store_true")
49
+
50
+ # Subcommands
51
+ subparsers = parser.add_subparsers(dest="command", required=True)
52
+ init_parser = subparsers.add_parser("init")
53
+ init_parser.add_argument("name")
54
+ run_parser = subparsers.add_parser("run")
55
+ run_parser.add_argument("--port", type=int, default=8000)
56
+
57
+ args = parser.parse_args()
58
+ ```
59
+
60
+ ### Namespace Access
61
+ ```python
62
+ args.input # Path object
63
+ args.output
64
+ args.verbose # 0, 1, 2, 3
65
+ args.force # True/False
66
+ args.format # "json" | "yaml" | "txt"
67
+ args.command # "init" | "run"
68
+ args.name # For init subcommand
69
+ ```
70
+
71
+ ### Custom Types
72
+ ```python
73
+ # Path validation
74
+ def existing_file(s):
75
+ path = Path(s)
76
+ if not path.is_file():
77
+ raise argparse.ArgumentTypeError(f"Not a file: {s}")
78
+ return path
79
+
80
+ parser.add_argument("file", type=existing_file)
81
+
82
+ # Comma-separated list
83
+ def csv_list(s):
84
+ return [x.strip() for x in s.split(",") if x.strip()]
85
+
86
+ parser.add_argument("--tags", type=csv_list, default=[])
87
+ ```
88
+
89
+ ### Subcommand Pattern (Recommended)
90
+ ```python
91
+ def main():
92
+ parser = create_parser()
93
+ args = parser.parse_args()
94
+
95
+ # Dispatch to handler
96
+ handlers = {
97
+ "init": handle_init,
98
+ "run": handle_run,
99
+ }
100
+ return handlers[args.command](args)
101
+
102
+ def handle_init(args):
103
+ print(f"Initializing {args.name}")
104
+
105
+ def handle_run(args):
106
+ print(f"Running on port {args.port}")
107
+
108
+ if __name__ == "__main__":
109
+ sys.exit(main())
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Decision Rules
115
+
116
+ | Need | Pattern |
117
+ |------|---------|
118
+ | Required input | Positional argument |
119
+ | Optional with default | `--option` with `default` |
120
+ | Boolean flag | `action="store_true"` |
121
+ | Count verbosity | `action="count"` |
122
+ | Multiple values | `action="append"` or `nargs="*"` |
123
+ | Choice validation | `choices=[...]` |
124
+ | Custom validation | `type=callable` |
125
+ | Subcommands | `add_subparsers()` |
126
+ | Mutually exclusive | `add_mutually_exclusive_group()` |
127
+
128
+ ---
129
+
130
+ ## Preferred Patterns
131
+
132
+ ```python
133
+ # Main entry point pattern
134
+ def create_parser() -> argparse.ArgumentParser:
135
+ parser = argparse.ArgumentParser(
136
+ prog="mytool",
137
+ description="Description",
138
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
139
+ )
140
+ # ... add arguments
141
+ return parser
142
+
143
+ def main(argv: list[str] | None = None) -> int:
144
+ parser = create_parser()
145
+ args = parser.parse_args(argv)
146
+ return dispatch(args)
147
+
148
+ if __name__ == "__main__":
149
+ sys.exit(main())
150
+ ```
151
+
152
+ ---
153
+
154
+ ## Avoid
155
+
156
+ - `sys.argv` parsing manually (error-prone)
157
+ - Global parser state
158
+ - Complex logic in `type=` callables (keep simple)
159
+ - Required optional arguments (confusing UX)
160
+ - Too many positional arguments (>2-3)
161
+
162
+ ---
163
+
164
+ ## Validation Considerations
165
+
166
+ - `parser.parse_args(["--help"])` exits 0
167
+ - Invalid args exit 2 with usage
168
+ - Test with `argv` parameter for unit testing
169
+ - `ArgumentDefaultsHelpFormatter` shows defaults in help
170
+
171
+ ---
172
+
173
+ ## Related Skills
174
+
175
+ - `engineering/cli_apps.md`
176
+ - `engineering/configuration.md`
177
+ - `stdlib/os_sys.md`
178
+ - `generation/type_hints.md`
@@ -0,0 +1,212 @@
1
+ # Stdlib: collections
2
+
3
+ **Purpose**: Specialized container datatypes beyond built-ins.
4
+
5
+ **When to use**: When built-in list/dict/set don't fit the problem.
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### `namedtuple` / `NamedTuple`
12
+ ```python
13
+ # Classic
14
+ from collections import namedtuple
15
+ Point = namedtuple("Point", ["x", "y"])
16
+
17
+ # Modern (Python 3.6+) — preferred
18
+ from typing import NamedTuple
19
+ class Point(NamedTuple):
20
+ x: float
21
+ y: float
22
+
23
+ # Usage
24
+ p = Point(1.0, 2.0)
25
+ p.x, p[0] # Both work
26
+ ```
27
+
28
+ - Immutable, hashable, lightweight
29
+ - NamedTuple supports type hints, methods, defaults
30
+
31
+ ### `dataclass` vs `NamedTuple`
32
+ | Feature | `NamedTuple` | `@dataclass` |
33
+ |---------|--------------|--------------|
34
+ | Mutability | Immutable | Mutable (or `frozen=True`) |
35
+ | Methods | Yes | Yes |
36
+ | Defaults | Yes | Yes |
37
+ | Inheritance | Limited | Full |
38
+ | Performance | Slightly faster | Flexible |
39
+
40
+ ### `defaultdict`
41
+ ```python
42
+ from collections import defaultdict
43
+
44
+ # Auto-create missing keys
45
+ grouped = defaultdict(list)
46
+ for item in items:
47
+ grouped[key(item)].append(item)
48
+
49
+ # Counter pattern
50
+ counts = defaultdict(int)
51
+ for item in items:
52
+ counts[item] += 1
53
+
54
+ # Custom factory
55
+ def default_factory():
56
+ return {"count": 0, "items": []}
57
+ ```
58
+
59
+ ### `Counter`
60
+ ```python
61
+ from collections import Counter
62
+
63
+ c = Counter(["a", "b", "a", "c", "b", "a"])
64
+ # Counter({'a': 3, 'b': 2, 'c': 1})
65
+
66
+ c.most_common(2) # [('a', 3), ('b', 2)]
67
+ c.total() # 6 (Python 3.10+)
68
+ c.elements() # Iterator over elements
69
+ c.update(["a", "d"]) # Add counts
70
+ c.subtract({"a": 1}) # Subtract counts
71
+
72
+ # Arithmetic
73
+ c1 + c2 # Add (keep positive)
74
+ c1 - c2 # Subtract (keep positive)
75
+ c1 & c2 # Intersection (min)
76
+ c1 | c2 # Union (max)
77
+ ```
78
+
79
+ ### `deque` (Double-Ended Queue)
80
+ ```python
81
+ from collections import deque
82
+
83
+ d = deque([1, 2, 3], maxlen=5) # Bounded (auto-discards old)
84
+
85
+ d.append(4) # Right
86
+ d.appendleft(0) # Left
87
+ d.pop() # Right
88
+ d.popleft() # Left
89
+ d.extend([5, 6])
90
+ d.extendleft([-1, -2])
91
+ d.rotate(1) # Rotate right
92
+ d.rotate(-1) # Rotate left
93
+
94
+ # Use cases: queue, stack, sliding window, BFS
95
+ ```
96
+
97
+ ### `OrderedDict`
98
+ ```python
99
+ from collections import OrderedDict
100
+
101
+ # Python 3.7+: regular dict preserves insertion order
102
+ # OrderedDict still useful for:
103
+ # - move_to_end(key, last=True)
104
+ # - popitem(last=True) — LIFO
105
+ # - Equality considers order
106
+ ```
107
+
108
+ ### `ChainMap`
109
+ ```python
110
+ from collections import ChainMap
111
+
112
+ # Layered mappings (config layers)
113
+ defaults = {"color": "blue", "size": 10}
114
+ user = {"size": 12}
115
+ env = {"color": "red"}
116
+
117
+ config = ChainMap(env, user, defaults)
118
+ config["color"] # "red" (first match)
119
+ config["size"] # 12
120
+
121
+ # Mutable — writes go to first mapping
122
+ config["new"] = "value" # Added to env
123
+ ```
124
+
125
+ ### `UserDict`, `UserList`, `UserString`
126
+ ```python
127
+ from collections import UserDict
128
+
129
+ class ValidatedDict(UserDict):
130
+ def __setitem__(self, key, value):
131
+ if not isinstance(key, str):
132
+ raise TypeError("Keys must be strings")
133
+ super().__setitem__(key, value)
134
+ ```
135
+
136
+ - Subclassable wrappers for built-in types
137
+ - Easier than inheriting from `dict`/`list`/`str` directly
138
+
139
+ ---
140
+
141
+ ## Decision Rules
142
+
143
+ | Need | Type |
144
+ |------|------|
145
+ | Immutable record with names | `NamedTuple` |
146
+ | Mutable record with methods | `@dataclass` |
147
+ | Auto-create missing keys | `defaultdict` |
148
+ | Count hashable items | `Counter` |
149
+ | Queue (FIFO) | `deque` |
150
+ | Stack (LIFO) | `list` or `deque` |
151
+ | Bounded buffer | `deque(maxlen=N)` |
152
+ | Sliding window | `deque(maxlen=N)` |
153
+ | Layered config | `ChainMap` |
154
+ | Custom dict behavior | `UserDict` |
155
+ | LRU cache | `functools.lru_cache` (not collections) |
156
+
157
+ ---
158
+
159
+ ## Preferred Patterns
160
+
161
+ ```python
162
+ # Frequency analysis
163
+ def top_words(text: str, n: int = 10) -> list[tuple[str, int]]:
164
+ words = re.findall(r"\w+", text.lower())
165
+ return Counter(words).most_common(n)
166
+
167
+ # Sliding window average
168
+ def moving_avg(values: list[float], window: int) -> list[float]:
169
+ from collections import deque
170
+ d = deque(maxlen=window)
171
+ result = []
172
+ for v in values:
173
+ d.append(v)
174
+ if len(d) == window:
175
+ result.append(sum(d) / window)
176
+ return result
177
+
178
+ # Config with layers
179
+ def load_config() -> ChainMap:
180
+ return ChainMap(
181
+ os.environ, # Highest priority
182
+ read_yaml("config.yaml"),
183
+ DEFAULTS, # Lowest priority
184
+ )
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Avoid
190
+
191
+ - `OrderedDict` when regular `dict` works (Python 3.7+)
192
+ - `namedtuple` (legacy) — use `NamedTuple` from `typing`
193
+ - `ChainMap` for deep nesting (only looks at first level)
194
+ - `deque` for random access (O(n)) — use `list`
195
+ - `Counter` for non-hashable items
196
+
197
+ ---
198
+
199
+ ## Validation Considerations
200
+
201
+ - Type checkers understand `NamedTuple`, `TypedDict` better than `namedtuple`
202
+ - `Counter` arithmetic returns new `Counter`
203
+ - `defaultdict` converts to regular `dict` via `dict(dd)`
204
+
205
+ ---
206
+
207
+ ## Related Skills
208
+
209
+ - `core/data_structures.md`
210
+ - `core/oop.md` (dataclasses)
211
+ - `stdlib/itertools.md`
212
+ - `generation/type_hints.md`