@martinffx/atelier 2.0.0 → 3.0.1

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 (81) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +94 -253
  3. package/package.json +1 -1
  4. package/skills/{spec-orchestrator → atelier-orchestrator}/SKILL.md +3 -3
  5. package/skills/atelier-setup/SKILL.md +80 -0
  6. package/skills/code-review/references/reviewers.md +3 -3
  7. package/skills/code-review/references/rq.md +6 -6
  8. package/skills/spec-brainstorm/SKILL.md +5 -5
  9. package/skills/spec-implement/SKILL.md +2 -3
  10. package/skills/spec-plan/SKILL.md +21 -29
  11. package/skills/spec-plan/references/plan_template.md +77 -0
  12. package/skills/python-architecture/SKILL.md +0 -148
  13. package/skills/python-architecture/references/data-modeling.md +0 -558
  14. package/skills/python-architecture/references/ddd.md +0 -569
  15. package/skills/python-architecture/references/functional-core.md +0 -337
  16. package/skills/python-build-tools/SKILL.md +0 -153
  17. package/skills/python-build-tools/references/basedpyright.md +0 -321
  18. package/skills/python-build-tools/references/ruff.md +0 -225
  19. package/skills/python-build-tools/references/uv.md +0 -257
  20. package/skills/python-fastapi/SKILL.md +0 -184
  21. package/skills/python-fastapi/references/api-design.md +0 -563
  22. package/skills/python-fastapi/references/dependencies.md +0 -479
  23. package/skills/python-fastapi/references/middleware.md +0 -475
  24. package/skills/python-fastapi/references/validation.md +0 -497
  25. package/skills/python-modern-python/SKILL.md +0 -201
  26. package/skills/python-modern-python/references/async.md +0 -76
  27. package/skills/python-modern-python/references/pattern-matching.md +0 -89
  28. package/skills/python-modern-python/references/typing.md +0 -96
  29. package/skills/python-monorepo/SKILL.md +0 -146
  30. package/skills/python-monorepo/references/docker.md +0 -515
  31. package/skills/python-monorepo/references/namespace-packages.md +0 -426
  32. package/skills/python-monorepo/references/workspace-config.md +0 -341
  33. package/skills/python-sqlalchemy/SKILL.md +0 -119
  34. package/skills/python-sqlalchemy/references/async.md +0 -51
  35. package/skills/python-sqlalchemy/references/models.md +0 -67
  36. package/skills/python-sqlalchemy/references/queries.md +0 -57
  37. package/skills/python-temporal/SKILL.md +0 -128
  38. package/skills/python-temporal/references/patterns.md +0 -87
  39. package/skills/python-temporal/references/testing.md +0 -54
  40. package/skills/python-testing/SKILL.md +0 -161
  41. package/skills/python-testing/references/boundaries.md +0 -449
  42. package/skills/python-testing/references/mocking.md +0 -449
  43. package/skills/python-testing/references/pytest.md +0 -524
  44. package/skills/typescript-api-design/SKILL.md +0 -396
  45. package/skills/typescript-api-design/references/error-responses.md +0 -469
  46. package/skills/typescript-build-tools/SKILL.md +0 -447
  47. package/skills/typescript-build-tools/references/biome.md +0 -436
  48. package/skills/typescript-build-tools/references/bun.md +0 -432
  49. package/skills/typescript-build-tools/references/turborepo.md +0 -426
  50. package/skills/typescript-build-tools/references/vitest.md +0 -518
  51. package/skills/typescript-drizzle-orm/SKILL.md +0 -398
  52. package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
  53. package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
  54. package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
  55. package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
  56. package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
  57. package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
  58. package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
  59. package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
  60. package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
  61. package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
  62. package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
  63. package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
  64. package/skills/typescript-effect-ts/SKILL.md +0 -341
  65. package/skills/typescript-effect-ts/references/core.md +0 -412
  66. package/skills/typescript-effect-ts/references/error-handling.md +0 -468
  67. package/skills/typescript-effect-ts/references/resources.md +0 -476
  68. package/skills/typescript-effect-ts/references/schema.md +0 -536
  69. package/skills/typescript-effect-ts/references/services.md +0 -461
  70. package/skills/typescript-fastify/SKILL.md +0 -405
  71. package/skills/typescript-fastify/references/plugins.md +0 -329
  72. package/skills/typescript-fastify/references/typeid.md +0 -315
  73. package/skills/typescript-functional-patterns/SKILL.md +0 -402
  74. package/skills/typescript-functional-patterns/references/adts.md +0 -497
  75. package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
  76. package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
  77. package/skills/typescript-functional-patterns/references/option-result.md +0 -585
  78. package/skills/typescript-testing/SKILL.md +0 -353
  79. package/skills/typescript-testing/references/mocking.md +0 -675
  80. package/skills/typescript-testing/references/msw.md +0 -852
  81. package/skills/typescript-testing/references/snapshot-testing.md +0 -774
