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,187 @@
1
+ # Stdlib: datetime
2
+
3
+ **Purpose**: Date and time handling with timezone awareness.
4
+
5
+ **When to use**: All date/time operations. Avoid `time` module for new code.
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### Key Types
12
+ ```python
13
+ from datetime import datetime, date, time, timedelta, timezone, tzinfo
14
+
15
+ # date: year, month, day (no time, no tz)
16
+ # time: hour, minute, second, microsecond, tzinfo
17
+ # datetime: date + time + tzinfo
18
+ # timedelta: duration
19
+ # timezone: fixed offset tzinfo
20
+ # ZoneInfo (Python 3.9+): IANA timezone database
21
+ ```
22
+
23
+ ### Creation
24
+ ```python
25
+ # date
26
+ date(2024, 1, 15)
27
+ date.fromisoformat("2024-01-15")
28
+ date.today()
29
+
30
+ # time
31
+ time(14, 30, 0)
32
+ time.fromisoformat("14:30:00")
33
+
34
+ # datetime (naive = no timezone)
35
+ datetime(2024, 1, 15, 14, 30, 0)
36
+ datetime.fromisoformat("2024-01-15T14:30:00")
37
+ datetime.now() # Local naive
38
+ datetime.utcnow() # DEPRECATED — avoid
39
+
40
+ # datetime (aware = with timezone)
41
+ datetime.now(timezone.utc)
42
+ datetime.now(ZoneInfo("America/New_York"))
43
+ datetime.fromisoformat("2024-01-15T14:30:00+00:00")
44
+ ```
45
+
46
+ ### Timezone Handling (Critical)
47
+ ```python
48
+ from zoneinfo import ZoneInfo # Python 3.9+
49
+
50
+ # UTC
51
+ utc = timezone.utc
52
+ dt_utc = datetime.now(utc)
53
+
54
+ # Named timezone
55
+ ny = ZoneInfo("America/New_York")
56
+ dt_ny = datetime.now(ny)
57
+
58
+ # Convert between timezones
59
+ dt_ny = dt_utc.astimezone(ny)
60
+
61
+ # Make naive aware (assume UTC)
62
+ dt_aware = dt_naive.replace(tzinfo=timezone.utc)
63
+
64
+ # Make aware naive (lose tz info)
65
+ dt_naive = dt_aware.replace(tzinfo=None)
66
+ ```
67
+
68
+ ### Operations
69
+ ```python
70
+ # Arithmetic
71
+ dt + timedelta(days=7)
72
+ dt - timedelta(hours=3)
73
+ dt1 - dt2 # Returns timedelta
74
+
75
+ # Comparison (only aware-aware or naive-naive)
76
+ dt1 < dt2
77
+
78
+ # Replace fields
79
+ dt.replace(year=2025, hour=0)
80
+
81
+ # Formatting
82
+ dt.isoformat() # "2024-01-15T14:30:00+00:00"
83
+ dt.strftime("%Y-%m-%d %H:%M:%S")
84
+ dt.strftime("%Y-%m-%dT%H:%M:%S%z")
85
+
86
+ # Parsing
87
+ datetime.fromisoformat("2024-01-15T14:30:00+00:00") # Python 3.11+ handles all ISO
88
+ datetime.strptime("15/01/2024", "%d/%m/%Y")
89
+ ```
90
+
91
+ ### Timedelta
92
+ ```python
93
+ timedelta(days=7, hours=3, minutes=30)
94
+ timedelta(weeks=1)
95
+ timedelta.total_seconds() # Float seconds
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Decision Rules
101
+
102
+ | Situation | Type |
103
+ |-----------|------|
104
+ | Calendar date only | `date` |
105
+ | Time of day only | `time` |
106
+ | Timestamp (point in time) | `datetime` (aware!) |
107
+ | Duration | `timedelta` |
108
+ | Fixed offset | `timezone(timedelta(hours=5))` |
109
+ | Named timezone | `ZoneInfo("Region/City")` |
110
+
111
+ ---
112
+
113
+ ## Preferred Patterns
114
+
115
+ ```python
116
+ # Always use aware datetimes for timestamps
117
+ def now_utc() -> datetime:
118
+ return datetime.now(timezone.utc)
119
+
120
+ # Parse ISO with fallback
121
+ def parse_iso(s: str) -> datetime:
122
+ try:
123
+ return datetime.fromisoformat(s)
124
+ except ValueError:
125
+ # Handle common variations
126
+ for fmt in ("%Y-%m-%dT%H:%M:%S%z", "%Y-%m-%dT%H:%M:%S.%f%z", "%Y-%m-%d"):
127
+ try:
128
+ return datetime.strptime(s, fmt)
129
+ except ValueError:
130
+ continue
131
+ raise
132
+
133
+ # Serialize for JSON/API
134
+ def serialize_dt(dt: datetime) -> str:
135
+ if dt.tzinfo is None:
136
+ dt = dt.replace(tzinfo=timezone.utc)
137
+ return dt.isoformat()
138
+
139
+ # Deserialize from JSON/API
140
+ def deserialize_dt(s: str) -> datetime:
141
+ dt = parse_iso(s)
142
+ if dt.tzinfo is None:
143
+ dt = dt.replace(tzinfo=timezone.utc)
144
+ return dt
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Avoid
150
+
151
+ - `datetime.utcnow()` (deprecated, returns naive)
152
+ - Naive datetimes for timestamps (ambiguous)
153
+ - `pytz` (use `zoneinfo` stdlib in 3.9+)
154
+ - String manipulation for date math
155
+ - Comparing aware to naive (raises TypeError)
156
+ - `time.mktime` / `time.gmtime` (use datetime methods)
157
+
158
+ ---
159
+
160
+ ## Python 3.11+ Improvements
161
+
162
+ ```python
163
+ # fromisoformat handles all ISO 8601 formats
164
+ datetime.fromisoformat("2024-01-15T14:30:00+05:30")
165
+ datetime.fromisoformat("2024-01-15") # Returns date, not datetime!
166
+
167
+ # UTC shortcut
168
+ datetime.UTC # timezone.utc singleton
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Validation Considerations
174
+
175
+ - Always validate timezone on input
176
+ - Use `isinstance(dt, datetime)` not `type(dt) is datetime`
177
+ - `date` and `datetime` are not comparable
178
+ - `timedelta` has no months/years (variable length)
179
+
180
+ ---
181
+
182
+ ## Related Skills
183
+
184
+ - `stdlib/json.md` (serialization)
185
+ - `engineering/configuration.md`
186
+ - `security/input_validation.md`
187
+ - `generation/type_hints.md`
@@ -0,0 +1,238 @@
1
+ # Stdlib: functools
2
+
3
+ **Purpose**: Higher-order functions and function utilities.
4
+
5
+ **When to use**: Function composition, caching, decoration, partial application.
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### `partial` / `partialmethod`
12
+ ```python
13
+ from functools import partial, partialmethod
14
+
15
+ # Fix arguments
16
+ def power(base, exp):
17
+ return base ** exp
18
+
19
+ square = partial(power, exp=2)
20
+ square(5) # 25
21
+
22
+ # For methods (binds self)
23
+ class Math:
24
+ def __init__(self, factor):
25
+ self.factor = factor
26
+ def multiply(self, x):
27
+ return self.factor * x
28
+ double = partialmethod(multiply, 2)
29
+ ```
30
+
31
+ ### `wraps` (Critical for Decorators)
32
+ ```python
33
+ from functools import wraps
34
+
35
+ def my_decorator(func):
36
+ @wraps(func) # Copies __name__, __doc__, __annotations__, __module__, __qualname__, __dict__
37
+ def wrapper(*args, **kwargs):
38
+ return func(*args, **kwargs)
39
+ return wrapper
40
+ ```
41
+
42
+ - **Always** use on decorator wrappers
43
+ - Without it: lost metadata, broken introspection, broken type hints
44
+
45
+ ### `lru_cache` (Memoization)
46
+ ```python
47
+ from functools import lru_cache
48
+
49
+ @lru_cache(maxsize=128) # None = unbounded
50
+ def fib(n: int) -> int:
51
+ if n < 2:
52
+ return n
53
+ return fib(n-1) + fib(n-2)
54
+
55
+ fib.cache_info() # CacheInfo(hits, misses, maxsize, currsize)
56
+ fib.cache_clear() # Clear cache
57
+
58
+ # Typed cache (Python 3.9+)
59
+ @lru_cache(maxsize=None, typed=True)
60
+ def typed_func(x: int) -> int: # Separate cache for int vs float
61
+ ...
62
+ ```
63
+
64
+ - Thread-safe
65
+ - Only for pure functions (same args → same result)
66
+ - `maxsize` should be power of 2 for performance
67
+
68
+ ### `cache` (Python 3.9+)
69
+ ```python
70
+ from functools import cache
71
+
72
+ @cache
73
+ def expensive(x):
74
+ ...
75
+ ```
76
+ - Unbounded `lru_cache` (no maxsize limit)
77
+ - Simpler for "cache forever" cases
78
+
79
+ ### `cached_property` (Python 3.8+)
80
+ ```python
81
+ from functools import cached_property
82
+
83
+ class DataProcessor:
84
+ @cached_property
85
+ def processed(self) -> DataFrame:
86
+ return expensive_computation(self.raw)
87
+ ```
88
+ - Computes once per instance, caches in `__dict__`
89
+ - Not thread-safe for simultaneous first access
90
+
91
+ ### `singledispatch` / `singledispatchmethod`
92
+ ```python
93
+ from functools import singledispatch, singledispatchmethod
94
+
95
+ @singledispatch
96
+ def serialize(obj):
97
+ raise NotImplementedError(f"Cannot serialize {type(obj)}")
98
+
99
+ @serialize.register
100
+ def _(obj: int) -> str:
101
+ return str(obj)
102
+
103
+ @serialize.register
104
+ def _(obj: list) -> str:
105
+ return "[" + ", ".join(serialize(x) for x in obj) + "]"
106
+
107
+ # For methods
108
+ class Formatter:
109
+ @singledispatchmethod
110
+ def format(self, value):
111
+ raise NotImplementedError
112
+
113
+ @format.register
114
+ def _(self, value: int) -> str:
115
+ return f"int: {value}"
116
+ ```
117
+
118
+ ### `reduce`
119
+ ```python
120
+ from functools import reduce
121
+ import operator
122
+
123
+ reduce(operator.add, [1, 2, 3, 4], 0) # 10 (with initial)
124
+ reduce(operator.mul, [1, 2, 3, 4]) # 24 (no initial)
125
+ reduce(lambda acc, x: acc + [x*2], items, [])
126
+ ```
127
+
128
+ - Left fold: `reduce(f, [a,b,c], init) = f(f(f(init, a), b), c)`
129
+ - Prefer explicit loops for readability in most cases
130
+
131
+ ### `cmp_to_key`
132
+ ```python
133
+ from functools import cmp_to_key
134
+
135
+ def compare(a, b):
136
+ return (a > b) - (a < b) # -1, 0, 1
137
+
138
+ sorted(items, key=cmp_to_key(compare))
139
+ ```
140
+
141
+ - Convert old-style comparison function to key function
142
+ - Needed for complex sorting not expressible as key
143
+
144
+ ### `total_ordering`
145
+ ```python
146
+ from functools import total_ordering
147
+
148
+ @total_ordering
149
+ class Version:
150
+ def __init__(self, major, minor, patch):
151
+ self.tuple = (major, minor, patch)
152
+
153
+ def __eq__(self, other):
154
+ return self.tuple == other.tuple
155
+
156
+ def __lt__(self, other):
157
+ return self.tuple < other.tuple
158
+ # Generates __le__, __gt__, __ge__, __ne__
159
+ ```
160
+
161
+ - Define `__eq__` + one of `__lt__`, `__le__`, `__gt__`, `__ge__`
162
+ - Generates the rest
163
+
164
+ ---
165
+
166
+ ## Decision Rules
167
+
168
+ | Need | Tool |
169
+ |------|------|
170
+ | Fix some arguments | `partial` / `partialmethod` |
171
+ | Cache pure function results | `lru_cache` / `cache` |
172
+ | Cache instance property | `cached_property` |
173
+ | Single-dispatch generic function | `singledispatch` |
174
+ | Single-dispatch method | `singledispatchmethod` |
175
+ | Reduce sequence to single value | `reduce` (or explicit loop) |
176
+ | Old-style comparison to key | `cmp_to_key` |
177
+ | Auto-generate comparisons | `total_ordering` |
178
+ | Preserve decorator metadata | `wraps` (ALWAYS) |
179
+
180
+ ---
181
+
182
+ ## Preferred Patterns
183
+
184
+ ```python
185
+ # Configurable retry with partial
186
+ retry_3 = partial(retry, times=3, delay=1.0)
187
+ retry_5 = partial(retry, times=5, delay=0.5)
188
+
189
+ # Cached property for expensive computation
190
+ class Service:
191
+ def __init__(self, config):
192
+ self.config = config
193
+
194
+ @cached_property
195
+ def client(self) -> APIClient:
196
+ return APIClient(self.config.api_key, timeout=self.config.timeout)
197
+
198
+ # Generic function for extensible serialization
199
+ @singledispatch
200
+ def to_json(obj) -> str:
201
+ raise TypeError(f"Type {type(obj)} not serializable")
202
+
203
+ @to_json.register
204
+ def _(obj: datetime) -> str:
205
+ return obj.isoformat()
206
+
207
+ @to_json.register
208
+ def _(obj: UUID) -> str:
209
+ return str(obj)
210
+ ```
211
+
212
+ ---
213
+
214
+ ## Avoid
215
+
216
+ - `lru_cache` on functions with side effects
217
+ - `lru_cache` on methods without `maxsize` (memory leak — instance never freed)
218
+ - `cached_property` with mutable return values (shared reference)
219
+ - `reduce` for simple aggregations (`sum`, `max`, `min`, `any`, `all`)
220
+ - `partial` with mutable default arguments
221
+ - Forgetting `@wraps` on decorators
222
+
223
+ ---
224
+
225
+ ## Validation Considerations
226
+
227
+ - `cache_info()` for cache effectiveness monitoring
228
+ - `typed=True` prevents `1` and `1.0` sharing cache entry
229
+ - Thread safety: `lru_cache` yes, `cached_property` no
230
+
231
+ ---
232
+
233
+ ## Related Skills
234
+
235
+ - `core/advanced_python.md` (decorators)
236
+ - `core/functions.md`
237
+ - `generation/async_concurrency.md` (async caching)
238
+ - `quality/functions.md`
@@ -0,0 +1,183 @@
1
+ # Stdlib: itertools
2
+
3
+ **Purpose**: Efficient iteration tools for combinatorics and data processing.
4
+
5
+ **When to use**: Complex iteration patterns, avoiding manual loops.
6
+
7
+ ---
8
+
9
+ ## Core Rules
10
+
11
+ ### Infinite Iterators
12
+ ```python
13
+ import itertools
14
+
15
+ itertools.count(start=0, step=1) # 0, 1, 2, ...
16
+ itertools.cycle(iterable) # Repeat forever
17
+ itertools.repeat(elem, times=None) # Repeat elem (forever if times=None)
18
+ ```
19
+
20
+ ### Finite Iterators (Combinatorics)
21
+ ```python
22
+ # Cartesian product
23
+ itertools.product("AB", repeat=2) # AA, AB, BA, BB
24
+ itertools.product(range(3), "AB") # (0,A), (0,B), (1,A), ...
25
+
26
+ # Permutations (order matters)
27
+ itertools.permutations("ABCD", 2) # AB, AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC
28
+
29
+ # Combinations (order doesn't matter)
30
+ itertools.combinations("ABCD", 2) # AB, AC, AD, BC, BD, CD
31
+ itertools.combinations_with_replacement("ABCD", 2) # AA, AB, AC, AD, BB, BC, BD, CC, CD, DD
32
+ ```
33
+
34
+ ### Filtering Iterators
35
+ ```python
36
+ itertools.filterfalse(pred, iterable) # Opposite of filter
37
+ itertools.takewhile(pred, iterable) # Until pred false
38
+ itertools.dropwhile(pred, iterable) # Skip while pred true
39
+ itertools.compress(data, selectors) # Data where selector true
40
+ itertools.islice(iterable, start, stop, step) # Slice iterator
41
+ ```
42
+
43
+ ### Grouping
44
+ ```python
45
+ # Group consecutive items (input MUST be sorted by key)
46
+ itertools.groupby(iterable, key=lambda x: x[0])
47
+ # Returns (key, group_iterator) — consume group before next iteration!
48
+
49
+ # Example
50
+ data = [("a", 1), ("a", 2), ("b", 3), ("a", 4)]
51
+ for key, group in itertools.groupby(data, key=lambda x: x[0]):
52
+ print(key, list(group))
53
+ # a [(a,1), (a,2)]
54
+ # b [(b,3)]
55
+ # a [(a,4)] # Separate group!
56
+ ```
57
+
58
+ ### Accumulation
59
+ ```python
60
+ itertools.accumulate(iterable, func=operator.add)
61
+ # Running totals: [1, 2, 3] -> 1, 3, 6
62
+ itertools.accumulate([1,2,3], func=operator.mul) # 1, 2, 6
63
+ itertools.accumulate([1,2,3], initial=10) # 10, 11, 13, 16 (Python 3.8+)
64
+ ```
65
+
66
+ ### Merging/Transforming
67
+ ```python
68
+ itertools.chain(*iterables) # Flatten: chain(a, b, c)
69
+ itertools.chain.from_iterable(iterable) # Flatten nested
70
+ itertools.zip_longest(*iterables, fillvalue=None) # Pad shorter
71
+ itertools.pairwise(iterable) # (s0,s1), (s1,s2), ... (Python 3.10+)
72
+ itertools.starmap(func, iterable) # func(*args) for each item
73
+ ```
74
+
75
+ ### Recipes (from docs)
76
+ ```python
77
+ def batched(iterable, n):
78
+ "Batch data into tuples of length n. The last batch may be shorter."
79
+ if n < 1:
80
+ raise ValueError("n must be at least one")
81
+ it = iter(iterable)
82
+ while batch := tuple(itertools.islice(it, n)):
83
+ yield batch
84
+
85
+ def sliding_window(iterable, n):
86
+ "Return a sliding window of width n over the iterable."
87
+ it = iter(iterable)
88
+ window = collections.deque(itertools.islice(it, n-1), maxlen=n)
89
+ for x in it:
90
+ window.append(x)
91
+ yield tuple(window)
92
+
93
+ def roundrobin(*iterables):
94
+ "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
95
+ num_active = len(iterables)
96
+ nexts = cycle(iter(it).__next__ for it in iterables)
97
+ while num_active:
98
+ try:
99
+ for next_func in nexts:
100
+ yield next_func()
101
+ except StopIteration:
102
+ num_active -= 1
103
+ nexts = cycle(itertools.islice(nexts, num_active))
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Decision Rules
109
+
110
+ | Need | Tool |
111
+ |------|------|
112
+ | All combinations | `product` |
113
+ | Ordered selections | `permutations` |
114
+ | Unordered selections | `combinations` |
115
+ | Unordered with replacement | `combinations_with_replacement` |
116
+ | Skip prefix | `dropwhile` / `islice` |
117
+ | Take prefix | `takewhile` / `islice` |
118
+ | Group consecutive | `groupby` (sort first!) |
119
+ | Running totals | `accumulate` |
120
+ | Flatten sequences | `chain` / `chain.from_iterable` |
121
+ | Parallel iteration with padding | `zip_longest` |
122
+ | Adjacent pairs | `pairwise` (3.10+) |
123
+ | Batch processing | `batched` recipe / `itertools.batched` (3.12+) |
124
+
125
+ ---
126
+
127
+ ## Preferred Patterns
128
+
129
+ ```python
130
+ # Chunk processing
131
+ for batch in batched(large_iterable, 1000):
132
+ process_batch(batch)
133
+
134
+ # Pairwise comparison
135
+ for a, b in itertools.pairwise(sorted_data):
136
+ if b - a > threshold:
137
+ ...
138
+
139
+ # Cartesian product for parameter grids
140
+ for params in itertools.product(learning_rates, batch_sizes, optimizers):
141
+ train(*params)
142
+
143
+ # Consuming groupby correctly
144
+ for key, group in itertools.groupby(sorted_data, key=keyfunc):
145
+ group_list = list(group) # Must consume before next iteration
146
+ process_group(key, group_list)
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Avoid
152
+
153
+ - `groupby` on unsorted data (produces incorrect groups)
154
+ - Converting large iterators to lists unnecessarily
155
+ - `zip_longest` without considering `fillvalue` semantics
156
+ - Manual index management when `islice`, `enumerate`, `pairwise` exist
157
+ - Nested `product` when single `product` with multiple iterables works
158
+
159
+ ---
160
+
161
+ ## Python 3.12+ Additions
162
+
163
+ ```python
164
+ itertools.batched(iterable, n) # Built-in batching
165
+ itertools.chunked(iterable, n) # Alias for batched
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Validation Considerations
171
+
172
+ - All return iterators (lazy)
173
+ - Type checkers understand generic types
174
+ - `groupby` groups are iterators — consume immediately
175
+
176
+ ---
177
+
178
+ ## Related Skills
179
+
180
+ - `core/data_structures.md`
181
+ - `core/advanced_python.md` (generators)
182
+ - `stdlib/collections.md`
183
+ - `stdlib/functools.md`