@@ -1,497 +0,0 @@
1
- # Pydantic Validation in FastAPI
2
-
3
- FastAPI uses Pydantic for request/response validation. Comprehensive validation patterns.
4
-
5
- ## Field Constraints
6
-
7
- ### Numeric Constraints
8
-
9
- ```python
10
- from pydantic import BaseModel, Field
11
- from decimal import Decimal
12
-
13
- class Product(BaseModel):
14
- price: Decimal = Field(gt=0, decimal_places=2) # Greater than 0, 2 decimals
15
- discount: float = Field(ge=0, le=1) # Between 0 and 1
16
- stock: int = Field(ge=0) # Greater than or equal to 0
17
- rating: float = Field(ge=0, le=5) # Rating from 0 to 5
18
-
19
- # Field constraints:
20
- # gt: greater than
21
- # ge: greater than or equal
22
- # lt: less than
23
- # le: less than or equal
24
- # multiple_of: must be multiple of value
25
- # decimal_places: max decimal places
26
- ```
27
-
28
- ### String Constraints
29
-
30
- ```python
31
- class User(BaseModel):
32
- username: str = Field(min_length=3, max_length=50)
33
- email: str = Field(pattern=r"^[\w\.\+\-]+@[\w\.\-]+\.\w+$")
34
- password: str = Field(min_length=8, max_length=100)
35
- bio: str | None = Field(default=None, max_length=500)
36
-
37
- # String constraints:
38
- # min_length: minimum length
39
- # max_length: maximum length
40
- # pattern: regex pattern
41
- ```
42
-
43
- ### Collection Constraints
44
-
45
- ```python
46
- class Order(BaseModel):
47
- items: list[str] = Field(min_length=1, max_length=100) # 1-100 items
48
- tags: set[str] = Field(max_length=10) # Max 10 unique tags
49
-
50
- # Collection constraints:
51
- # min_length: minimum items
52
- # max_length: maximum items
53
- ```
54
-
55
- ## Field Types
56
-
57
- ### Special Pydantic Types
58
-
59
- ```python
60
- from pydantic import BaseModel, EmailStr, HttpUrl, UUID4, constr, conint
61
-
62
- class User(BaseModel):
63
- id: UUID4 # Valid UUID4
64
- email: EmailStr # Valid email
65
- website: HttpUrl # Valid HTTP URL
66
- username: constr(min_length=3, max_length=50) # Constrained string
67
- age: conint(ge=18, le=120) # Constrained int
68
-
69
- # Install email-validator for EmailStr:
70
- # pip install email-validator
71
- ```
72
-
73
- ### Datetime Types
74
-
75
- ```python
76
- from datetime import datetime, date, time
77
- from pydantic import BaseModel, Field
78
-
79
- class Event(BaseModel):
80
- name: str
81
- start_date: date # YYYY-MM-DD
82
- start_time: time # HH:MM:SS
83
- created_at: datetime # ISO 8601 datetime
84
-
85
- class Appointment(BaseModel):
86
- scheduled_at: datetime = Field(
87
- description="Appointment datetime in ISO 8601 format"
88
- )
89
- ```
90
-
91
- ## Custom Validators
92
-
93
- ### Field Validators
94
-
95
- ```python
96
- from pydantic import BaseModel, field_validator
97
-
98
- class User(BaseModel):
99
- email: str
100
- age: int
101
-
102
- @field_validator("email")
103
- @classmethod
104
- def validate_email(cls, v):
105
- """Validate email domain"""
106
- if not v.endswith("@example.com"):
107
- raise ValueError("Only @example.com emails allowed")
108
- return v
109
-
110
- @field_validator("age")
111
- @classmethod
112
- def validate_age(cls, v):
113
- """Validate age range"""
114
- if v < 18:
115
- raise ValueError("Must be at least 18 years old")
116
- if v > 120:
117
- raise ValueError("Age must be realistic")
118
- return v
119
- ```
120
-
121
- ### Model Validators
122
-
123
- Validate across multiple fields:
124
-
125
- ```python
126
- from pydantic import BaseModel, model_validator
127
-
128
- class DateRange(BaseModel):
129
- start_date: date
130
- end_date: date
131
-
132
- @model_validator(mode="after")
133
- def validate_date_range(self):
134
- """Validate start before end"""
135
- if self.start_date >= self.end_date:
136
- raise ValueError("start_date must be before end_date")
137
- return self
138
-
139
- class Order(BaseModel):
140
- items: list[str]
141
- discount: float
142
-
143
- @model_validator(mode="after")
144
- def validate_discount_eligibility(self):
145
- """Discount requires minimum items"""
146
- if self.discount > 0 and len(self.items) < 2:
147
- raise ValueError("Discount requires at least 2 items")
148
- return self
149
- ```
150
-
151
- ### Transform Values
152
-
153
- ```python
154
- from pydantic import field_validator
155
-
156
- class User(BaseModel):
157
- email: str
158
- username: str
159
-
160
- @field_validator("email")
161
- @classmethod
162
- def lowercase_email(cls, v):
163
- """Normalize email to lowercase"""
164
- return v.lower()
165
-
166
- @field_validator("username")
167
- @classmethod
168
- def strip_username(cls, v):
169
- """Remove whitespace from username"""
170
- return v.strip()
171
- ```
172
-
173
- ## Complex Validation
174
-
175
- ### Conditional Validation
176
-
177
- ```python
178
- from pydantic import BaseModel, model_validator
179
-
180
- class Payment(BaseModel):
181
- method: str # "card" or "bank"
182
- card_number: str | None = None
183
- bank_account: str | None = None
184
-
185
- @model_validator(mode="after")
186
- def validate_payment_method(self):
187
- """Validate required fields based on method"""
188
- if self.method == "card":
189
- if not self.card_number:
190
- raise ValueError("card_number required for card payment")
191
- elif self.method == "bank":
192
- if not self.bank_account:
193
- raise ValueError("bank_account required for bank payment")
194
- else:
195
- raise ValueError("Invalid payment method")
196
- return self
197
- ```
198
-
199
- ### List Item Validation
200
-
201
- ```python
202
- from pydantic import BaseModel, field_validator
203
-
204
- class Order(BaseModel):
205
- items: list[str]
206
-
207
- @field_validator("items")
208
- @classmethod
209
- def validate_items(cls, v):
210
- """Validate each item"""
211
- if not v:
212
- raise ValueError("Order must have at least one item")
213
-
214
- # Check for duplicates
215
- if len(v) != len(set(v)):
216
- raise ValueError("Duplicate items not allowed")
217
-
218
- # Validate each item
219
- for item in v:
220
- if len(item) < 3:
221
- raise ValueError(f"Item name too short: {item}")
222
-
223
- return v
224
- ```
225
-
226
- ## Nested Models
227
-
228
- ```python
229
- from pydantic import BaseModel, Field
230
-
231
- class Address(BaseModel):
232
- street: str
233
- city: str
234
- country: str = Field(pattern=r"^[A-Z]{2}$") # Country code
235
-
236
- class User(BaseModel):
237
- name: str
238
- email: EmailStr
239
- address: Address # Nested model
240
-
241
- # Request body:
242
- # {
243
- # "name": "Alice",
244
- # "email": "alice@example.com",
245
- # "address": {
246
- # "street": "123 Main St",
247
- # "city": "New York",
248
- # "country": "US"
249
- # }
250
- # }
251
- ```
252
-
253
- ## Optional Fields
254
-
255
- ```python
256
- from typing import Optional
257
-
258
- class User(BaseModel):
259
- name: str
260
- email: str
261
- bio: str | None = None # Optional, defaults to None
262
- age: int | None = None # Optional
263
- website: HttpUrl | None = None # Optional URL
264
-
265
- # Or use Optional (older syntax)
266
- class User(BaseModel):
267
- name: str
268
- bio: Optional[str] = None
269
- ```
270
-
271
- ## Default Values
272
-
273
- ```python
274
- from datetime import datetime
275
- from uuid import uuid4
276
-
277
- class User(BaseModel):
278
- id: UUID = Field(default_factory=uuid4) # Generate new UUID
279
- created_at: datetime = Field(default_factory=datetime.now)
280
- is_active: bool = True # Static default
281
- role: str = "user" # Static default
282
- ```
283
-
284
- ## Union Types
285
-
286
- ```python
287
- from typing import Union
288
- from pydantic import field_validator
289
-
290
- class FlexibleField(BaseModel):
291
- value: int | str # Can be int or string
292
-
293
- @field_validator("value")
294
- @classmethod
295
- def validate_value(cls, v):
296
- """Validate based on type"""
297
- if isinstance(v, int):
298
- if v < 0:
299
- raise ValueError("Int value must be positive")
300
- elif isinstance(v, str):
301
- if len(v) < 3:
302
- raise ValueError("String value too short")
303
- return v
304
- ```
305
-
306
- ## Discriminated Unions
307
-
308
- For handling multiple types with type field:
309
-
310
- ```python
311
- from typing import Literal, Union
312
- from pydantic import BaseModel, Field
313
-
314
- class CardPayment(BaseModel):
315
- type: Literal["card"]
316
- card_number: str
317
- cvv: str
318
-
319
- class BankPayment(BaseModel):
320
- type: Literal["bank"]
321
- account_number: str
322
- routing_number: str
323
-
324
- class Payment(BaseModel):
325
- payment: Union[CardPayment, BankPayment] = Field(discriminator="type")
326
-
327
- # FastAPI automatically validates based on "type" field
328
- ```
329
-
330
- ## Custom Error Messages
331
-
332
- ```python
333
- from pydantic import BaseModel, Field, field_validator, ValidationError
334
-
335
- class User(BaseModel):
336
- age: int = Field(
337
- ge=18,
338
- le=120,
339
- description="User age in years",
340
- )
341
-
342
- @field_validator("age")
343
- @classmethod
344
- def validate_age(cls, v):
345
- if v < 18:
346
- raise ValueError("You must be at least 18 years old to register")
347
- return v
348
-
349
- # Customize validation error response in FastAPI
350
- from fastapi import Request, status
351
- from fastapi.responses import JSONResponse
352
- from fastapi.exceptions import RequestValidationError
353
-
354
- @app.exception_handler(RequestValidationError)
355
- async def validation_exception_handler(request: Request, exc: RequestValidationError):
356
- """Custom validation error format"""
357
- errors = []
358
- for error in exc.errors():
359
- errors.append({
360
- "field": ".".join(str(loc) for loc in error["loc"]),
361
- "message": error["msg"],
362
- "type": error["type"],
363
- })
364
-
365
- return JSONResponse(
366
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
367
- content={"errors": errors},
368
- )
369
- ```
370
-
371
- ## Reusable Validation
372
-
373
- ```python
374
- from pydantic import field_validator
375
-
376
- def validate_positive(v: int) -> int:
377
- """Reusable validator"""
378
- if v <= 0:
379
- raise ValueError("Must be positive")
380
- return v
381
-
382
- class Product(BaseModel):
383
- price: int
384
- stock: int
385
-
386
- _validate_price = field_validator("price")(classmethod(validate_positive))
387
- _validate_stock = field_validator("stock")(classmethod(validate_positive))
388
- ```
389
-
390
- ## Config Options
391
-
392
- ```python
393
- from pydantic import BaseModel, ConfigDict
394
-
395
- class User(BaseModel):
396
- model_config = ConfigDict(
397
- str_strip_whitespace=True, # Strip whitespace from strings
398
- str_min_length=1, # Minimum string length
399
- validate_assignment=True, # Validate on assignment
400
- validate_default=True, # Validate default values
401
- from_attributes=True, # Enable ORM mode
402
- )
403
-
404
- name: str
405
- email: str
406
- ```
407
-
408
- ## Validation in Route
409
-
410
- ```python
411
- from fastapi import HTTPException
412
-
413
- @app.post("/users")
414
- def create_user(user: CreateUserRequest):
415
- """Pydantic validation happens automatically"""
416
- # If validation fails, FastAPI returns 422 with error details
417
- # If successful, user is validated CreateUserRequest instance
418
-
419
- # Additional business validation
420
- if user_exists(user.email):
421
- raise HTTPException(
422
- status_code=400,
423
- detail="User with this email already exists",
424
- )
425
-
426
- return create_user_in_db(user)
427
- ```
428
-
429
- ## Testing Validation
430
-
431
- ```python
432
- import pytest
433
- from pydantic import ValidationError
434
-
435
- def test_valid_user():
436
- """Test valid user creation"""
437
- user = CreateUserRequest(
438
- email="test@example.com",
439
- name="Test User",
440
- age=25,
441
- )
442
- assert user.email == "test@example.com"
443
-
444
- def test_invalid_email():
445
- """Test invalid email"""
446
- with pytest.raises(ValidationError) as exc_info:
447
- CreateUserRequest(
448
- email="invalid-email",
449
- name="Test User",
450
- age=25,
451
- )
452
- errors = exc_info.value.errors()
453
- assert any(error["loc"] == ("email",) for error in errors)
454
-
455
- def test_age_validation():
456
- """Test age must be >= 18"""
457
- with pytest.raises(ValidationError) as exc_info:
458
- CreateUserRequest(
459
- email="test@example.com",
460
- name="Test User",
461
- age=15,
462
- )
463
- errors = exc_info.value.errors()
464
- assert "age" in str(errors)
465
- ```
466
-
467
- ## Best Practices
468
-
469
- 1. **Use Field constraints**: Prefer `Field(gt=0)` over custom validators for simple cases
470
- 2. **Descriptive error messages**: Make validation errors helpful
471
- 3. **Validate early**: Pydantic validates at API boundary
472
- 4. **Normalize data**: Use validators to transform (lowercase email, strip whitespace)
473
- 5. **Test validators**: Write tests for complex validation logic
474
- 6. **Reuse validators**: Extract common validators to functions
475
- 7. **Model validators for cross-field**: Use `@model_validator` when validating multiple fields
476
-
477
- ## Summary
478
-
479
- **Field constraints:**
480
- - Numeric: `gt`, `ge`, `lt`, `le`, `multiple_of`
481
- - String: `min_length`, `max_length`, `pattern`
482
- - Collection: `min_length`, `max_length`
483
-
484
- **Validators:**
485
- - `@field_validator`: Validate single field
486
- - `@model_validator`: Validate across fields
487
- - Transform values in validators
488
-
489
- **Special types:**
490
- - `EmailStr`: Valid email
491
- - `HttpUrl`: Valid URL
492
- - `UUID4`: Valid UUID
493
-
494
- **Error handling:**
495
- - Automatic 422 responses
496
- - Custom error messages
497
- - Exception handlers
@@ -1,201 +0,0 @@
1
- ---
2
- name: python-modern-python
3
- description: Modern Python language features and typing patterns. Use when writing type hints, using generics, implementing pattern matching, working with async/await, or leveraging Python 3.10+ features.
4
- user-invocable: false
5
- ---
6
-
7
- # Modern Python Features
8
-
9
- Modern Python 3.10+ language features, type hints, and patterns.
10
-
11
- ## Type Hints
12
-
13
- ### Basic Types
14
-
15
- ```python
16
- def greet(name: str) -> str:
17
- return f"Hello {name}"
18
-
19
- age: int = 25
20
- prices: list[float] = [9.99, 19.99]
21
- mapping: dict[str, int] = {"a": 1}
22
- ```
23
-
24
- ### Union Types (Python 3.10+)
25
-
26
- ```python
27
- # Modern syntax
28
- def process(value: int | str) -> bool:
29
- ...
30
-
31
- # Optional
32
- def get_user(id: int) -> User | None:
33
- ...
34
-
35
- # Multiple types
36
- Result = int | str | bool
37
- ```
38
-
39
- ### Generic Types
40
-
41
- ```python
42
- from typing import TypeVar, Generic
43
-
44
- T = TypeVar("T")
45
-
46
- class Repository(Generic[T]):
47
- def get(self, id: int) -> T | None:
48
- ...
49
-
50
- def save(self, entity: T) -> T:
51
- ...
52
-
53
- user_repo = Repository[User]()
54
- ```
55
-
56
- ### Protocol (Structural Typing)
57
-
58
- ```python
59
- from typing import Protocol
60
-
61
- class Drawable(Protocol):
62
- """Structural type - any class with draw()"""
63
- def draw(self) -> None:
64
- ...
65
-
66
- def render(obj: Drawable) -> None:
67
- """Works with any object that has draw()"""
68
- obj.draw()
69
- ```
70
-
71
- ## Pattern Matching (Python 3.10+)
72
-
73
- ### Basic Matching
74
-
75
- ```python
76
- def handle_command(command: str):
77
- match command:
78
- case "start":
79
- start_process()
80
- case "stop":
81
- stop_process()
82
- case "status":
83
- return get_status()
84
- case _:
85
- raise ValueError("Unknown command")
86
- ```
87
-
88
- ### Matching with Values
89
-
90
- ```python
91
- def handle_http_status(status: int):
92
- match status:
93
- case 200:
94
- return "OK"
95
- case 404:
96
- return "Not Found"
97
- case 500 | 502 | 503:
98
- return "Server Error"
99
- case _:
100
- return "Unknown"
101
- ```
102
-
103
- ### Structural Pattern Matching
104
-
105
- ```python
106
- def process_point(point):
107
- match point:
108
- case (0, 0):
109
- return "Origin"
110
- case (x, 0):
111
- return f"On X-axis at {x}"
112
- case (0, y):
113
- return f"On Y-axis at {y}"
114
- case (x, y):
115
- return f"At ({x}, {y})"
116
- ```
117
-
118
- ## Async/Await
119
-
120
- ### Async Functions
121
-
122
- ```python
123
- async def fetch_data(url: str) -> dict:
124
- """Async function"""
125
- async with httpx.AsyncClient() as client:
126
- response = await client.get(url)
127
- return response.json()
128
-
129
- # Call async function
130
- data = await fetch_data("https://api.example.com")
131
- ```
132
-
133
- ### Concurrent Execution
134
-
135
- ```python
136
- import asyncio
137
-
138
- async def process_all(urls: list[str]):
139
- """Process multiple URLs concurrently"""
140
- tasks = [fetch_data(url) for url in urls]
141
- results = await asyncio.gather(*tasks)
142
- return results
143
- ```
144
-
145
- ### Async Context Managers
146
-
147
- ```python
148
- class AsyncDatabase:
149
- async def __aenter__(self):
150
- await self.connect()
151
- return self
152
-
153
- async def __aexit__(self, *args):
154
- await self.disconnect()
155
-
156
- async with AsyncDatabase() as db:
157
- await db.query(...)
158
- ```
159
-
160
- ## Dataclasses and attrs
161
-
162
- ```python
163
- from dataclasses import dataclass
164
-
165
- @dataclass(frozen=True)
166
- class Point:
167
- x: float
168
- y: float
169
-
170
- def distance_from_origin(self) -> float:
171
- return (self.x ** 2 + self.y ** 2) ** 0.5
172
- ```
173
-
174
- ## Walrus Operator
175
-
176
- ```python
177
- # Assign and use in one expression
178
- if (n := len(items)) > 10:
179
- print(f"Too many items: {n}")
180
-
181
- # In comprehensions
182
- results = [y for x in items if (y := process(x)) is not None]
183
- ```
184
-
185
- ## Modern String Formatting
186
-
187
- ```python
188
- name = "Alice"
189
- age = 30
190
-
191
- # f-strings
192
- message = f"Hello {name}, you are {age} years old"
193
-
194
- # f-strings with expressions
195
- message = f"In 5 years you'll be {age + 5}"
196
-
197
- # Debug f-strings (Python 3.8+)
198
- print(f"{name=}") # name='Alice'
199
- ```
200
-
201
- See references/ for advanced typing, async patterns, and pattern matching.