@mytechtoday/augment-extensions 0.2.0 → 0.5.0
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.
- package/README.md +614 -39
- package/augment-extensions/coding-standards/bash/README.md +196 -0
- package/augment-extensions/coding-standards/bash/module.json +163 -0
- package/augment-extensions/coding-standards/bash/rules/naming-conventions.md +336 -0
- package/augment-extensions/coding-standards/bash/rules/universal-standards.md +289 -0
- package/augment-extensions/coding-standards/css/README.md +40 -0
- package/augment-extensions/coding-standards/css/examples/css-examples.css +550 -0
- package/augment-extensions/coding-standards/css/module.json +44 -0
- package/augment-extensions/coding-standards/css/rules/css-modern-features.md +448 -0
- package/augment-extensions/coding-standards/css/rules/css-standards.md +492 -0
- package/augment-extensions/coding-standards/html/README.md +40 -0
- package/augment-extensions/coding-standards/html/examples/html-examples.html +267 -0
- package/augment-extensions/coding-standards/html/examples/responsive-layout.html +505 -0
- package/augment-extensions/coding-standards/html/module.json +44 -0
- package/augment-extensions/coding-standards/html/rules/html-standards.md +349 -0
- package/augment-extensions/coding-standards/html-css-js/README.md +194 -0
- package/augment-extensions/coding-standards/html-css-js/examples/async-examples.js +487 -0
- package/augment-extensions/coding-standards/html-css-js/examples/css-examples.css +550 -0
- package/augment-extensions/coding-standards/html-css-js/examples/dom-examples.js +667 -0
- package/augment-extensions/coding-standards/html-css-js/examples/html-examples.html +267 -0
- package/augment-extensions/coding-standards/html-css-js/examples/javascript-examples.js +612 -0
- package/augment-extensions/coding-standards/html-css-js/examples/responsive-layout.html +505 -0
- package/augment-extensions/coding-standards/html-css-js/module.json +48 -0
- package/augment-extensions/coding-standards/html-css-js/rules/async-patterns.md +515 -0
- package/augment-extensions/coding-standards/html-css-js/rules/css-modern-features.md +448 -0
- package/augment-extensions/coding-standards/html-css-js/rules/css-standards.md +492 -0
- package/augment-extensions/coding-standards/html-css-js/rules/dom-manipulation.md +439 -0
- package/augment-extensions/coding-standards/html-css-js/rules/html-standards.md +349 -0
- package/augment-extensions/coding-standards/html-css-js/rules/javascript-standards.md +486 -0
- package/augment-extensions/coding-standards/html-css-js/rules/performance.md +463 -0
- package/augment-extensions/coding-standards/html-css-js/rules/tooling.md +543 -0
- package/augment-extensions/coding-standards/js/README.md +46 -0
- package/augment-extensions/coding-standards/js/examples/async-examples.js +487 -0
- package/augment-extensions/coding-standards/js/examples/dom-examples.js +667 -0
- package/augment-extensions/coding-standards/js/examples/javascript-examples.js +612 -0
- package/augment-extensions/coding-standards/js/module.json +49 -0
- package/augment-extensions/coding-standards/js/rules/async-patterns.md +515 -0
- package/augment-extensions/coding-standards/js/rules/dom-manipulation.md +439 -0
- package/augment-extensions/coding-standards/js/rules/javascript-standards.md +486 -0
- package/augment-extensions/coding-standards/js/rules/performance.md +463 -0
- package/augment-extensions/coding-standards/js/rules/tooling.md +543 -0
- package/augment-extensions/coding-standards/php/README.md +248 -0
- package/augment-extensions/coding-standards/php/examples/api-endpoint-example.php +204 -0
- package/augment-extensions/coding-standards/php/examples/cli-command-example.php +206 -0
- package/augment-extensions/coding-standards/php/examples/legacy-refactoring-example.php +234 -0
- package/augment-extensions/coding-standards/php/examples/web-application-example.php +211 -0
- package/augment-extensions/coding-standards/php/examples/woocommerce-extension-example.php +215 -0
- package/augment-extensions/coding-standards/php/examples/wordpress-plugin-example.php +189 -0
- package/augment-extensions/coding-standards/php/module.json +166 -0
- package/augment-extensions/coding-standards/php/rules/api-development.md +480 -0
- package/augment-extensions/coding-standards/php/rules/category-configuration.md +332 -0
- package/augment-extensions/coding-standards/php/rules/cli-tools.md +472 -0
- package/augment-extensions/coding-standards/php/rules/cms-integration.md +561 -0
- package/augment-extensions/coding-standards/php/rules/code-quality.md +402 -0
- package/augment-extensions/coding-standards/php/rules/documentation.md +425 -0
- package/augment-extensions/coding-standards/php/rules/ecommerce.md +627 -0
- package/augment-extensions/coding-standards/php/rules/error-handling.md +336 -0
- package/augment-extensions/coding-standards/php/rules/legacy-migration.md +677 -0
- package/augment-extensions/coding-standards/php/rules/naming-conventions.md +279 -0
- package/augment-extensions/coding-standards/php/rules/performance.md +392 -0
- package/augment-extensions/coding-standards/php/rules/psr-standards.md +186 -0
- package/augment-extensions/coding-standards/php/rules/security.md +358 -0
- package/augment-extensions/coding-standards/php/rules/testing.md +403 -0
- package/augment-extensions/coding-standards/php/rules/type-declarations.md +331 -0
- package/augment-extensions/coding-standards/php/rules/web-applications.md +426 -0
- package/augment-extensions/coding-standards/powershell/README.md +154 -0
- package/augment-extensions/coding-standards/powershell/examples/admin-example.ps1 +272 -0
- package/augment-extensions/coding-standards/powershell/examples/automation-example.ps1 +173 -0
- package/augment-extensions/coding-standards/powershell/examples/cloud-example.ps1 +243 -0
- package/augment-extensions/coding-standards/powershell/examples/cross-platform-example.ps1 +297 -0
- package/augment-extensions/coding-standards/powershell/examples/dsc-example.ps1 +224 -0
- package/augment-extensions/coding-standards/powershell/examples/legacy-migration-example.ps1 +340 -0
- package/augment-extensions/coding-standards/powershell/examples/module-example.psm1 +255 -0
- package/augment-extensions/coding-standards/powershell/module.json +165 -0
- package/augment-extensions/coding-standards/powershell/rules/administrative-tools.md +439 -0
- package/augment-extensions/coding-standards/powershell/rules/automation-scripts.md +240 -0
- package/augment-extensions/coding-standards/powershell/rules/cloud-orchestration.md +384 -0
- package/augment-extensions/coding-standards/powershell/rules/configuration-schema.md +383 -0
- package/augment-extensions/coding-standards/powershell/rules/cross-platform-scripts.md +482 -0
- package/augment-extensions/coding-standards/powershell/rules/dsc-configurations.md +296 -0
- package/augment-extensions/coding-standards/powershell/rules/error-handling.md +314 -0
- package/augment-extensions/coding-standards/powershell/rules/legacy-migrations.md +466 -0
- package/augment-extensions/coding-standards/powershell/rules/modules-functions.md +244 -0
- package/augment-extensions/coding-standards/powershell/rules/naming-conventions.md +266 -0
- package/augment-extensions/coding-standards/powershell/rules/performance-optimization.md +209 -0
- package/augment-extensions/coding-standards/powershell/rules/security-practices.md +314 -0
- package/augment-extensions/coding-standards/powershell/rules/testing-guidelines.md +268 -0
- package/augment-extensions/coding-standards/powershell/rules/universal-standards.md +197 -0
- package/augment-extensions/coding-standards/python/README.md +12 -8
- package/augment-extensions/coding-standards/python/examples/best-practices.py +373 -0
- package/augment-extensions/coding-standards/python/module.json +8 -4
- package/augment-extensions/coding-standards/python/rules/async-patterns.md +884 -0
- package/augment-extensions/coding-standards/python/rules/documentation.md +831 -0
- package/augment-extensions/coding-standards/python/rules/error-handling.md +855 -68
- package/augment-extensions/coding-standards/python/rules/testing.md +409 -0
- package/augment-extensions/coding-standards/python/rules/tooling.md +446 -0
- package/augment-extensions/coding-standards/python/rules/type-hints.md +115 -50
- package/augment-extensions/collections/html-css-js/README.md +82 -0
- package/augment-extensions/collections/html-css-js/collection.json +41 -0
- package/augment-extensions/domain-rules/database/README.md +161 -0
- package/augment-extensions/domain-rules/database/examples/flat-database-example.md +793 -0
- package/augment-extensions/domain-rules/database/examples/hybrid-database-example.md +1132 -0
- package/augment-extensions/domain-rules/database/examples/nosql-document-example.md +868 -0
- package/augment-extensions/domain-rules/database/examples/nosql-graph-example.md +805 -0
- package/augment-extensions/domain-rules/database/examples/relational-schema-example.md +621 -0
- package/augment-extensions/domain-rules/database/examples/vector-database-example.md +965 -0
- package/augment-extensions/domain-rules/database/module.json +28 -0
- package/augment-extensions/domain-rules/database/rules/flat-databases.md +624 -0
- package/augment-extensions/domain-rules/database/rules/nosql-databases.md +588 -0
- package/augment-extensions/domain-rules/database/rules/nosql-document-stores.md +856 -0
- package/augment-extensions/domain-rules/database/rules/nosql-graph-databases.md +778 -0
- package/augment-extensions/domain-rules/database/rules/nosql-key-value-stores.md +963 -0
- package/augment-extensions/domain-rules/database/rules/performance-optimization.md +1076 -0
- package/augment-extensions/domain-rules/database/rules/relational-databases.md +697 -0
- package/augment-extensions/domain-rules/database/rules/relational-indexing.md +671 -0
- package/augment-extensions/domain-rules/database/rules/relational-query-optimization.md +607 -0
- package/augment-extensions/domain-rules/database/rules/relational-schema-design.md +907 -0
- package/augment-extensions/domain-rules/database/rules/relational-transactions.md +783 -0
- package/augment-extensions/domain-rules/database/rules/security-standards.md +980 -0
- package/augment-extensions/domain-rules/database/rules/universal-best-practices.md +485 -0
- package/augment-extensions/domain-rules/database/rules/vector-databases.md +521 -0
- package/augment-extensions/domain-rules/database/rules/vector-embeddings.md +858 -0
- package/augment-extensions/domain-rules/database/rules/vector-indexing.md +934 -0
- package/augment-extensions/domain-rules/design/color/themes/catppuccin-latte/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/catppuccin-latte/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/catppuccin-mocha/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/catppuccin-mocha/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/dracula/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/dracula/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/gruvbox-dark/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/gruvbox-dark/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/gruvbox-light/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/gruvbox-light/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/high-contrast/README.md +27 -0
- package/augment-extensions/domain-rules/design/color/themes/high-contrast/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/monokai/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/monokai/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/nord/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/nord/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/one-dark/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/one-dark/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/one-light/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/one-light/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/solarized-dark/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/solarized-dark/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/solarized-light/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/solarized-light/module.json +26 -0
- package/augment-extensions/domain-rules/design/color/themes/tokyo-night/README.md +23 -0
- package/augment-extensions/domain-rules/design/color/themes/tokyo-night/module.json +26 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/README.md +136 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/SCHEMA-VALIDATION-REPORT.md +216 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/examples/brand-kit-example.yaml +292 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/examples/campaign-brief-example.yaml +389 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/examples/content-calendar-example.yaml +643 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/examples/email-newsletter-example.md +376 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/examples/landing-page-example.md +934 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/examples/ppc-ad-copy-example.md +301 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/examples/seo-blog-post-example.md +347 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/examples/social-media-campaign-example.md +606 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/module.json +50 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/affiliate-influencer-marketing.md +593 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/asset-management.md +418 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/brand-consistency.md +210 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/content-marketing.md +337 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/conversion-optimization.md +455 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/direct-sales.md +499 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/email-marketing.md +439 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/legal-compliance.md +227 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/ppc-advertising.md +569 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/seo-optimization.md +470 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/social-media-marketing.md +414 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/rules/universal-marketing.md +177 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/schemas/asset-inventory.schema.json +247 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/schemas/brand-kit.schema.json +326 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/schemas/campaign-brief.schema.json +342 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/schemas/color-palette.schema.json +223 -0
- package/augment-extensions/domain-rules/marketing-standards/seo-sales-marketing/schemas/content-template.schema.json +383 -0
- package/augment-extensions/domain-rules/mcp/README.md +150 -0
- package/augment-extensions/domain-rules/mcp/examples/compressed-example.md +522 -0
- package/augment-extensions/domain-rules/mcp/examples/graph-augmented-example.md +520 -0
- package/augment-extensions/domain-rules/mcp/examples/hybrid-example.md +570 -0
- package/augment-extensions/domain-rules/mcp/examples/state-based-example.md +427 -0
- package/augment-extensions/domain-rules/mcp/examples/token-based-example.md +435 -0
- package/augment-extensions/domain-rules/mcp/examples/vector-based-example.md +502 -0
- package/augment-extensions/domain-rules/mcp/module.json +49 -0
- package/augment-extensions/domain-rules/mcp/rules/compressed-mcp.md +595 -0
- package/augment-extensions/domain-rules/mcp/rules/configuration.md +345 -0
- package/augment-extensions/domain-rules/mcp/rules/graph-augmented-mcp.md +687 -0
- package/augment-extensions/domain-rules/mcp/rules/hybrid-mcp.md +636 -0
- package/augment-extensions/domain-rules/mcp/rules/state-based-mcp.md +484 -0
- package/augment-extensions/domain-rules/mcp/rules/testing-validation.md +360 -0
- package/augment-extensions/domain-rules/mcp/rules/token-based-mcp.md +393 -0
- package/augment-extensions/domain-rules/mcp/rules/universal-rules.md +194 -0
- package/augment-extensions/domain-rules/mcp/rules/vector-based-mcp.md +625 -0
- package/augment-extensions/workflows/beads/module.json +4 -3
- package/augment-extensions/workflows/beads-integration/IMPLEMENTATION-STATUS.md +145 -0
- package/augment-extensions/workflows/beads-integration/README.md +143 -0
- package/augment-extensions/workflows/beads-integration/config/defaults.json +32 -0
- package/augment-extensions/workflows/beads-integration/config/schema.json +140 -0
- package/augment-extensions/workflows/beads-integration/examples/basic-task-generation.md +293 -0
- package/augment-extensions/workflows/beads-integration/module.json +75 -0
- package/augment-extensions/workflows/beads-integration/rules/core-rules.md +219 -0
- package/augment-extensions/workflows/beads-integration/rules/effectiveness-standards.md +256 -0
- package/augment-extensions/workflows/beads-integration/rules/task-generation.md +607 -0
- package/augment-extensions/workflows/database/README.md +195 -0
- package/augment-extensions/workflows/database/ai-prompt-testing.md +295 -0
- package/augment-extensions/workflows/database/examples/migration-example.md +498 -0
- package/augment-extensions/workflows/database/examples/optimization-example.md +496 -0
- package/augment-extensions/workflows/database/examples/schema-design-example.md +444 -0
- package/augment-extensions/workflows/database/module.json +42 -0
- package/augment-extensions/workflows/database/rules/data-migration.md +249 -0
- package/augment-extensions/workflows/database/rules/documentation-standards.md +339 -0
- package/augment-extensions/workflows/database/rules/migration-workflow.md +352 -0
- package/augment-extensions/workflows/database/rules/optimization-workflow.md +435 -0
- package/augment-extensions/workflows/database/rules/schema-design-workflow.md +535 -0
- package/augment-extensions/workflows/database/rules/testing-patterns.md +305 -0
- package/augment-extensions/workflows/database/rules/workflow.md +458 -0
- package/augment-extensions/workflows/openspec/module.json +4 -3
- package/augment-extensions/writing-standards/screenplay/README.md +300 -0
- package/augment-extensions/writing-standards/screenplay/_templates/README.md +121 -0
- package/augment-extensions/writing-standards/screenplay/_templates/genre-template.md +153 -0
- package/augment-extensions/writing-standards/screenplay/_templates/style-template.md +243 -0
- package/augment-extensions/writing-standards/screenplay/_templates/theme-template.md +213 -0
- package/augment-extensions/writing-standards/screenplay/examples/aaa-hollywood-scene.fountain +164 -0
- package/augment-extensions/writing-standards/screenplay/examples/beat-sheet-example.yaml +95 -0
- package/augment-extensions/writing-standards/screenplay/examples/character-profile-example.yaml +116 -0
- package/augment-extensions/writing-standards/screenplay/examples/commercial-30sec.fountain +151 -0
- package/augment-extensions/writing-standards/screenplay/examples/independent-monologue.fountain +67 -0
- package/augment-extensions/writing-standards/screenplay/examples/news-segment.fountain +142 -0
- package/augment-extensions/writing-standards/screenplay/examples/plot-outline-example.yaml +184 -0
- package/augment-extensions/writing-standards/screenplay/examples/tv-episode-teaser.fountain +204 -0
- package/augment-extensions/writing-standards/screenplay/genres/README.md +181 -0
- package/augment-extensions/writing-standards/screenplay/genres/examples/.gitkeep +2 -0
- package/augment-extensions/writing-standards/screenplay/genres/module.json +70 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/.gitkeep +2 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/action.md +399 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/adventure.md +407 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/animation.md +293 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/biographical.md +293 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/comedy.md +401 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/documentary.md +293 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/drama.md +409 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/fantasy.md +293 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/historical.md +293 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/horror.md +268 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/musical.md +294 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/mystery.md +293 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/noir.md +294 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/romance.md +293 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/sci-fi.md +289 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/superhero.md +293 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/thriller.md +294 -0
- package/augment-extensions/writing-standards/screenplay/genres/rules/western.md +293 -0
- package/augment-extensions/writing-standards/screenplay/module.json +124 -0
- package/augment-extensions/writing-standards/screenplay/rules/aaa-hollywood-films.md +339 -0
- package/augment-extensions/writing-standards/screenplay/rules/ai-integration-testing.md +329 -0
- package/augment-extensions/writing-standards/screenplay/rules/character-development.md +169 -0
- package/augment-extensions/writing-standards/screenplay/rules/commercials.md +437 -0
- package/augment-extensions/writing-standards/screenplay/rules/dialogue-writing.md +263 -0
- package/augment-extensions/writing-standards/screenplay/rules/diversity-inclusion.md +261 -0
- package/augment-extensions/writing-standards/screenplay/rules/examples-guide.md +315 -0
- package/augment-extensions/writing-standards/screenplay/rules/formatting-validation.md +413 -0
- package/augment-extensions/writing-standards/screenplay/rules/fountain-format.md +372 -0
- package/augment-extensions/writing-standards/screenplay/rules/independent-films.md +374 -0
- package/augment-extensions/writing-standards/screenplay/rules/live-tv-productions.md +443 -0
- package/augment-extensions/writing-standards/screenplay/rules/narrative-structures.md +207 -0
- package/augment-extensions/writing-standards/screenplay/rules/news-broadcasts.md +444 -0
- package/augment-extensions/writing-standards/screenplay/rules/pacing-timing.md +331 -0
- package/augment-extensions/writing-standards/screenplay/rules/quality-review-checklist.md +334 -0
- package/augment-extensions/writing-standards/screenplay/rules/quick-reference.md +299 -0
- package/augment-extensions/writing-standards/screenplay/rules/screen-continuity.md +263 -0
- package/augment-extensions/writing-standards/screenplay/rules/streaming-content.md +412 -0
- package/augment-extensions/writing-standards/screenplay/rules/trope-management.md +370 -0
- package/augment-extensions/writing-standards/screenplay/rules/tv-series.md +374 -0
- package/augment-extensions/writing-standards/screenplay/rules/universal-formatting.md +339 -0
- package/augment-extensions/writing-standards/screenplay/rules/vscode-integration.md +277 -0
- package/augment-extensions/writing-standards/screenplay/rules/web-content.md +393 -0
- package/augment-extensions/writing-standards/screenplay/schemas/beat-sheet.json +332 -0
- package/augment-extensions/writing-standards/screenplay/schemas/character-profile.json +247 -0
- package/augment-extensions/writing-standards/screenplay/schemas/feature-selection.json +200 -0
- package/augment-extensions/writing-standards/screenplay/schemas/plot-outline.json +233 -0
- package/augment-extensions/writing-standards/screenplay/schemas/screenplay-config.json +245 -0
- package/augment-extensions/writing-standards/screenplay/schemas/trope-inventory.json +221 -0
- package/augment-extensions/writing-standards/screenplay/styles/README.md +159 -0
- package/augment-extensions/writing-standards/screenplay/styles/examples/.gitkeep +2 -0
- package/augment-extensions/writing-standards/screenplay/styles/examples/style-applications.md +1449 -0
- package/augment-extensions/writing-standards/screenplay/styles/module.json +64 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/.gitkeep +2 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/dialogue-centric.md +520 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/ensemble.md +499 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/epic.md +497 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/experimental.md +492 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/flashback.md +509 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/linear.md +490 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/minimalist.md +499 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/non-linear.md +501 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/poetic.md +499 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/realistic.md +498 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/satirical.md +499 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/surreal.md +508 -0
- package/augment-extensions/writing-standards/screenplay/styles/rules/voice-over.md +500 -0
- package/augment-extensions/writing-standards/screenplay/themes/README.md +158 -0
- package/augment-extensions/writing-standards/screenplay/themes/examples/.gitkeep +2 -0
- package/augment-extensions/writing-standards/screenplay/themes/examples/common-mistakes-and-fixes.md +643 -0
- package/augment-extensions/writing-standards/screenplay/themes/examples/complete-scene-example.md +311 -0
- package/augment-extensions/writing-standards/screenplay/themes/examples/individual-theme-examples.md +562 -0
- package/augment-extensions/writing-standards/screenplay/themes/examples/multi-theme-weaving.md +538 -0
- package/augment-extensions/writing-standards/screenplay/themes/examples/theme-application-guide.md +432 -0
- package/augment-extensions/writing-standards/screenplay/themes/examples/theme-integration-across-acts.md +637 -0
- package/augment-extensions/writing-standards/screenplay/themes/module.json +66 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/.gitkeep +2 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/ambition.md +458 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/betrayal.md +490 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/environment.md +458 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/fate.md +459 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/friendship.md +491 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/growth.md +491 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/identity.md +490 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/isolation.md +464 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/justice.md +461 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/love.md +489 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/power.md +494 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/redemption.md +483 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/revenge.md +489 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/survival.md +496 -0
- package/augment-extensions/writing-standards/screenplay/themes/rules/technology.md +463 -0
- package/cli/MODULES.md +302 -0
- package/cli/dist/cli.js +168 -10
- package/cli/dist/cli.js.map +1 -1
- package/cli/dist/commands/catalog.d.ts +13 -0
- package/cli/dist/commands/catalog.d.ts.map +1 -0
- package/cli/dist/commands/catalog.js +104 -0
- package/cli/dist/commands/catalog.js.map +1 -0
- package/cli/dist/commands/gui.d.ts +6 -0
- package/cli/dist/commands/gui.d.ts.map +1 -0
- package/cli/dist/commands/gui.js +211 -0
- package/cli/dist/commands/gui.js.map +1 -0
- package/cli/dist/commands/init.d.ts.map +1 -1
- package/cli/dist/commands/init.js +12 -0
- package/cli/dist/commands/init.js.map +1 -1
- package/cli/dist/commands/install-rules.d.ts +14 -0
- package/cli/dist/commands/install-rules.d.ts.map +1 -0
- package/cli/dist/commands/install-rules.js +127 -0
- package/cli/dist/commands/install-rules.js.map +1 -0
- package/cli/dist/commands/link.d.ts.map +1 -1
- package/cli/dist/commands/link.js +9 -11
- package/cli/dist/commands/link.js.map +1 -1
- package/cli/dist/commands/list.d.ts.map +1 -1
- package/cli/dist/commands/list.js +11 -28
- package/cli/dist/commands/list.js.map +1 -1
- package/cli/dist/commands/mcp.d.ts +48 -0
- package/cli/dist/commands/mcp.d.ts.map +1 -0
- package/cli/dist/commands/mcp.js +229 -0
- package/cli/dist/commands/mcp.js.map +1 -0
- package/cli/dist/commands/self-remove.d.ts +7 -0
- package/cli/dist/commands/self-remove.d.ts.map +1 -0
- package/cli/dist/commands/self-remove.js +179 -0
- package/cli/dist/commands/self-remove.js.map +1 -0
- package/cli/dist/commands/show.d.ts +19 -0
- package/cli/dist/commands/show.d.ts.map +1 -1
- package/cli/dist/commands/show.js +478 -63
- package/cli/dist/commands/show.js.map +1 -1
- package/cli/dist/commands/skill.d.ts +67 -0
- package/cli/dist/commands/skill.d.ts.map +1 -0
- package/cli/dist/commands/skill.js +513 -0
- package/cli/dist/commands/skill.js.map +1 -0
- package/cli/dist/commands/unlink.d.ts +6 -0
- package/cli/dist/commands/unlink.d.ts.map +1 -0
- package/cli/dist/commands/unlink.js +115 -0
- package/cli/dist/commands/unlink.js.map +1 -0
- package/cli/dist/commands/validate.d.ts +6 -0
- package/cli/dist/commands/validate.d.ts.map +1 -0
- package/cli/dist/commands/validate.js +159 -0
- package/cli/dist/commands/validate.js.map +1 -0
- package/cli/dist/types/gui.d.ts +62 -0
- package/cli/dist/types/gui.d.ts.map +1 -0
- package/cli/dist/types/gui.js +30 -0
- package/cli/dist/types/gui.js.map +1 -0
- package/cli/dist/utils/catalog-sync.d.ts +22 -0
- package/cli/dist/utils/catalog-sync.d.ts.map +1 -0
- package/cli/dist/utils/catalog-sync.js +157 -0
- package/cli/dist/utils/catalog-sync.js.map +1 -0
- package/cli/dist/utils/character-count.d.ts +56 -0
- package/cli/dist/utils/character-count.d.ts.map +1 -0
- package/cli/dist/utils/character-count.js +190 -0
- package/cli/dist/utils/character-count.js.map +1 -0
- package/cli/dist/utils/documentation-validator.d.ts +18 -0
- package/cli/dist/utils/documentation-validator.d.ts.map +1 -0
- package/cli/dist/utils/documentation-validator.js +233 -0
- package/cli/dist/utils/documentation-validator.js.map +1 -0
- package/cli/dist/utils/gui-helpers.d.ts +23 -0
- package/cli/dist/utils/gui-helpers.d.ts.map +1 -0
- package/cli/dist/utils/gui-helpers.js +159 -0
- package/cli/dist/utils/gui-helpers.js.map +1 -0
- package/cli/dist/utils/install-rules.d.ts +32 -0
- package/cli/dist/utils/install-rules.d.ts.map +1 -0
- package/cli/dist/utils/install-rules.js +375 -0
- package/cli/dist/utils/install-rules.js.map +1 -0
- package/cli/dist/utils/mcp-integration.d.ts +70 -0
- package/cli/dist/utils/mcp-integration.d.ts.map +1 -0
- package/cli/dist/utils/mcp-integration.js +292 -0
- package/cli/dist/utils/mcp-integration.js.map +1 -0
- package/cli/dist/utils/module-system.d.ts +232 -0
- package/cli/dist/utils/module-system.d.ts.map +1 -0
- package/cli/dist/utils/module-system.js +900 -0
- package/cli/dist/utils/module-system.js.map +1 -0
- package/cli/dist/utils/modules-catalog.d.ts +33 -0
- package/cli/dist/utils/modules-catalog.d.ts.map +1 -0
- package/cli/dist/utils/modules-catalog.js +163 -0
- package/cli/dist/utils/modules-catalog.js.map +1 -0
- package/cli/dist/utils/rule-install-hooks.d.ts +19 -0
- package/cli/dist/utils/rule-install-hooks.d.ts.map +1 -0
- package/cli/dist/utils/rule-install-hooks.js +224 -0
- package/cli/dist/utils/rule-install-hooks.js.map +1 -0
- package/cli/dist/utils/skill-system.d.ts +95 -0
- package/cli/dist/utils/skill-system.d.ts.map +1 -0
- package/cli/dist/utils/skill-system.js +313 -0
- package/cli/dist/utils/skill-system.js.map +1 -0
- package/modules.md +559 -105
- package/package.json +17 -6
|
@@ -0,0 +1,884 @@
|
|
|
1
|
+
# Python Async Patterns
|
|
2
|
+
|
|
3
|
+
Comprehensive guide to asynchronous programming in Python using async/await, asyncio, and related patterns.
|
|
4
|
+
|
|
5
|
+
## Async/Await Basics
|
|
6
|
+
|
|
7
|
+
### Defining Async Functions
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
import asyncio
|
|
11
|
+
from typing import List
|
|
12
|
+
|
|
13
|
+
# Async function definition
|
|
14
|
+
async def fetch_data(url: str) -> dict:
|
|
15
|
+
"""Fetch data from URL asynchronously.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
url: URL to fetch from
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
Fetched data as dictionary
|
|
22
|
+
"""
|
|
23
|
+
# Simulate async I/O operation
|
|
24
|
+
await asyncio.sleep(1)
|
|
25
|
+
return {"url": url, "data": "..."}
|
|
26
|
+
|
|
27
|
+
# Calling async functions
|
|
28
|
+
async def main():
|
|
29
|
+
# Must use 'await' to call async functions
|
|
30
|
+
result = await fetch_data("https://api.example.com")
|
|
31
|
+
print(result)
|
|
32
|
+
|
|
33
|
+
# Running async code
|
|
34
|
+
if __name__ == "__main__":
|
|
35
|
+
# Python 3.7+
|
|
36
|
+
asyncio.run(main())
|
|
37
|
+
|
|
38
|
+
# Python 3.6 (older style)
|
|
39
|
+
# loop = asyncio.get_event_loop()
|
|
40
|
+
# loop.run_until_complete(main())
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Async vs Sync
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
# Synchronous - Blocks execution
|
|
47
|
+
def sync_fetch(url: str) -> dict:
|
|
48
|
+
time.sleep(1) # Blocks the entire thread
|
|
49
|
+
return {"url": url}
|
|
50
|
+
|
|
51
|
+
# Asynchronous - Allows other tasks to run
|
|
52
|
+
async def async_fetch(url: str) -> dict:
|
|
53
|
+
await asyncio.sleep(1) # Yields control to event loop
|
|
54
|
+
return {"url": url}
|
|
55
|
+
|
|
56
|
+
# Synchronous execution - Takes 3 seconds
|
|
57
|
+
def sync_main():
|
|
58
|
+
results = []
|
|
59
|
+
for url in ["url1", "url2", "url3"]:
|
|
60
|
+
results.append(sync_fetch(url)) # Each takes 1 second
|
|
61
|
+
return results
|
|
62
|
+
|
|
63
|
+
# Asynchronous execution - Takes 1 second total
|
|
64
|
+
async def async_main():
|
|
65
|
+
tasks = [async_fetch(url) for url in ["url1", "url2", "url3"]]
|
|
66
|
+
results = await asyncio.gather(*tasks) # All run concurrently
|
|
67
|
+
return results
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Running Async Tasks
|
|
71
|
+
|
|
72
|
+
### asyncio.gather() - Run Multiple Tasks
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
# Run multiple tasks concurrently
|
|
76
|
+
async def fetch_all_data():
|
|
77
|
+
# Create multiple tasks
|
|
78
|
+
task1 = fetch_data("https://api1.example.com")
|
|
79
|
+
task2 = fetch_data("https://api2.example.com")
|
|
80
|
+
task3 = fetch_data("https://api3.example.com")
|
|
81
|
+
|
|
82
|
+
# Wait for all tasks to complete
|
|
83
|
+
results = await asyncio.gather(task1, task2, task3)
|
|
84
|
+
return results
|
|
85
|
+
|
|
86
|
+
# With list comprehension
|
|
87
|
+
async def fetch_multiple_urls(urls: List[str]):
|
|
88
|
+
tasks = [fetch_data(url) for url in urls]
|
|
89
|
+
results = await asyncio.gather(*tasks)
|
|
90
|
+
return results
|
|
91
|
+
|
|
92
|
+
# Handle exceptions in gather
|
|
93
|
+
async def fetch_with_error_handling():
|
|
94
|
+
tasks = [fetch_data(url) for url in urls]
|
|
95
|
+
|
|
96
|
+
# return_exceptions=True: Return exceptions instead of raising
|
|
97
|
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
98
|
+
|
|
99
|
+
# Process results and exceptions
|
|
100
|
+
for i, result in enumerate(results):
|
|
101
|
+
if isinstance(result, Exception):
|
|
102
|
+
logger.error(f"Task {i} failed: {result}")
|
|
103
|
+
else:
|
|
104
|
+
process_result(result)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### asyncio.create_task() - Create Background Tasks
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
# Create tasks that run in background
|
|
111
|
+
async def background_task(name: str):
|
|
112
|
+
while True:
|
|
113
|
+
print(f"{name} running")
|
|
114
|
+
await asyncio.sleep(1)
|
|
115
|
+
|
|
116
|
+
async def main():
|
|
117
|
+
# Create background tasks
|
|
118
|
+
task1 = asyncio.create_task(background_task("Task 1"))
|
|
119
|
+
task2 = asyncio.create_task(background_task("Task 2"))
|
|
120
|
+
|
|
121
|
+
# Do other work
|
|
122
|
+
await asyncio.sleep(5)
|
|
123
|
+
|
|
124
|
+
# Cancel background tasks
|
|
125
|
+
task1.cancel()
|
|
126
|
+
task2.cancel()
|
|
127
|
+
|
|
128
|
+
# Wait for cancellation to complete
|
|
129
|
+
await asyncio.gather(task1, task2, return_exceptions=True)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### asyncio.wait() - Advanced Task Management
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
# Wait for tasks with more control
|
|
136
|
+
async def wait_for_tasks():
|
|
137
|
+
tasks = [fetch_data(url) for url in urls]
|
|
138
|
+
|
|
139
|
+
# Wait for all tasks
|
|
140
|
+
done, pending = await asyncio.wait(tasks)
|
|
141
|
+
|
|
142
|
+
# Wait for first task to complete
|
|
143
|
+
done, pending = await asyncio.wait(
|
|
144
|
+
tasks,
|
|
145
|
+
return_when=asyncio.FIRST_COMPLETED
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Wait with timeout
|
|
149
|
+
done, pending = await asyncio.wait(
|
|
150
|
+
tasks,
|
|
151
|
+
timeout=5.0
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# Cancel pending tasks
|
|
155
|
+
for task in pending:
|
|
156
|
+
task.cancel()
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Async Context Managers
|
|
160
|
+
|
|
161
|
+
Async context managers use `async with` for asynchronous resource management.
|
|
162
|
+
|
|
163
|
+
### Defining Async Context Managers
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from typing import AsyncGenerator
|
|
167
|
+
|
|
168
|
+
# Class-based async context manager
|
|
169
|
+
class AsyncDatabaseConnection:
|
|
170
|
+
"""Async context manager for database connections."""
|
|
171
|
+
|
|
172
|
+
def __init__(self, db_url: str):
|
|
173
|
+
self.db_url = db_url
|
|
174
|
+
self.conn = None
|
|
175
|
+
|
|
176
|
+
async def __aenter__(self):
|
|
177
|
+
"""Establish connection when entering context."""
|
|
178
|
+
self.conn = await async_connect(self.db_url)
|
|
179
|
+
logger.info(f"Connected to {self.db_url}")
|
|
180
|
+
return self.conn
|
|
181
|
+
|
|
182
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
183
|
+
"""Close connection when exiting context."""
|
|
184
|
+
if self.conn is not None:
|
|
185
|
+
await self.conn.close()
|
|
186
|
+
logger.info(f"Closed connection to {self.db_url}")
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
# Usage
|
|
190
|
+
async def fetch_users():
|
|
191
|
+
async with AsyncDatabaseConnection("postgresql://...") as conn:
|
|
192
|
+
return await conn.fetch("SELECT * FROM users")
|
|
193
|
+
|
|
194
|
+
# Generator-based async context manager
|
|
195
|
+
from contextlib import asynccontextmanager
|
|
196
|
+
|
|
197
|
+
@asynccontextmanager
|
|
198
|
+
async def async_database_connection(
|
|
199
|
+
db_url: str
|
|
200
|
+
) -> AsyncGenerator[AsyncConnection, None]:
|
|
201
|
+
"""Async context manager for database connections.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
db_url: Database connection URL
|
|
205
|
+
|
|
206
|
+
Yields:
|
|
207
|
+
Active database connection
|
|
208
|
+
"""
|
|
209
|
+
conn = await async_connect(db_url)
|
|
210
|
+
try:
|
|
211
|
+
logger.info(f"Connected to {db_url}")
|
|
212
|
+
yield conn
|
|
213
|
+
except Exception as e:
|
|
214
|
+
logger.error(f"Database error: {e}")
|
|
215
|
+
raise
|
|
216
|
+
finally:
|
|
217
|
+
await conn.close()
|
|
218
|
+
logger.info(f"Closed connection to {db_url}")
|
|
219
|
+
|
|
220
|
+
# Usage
|
|
221
|
+
async def fetch_data():
|
|
222
|
+
async with async_database_connection("postgresql://...") as conn:
|
|
223
|
+
return await conn.fetch("SELECT * FROM users")
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Common Async Context Manager Patterns
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
# Async file operations (Python 3.9+ with aiofiles)
|
|
230
|
+
import aiofiles
|
|
231
|
+
|
|
232
|
+
async def read_file_async(file_path: str) -> str:
|
|
233
|
+
async with aiofiles.open(file_path, mode='r') as f:
|
|
234
|
+
contents = await f.read()
|
|
235
|
+
return contents
|
|
236
|
+
|
|
237
|
+
async def write_file_async(file_path: str, data: str) -> None:
|
|
238
|
+
async with aiofiles.open(file_path, mode='w') as f:
|
|
239
|
+
await f.write(data)
|
|
240
|
+
|
|
241
|
+
# Async HTTP client (with aiohttp)
|
|
242
|
+
import aiohttp
|
|
243
|
+
|
|
244
|
+
async def fetch_url(url: str) -> dict:
|
|
245
|
+
async with aiohttp.ClientSession() as session:
|
|
246
|
+
async with session.get(url) as response:
|
|
247
|
+
return await response.json()
|
|
248
|
+
|
|
249
|
+
# Async lock
|
|
250
|
+
async def critical_section():
|
|
251
|
+
lock = asyncio.Lock()
|
|
252
|
+
|
|
253
|
+
async with lock:
|
|
254
|
+
# Only one coroutine can execute this at a time
|
|
255
|
+
await modify_shared_resource()
|
|
256
|
+
|
|
257
|
+
# Async semaphore - Limit concurrent operations
|
|
258
|
+
async def rate_limited_fetch(urls: List[str], max_concurrent: int = 5):
|
|
259
|
+
semaphore = asyncio.Semaphore(max_concurrent)
|
|
260
|
+
|
|
261
|
+
async def fetch_with_semaphore(url: str):
|
|
262
|
+
async with semaphore:
|
|
263
|
+
# Only max_concurrent tasks run simultaneously
|
|
264
|
+
return await fetch_data(url)
|
|
265
|
+
|
|
266
|
+
tasks = [fetch_with_semaphore(url) for url in urls]
|
|
267
|
+
return await asyncio.gather(*tasks)
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Async Context Manager with Timeout
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
@asynccontextmanager
|
|
274
|
+
async def async_timeout(seconds: float) -> AsyncGenerator[None, None]:
|
|
275
|
+
"""Context manager with timeout.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
seconds: Timeout in seconds
|
|
279
|
+
|
|
280
|
+
Raises:
|
|
281
|
+
asyncio.TimeoutError: If operation exceeds timeout
|
|
282
|
+
"""
|
|
283
|
+
try:
|
|
284
|
+
async with asyncio.timeout(seconds): # Python 3.11+
|
|
285
|
+
yield
|
|
286
|
+
except asyncio.TimeoutError:
|
|
287
|
+
logger.error(f"Operation timed out after {seconds} seconds")
|
|
288
|
+
raise
|
|
289
|
+
|
|
290
|
+
# For Python < 3.11, use asyncio.wait_for
|
|
291
|
+
async def with_timeout_legacy(coro, seconds: float):
|
|
292
|
+
try:
|
|
293
|
+
return await asyncio.wait_for(coro, timeout=seconds)
|
|
294
|
+
except asyncio.TimeoutError:
|
|
295
|
+
logger.error(f"Operation timed out after {seconds} seconds")
|
|
296
|
+
raise
|
|
297
|
+
|
|
298
|
+
# Usage
|
|
299
|
+
async def fetch_with_timeout():
|
|
300
|
+
async with async_timeout(5.0):
|
|
301
|
+
return await fetch_data("https://api.example.com")
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Task Cancellation
|
|
305
|
+
|
|
306
|
+
### Basic Cancellation
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
# Cancel a task
|
|
310
|
+
async def long_running_task():
|
|
311
|
+
try:
|
|
312
|
+
while True:
|
|
313
|
+
await asyncio.sleep(1)
|
|
314
|
+
print("Working...")
|
|
315
|
+
except asyncio.CancelledError:
|
|
316
|
+
print("Task was cancelled")
|
|
317
|
+
# Cleanup code here
|
|
318
|
+
raise # Re-raise to complete cancellation
|
|
319
|
+
|
|
320
|
+
async def main():
|
|
321
|
+
# Create task
|
|
322
|
+
task = asyncio.create_task(long_running_task())
|
|
323
|
+
|
|
324
|
+
# Let it run for a bit
|
|
325
|
+
await asyncio.sleep(3)
|
|
326
|
+
|
|
327
|
+
# Cancel the task
|
|
328
|
+
task.cancel()
|
|
329
|
+
|
|
330
|
+
# Wait for cancellation to complete
|
|
331
|
+
try:
|
|
332
|
+
await task
|
|
333
|
+
except asyncio.CancelledError:
|
|
334
|
+
print("Task cancelled successfully")
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Graceful Cancellation
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
async def graceful_task():
|
|
341
|
+
"""Task that handles cancellation gracefully."""
|
|
342
|
+
try:
|
|
343
|
+
while True:
|
|
344
|
+
await asyncio.sleep(1)
|
|
345
|
+
await process_item()
|
|
346
|
+
except asyncio.CancelledError:
|
|
347
|
+
logger.info("Cancellation requested, cleaning up...")
|
|
348
|
+
await cleanup_resources()
|
|
349
|
+
logger.info("Cleanup complete")
|
|
350
|
+
raise # Re-raise to complete cancellation
|
|
351
|
+
|
|
352
|
+
async def main():
|
|
353
|
+
task = asyncio.create_task(graceful_task())
|
|
354
|
+
await asyncio.sleep(5)
|
|
355
|
+
task.cancel()
|
|
356
|
+
|
|
357
|
+
try:
|
|
358
|
+
await task
|
|
359
|
+
except asyncio.CancelledError:
|
|
360
|
+
logger.info("Task cancelled gracefully")
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Cancellation with Timeout
|
|
364
|
+
|
|
365
|
+
```python
|
|
366
|
+
# Cancel task if it takes too long
|
|
367
|
+
async def task_with_timeout(timeout: float):
|
|
368
|
+
task = asyncio.create_task(long_running_operation())
|
|
369
|
+
|
|
370
|
+
try:
|
|
371
|
+
# Python 3.11+
|
|
372
|
+
async with asyncio.timeout(timeout):
|
|
373
|
+
result = await task
|
|
374
|
+
except asyncio.TimeoutError:
|
|
375
|
+
logger.warning(f"Task timed out after {timeout} seconds")
|
|
376
|
+
task.cancel()
|
|
377
|
+
try:
|
|
378
|
+
await task
|
|
379
|
+
except asyncio.CancelledError:
|
|
380
|
+
pass
|
|
381
|
+
raise
|
|
382
|
+
|
|
383
|
+
return result
|
|
384
|
+
|
|
385
|
+
# Python < 3.11
|
|
386
|
+
async def task_with_timeout_legacy(timeout: float):
|
|
387
|
+
task = asyncio.create_task(long_running_operation())
|
|
388
|
+
|
|
389
|
+
try:
|
|
390
|
+
result = await asyncio.wait_for(task, timeout=timeout)
|
|
391
|
+
except asyncio.TimeoutError:
|
|
392
|
+
logger.warning(f"Task timed out after {timeout} seconds")
|
|
393
|
+
task.cancel()
|
|
394
|
+
try:
|
|
395
|
+
await task
|
|
396
|
+
except asyncio.CancelledError:
|
|
397
|
+
pass
|
|
398
|
+
raise
|
|
399
|
+
|
|
400
|
+
return result
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Shield from Cancellation
|
|
404
|
+
|
|
405
|
+
```python
|
|
406
|
+
# Protect critical operations from cancellation
|
|
407
|
+
async def critical_operation():
|
|
408
|
+
"""Operation that should not be cancelled."""
|
|
409
|
+
await save_to_database()
|
|
410
|
+
await send_confirmation_email()
|
|
411
|
+
|
|
412
|
+
async def main():
|
|
413
|
+
task = asyncio.create_task(critical_operation())
|
|
414
|
+
|
|
415
|
+
# Shield the task from cancellation
|
|
416
|
+
try:
|
|
417
|
+
result = await asyncio.shield(task)
|
|
418
|
+
except asyncio.CancelledError:
|
|
419
|
+
# Even if this coroutine is cancelled, task continues
|
|
420
|
+
logger.info("Main cancelled, but task continues")
|
|
421
|
+
# Wait for task to complete
|
|
422
|
+
result = await task
|
|
423
|
+
|
|
424
|
+
return result
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Cancelling Multiple Tasks
|
|
428
|
+
|
|
429
|
+
```python
|
|
430
|
+
async def cancel_all_tasks(tasks: List[asyncio.Task]) -> None:
|
|
431
|
+
"""Cancel all tasks and wait for them to finish.
|
|
432
|
+
|
|
433
|
+
Args:
|
|
434
|
+
tasks: List of tasks to cancel
|
|
435
|
+
"""
|
|
436
|
+
# Cancel all tasks
|
|
437
|
+
for task in tasks:
|
|
438
|
+
task.cancel()
|
|
439
|
+
|
|
440
|
+
# Wait for all cancellations to complete
|
|
441
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
442
|
+
|
|
443
|
+
# Log results
|
|
444
|
+
for i, task in enumerate(tasks):
|
|
445
|
+
if task.cancelled():
|
|
446
|
+
logger.info(f"Task {i} cancelled")
|
|
447
|
+
elif task.exception():
|
|
448
|
+
logger.error(f"Task {i} failed: {task.exception()}")
|
|
449
|
+
|
|
450
|
+
# Usage
|
|
451
|
+
async def main():
|
|
452
|
+
tasks = [
|
|
453
|
+
asyncio.create_task(worker(i))
|
|
454
|
+
for i in range(10)
|
|
455
|
+
]
|
|
456
|
+
|
|
457
|
+
# Let them run
|
|
458
|
+
await asyncio.sleep(5)
|
|
459
|
+
|
|
460
|
+
# Cancel all
|
|
461
|
+
await cancel_all_tasks(tasks)
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
## Advanced Patterns
|
|
465
|
+
|
|
466
|
+
### Async Generators
|
|
467
|
+
|
|
468
|
+
```python
|
|
469
|
+
from typing import AsyncIterator
|
|
470
|
+
|
|
471
|
+
async def async_range(count: int) -> AsyncIterator[int]:
|
|
472
|
+
"""Async generator that yields numbers.
|
|
473
|
+
|
|
474
|
+
Args:
|
|
475
|
+
count: Number of items to generate
|
|
476
|
+
|
|
477
|
+
Yields:
|
|
478
|
+
Numbers from 0 to count-1
|
|
479
|
+
"""
|
|
480
|
+
for i in range(count):
|
|
481
|
+
await asyncio.sleep(0.1) # Simulate async work
|
|
482
|
+
yield i
|
|
483
|
+
|
|
484
|
+
# Usage
|
|
485
|
+
async def consume_async_generator():
|
|
486
|
+
async for value in async_range(10):
|
|
487
|
+
print(value)
|
|
488
|
+
|
|
489
|
+
# Async generator with cleanup
|
|
490
|
+
async def fetch_items_stream(url: str) -> AsyncIterator[dict]:
|
|
491
|
+
"""Stream items from API.
|
|
492
|
+
|
|
493
|
+
Args:
|
|
494
|
+
url: API endpoint URL
|
|
495
|
+
|
|
496
|
+
Yields:
|
|
497
|
+
Items from API
|
|
498
|
+
"""
|
|
499
|
+
async with aiohttp.ClientSession() as session:
|
|
500
|
+
async with session.get(url) as response:
|
|
501
|
+
async for line in response.content:
|
|
502
|
+
yield json.loads(line)
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Async Comprehensions
|
|
506
|
+
|
|
507
|
+
```python
|
|
508
|
+
# Async list comprehension
|
|
509
|
+
async def fetch_all_users(user_ids: List[int]) -> List[User]:
|
|
510
|
+
return [
|
|
511
|
+
user
|
|
512
|
+
async for user_id in async_user_ids()
|
|
513
|
+
if await is_active(user_id)
|
|
514
|
+
for user in [await fetch_user(user_id)]
|
|
515
|
+
]
|
|
516
|
+
|
|
517
|
+
# Async dict comprehension
|
|
518
|
+
async def fetch_user_map(user_ids: List[int]) -> dict[int, User]:
|
|
519
|
+
return {
|
|
520
|
+
user_id: user
|
|
521
|
+
async for user_id in async_user_ids()
|
|
522
|
+
for user in [await fetch_user(user_id)]
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
# Async set comprehension
|
|
526
|
+
async def fetch_active_user_ids() -> set[int]:
|
|
527
|
+
return {
|
|
528
|
+
user_id
|
|
529
|
+
async for user_id in async_user_ids()
|
|
530
|
+
if await is_active(user_id)
|
|
531
|
+
}
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Task Groups (Python 3.11+)
|
|
535
|
+
|
|
536
|
+
```python
|
|
537
|
+
# Task groups provide structured concurrency
|
|
538
|
+
async def fetch_all_data():
|
|
539
|
+
async with asyncio.TaskGroup() as tg:
|
|
540
|
+
task1 = tg.create_task(fetch_data("url1"))
|
|
541
|
+
task2 = tg.create_task(fetch_data("url2"))
|
|
542
|
+
task3 = tg.create_task(fetch_data("url3"))
|
|
543
|
+
|
|
544
|
+
# All tasks complete here (or exception is raised)
|
|
545
|
+
return [task1.result(), task2.result(), task3.result()]
|
|
546
|
+
|
|
547
|
+
# Task groups with exception handling
|
|
548
|
+
async def fetch_with_error_handling():
|
|
549
|
+
try:
|
|
550
|
+
async with asyncio.TaskGroup() as tg:
|
|
551
|
+
for url in urls:
|
|
552
|
+
tg.create_task(fetch_data(url))
|
|
553
|
+
except* HTTPError as eg:
|
|
554
|
+
# Handle all HTTP errors
|
|
555
|
+
for exc in eg.exceptions:
|
|
556
|
+
logger.error(f"HTTP error: {exc}")
|
|
557
|
+
except* TimeoutError as eg:
|
|
558
|
+
# Handle all timeout errors
|
|
559
|
+
for exc in eg.exceptions:
|
|
560
|
+
logger.error(f"Timeout: {exc}")
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
### Async Queue
|
|
566
|
+
|
|
567
|
+
```python
|
|
568
|
+
from asyncio import Queue
|
|
569
|
+
|
|
570
|
+
# Producer-consumer pattern
|
|
571
|
+
async def producer(queue: Queue, n: int):
|
|
572
|
+
"""Produce items and put them in queue."""
|
|
573
|
+
for i in range(n):
|
|
574
|
+
await asyncio.sleep(0.1)
|
|
575
|
+
await queue.put(i)
|
|
576
|
+
logger.info(f"Produced: {i}")
|
|
577
|
+
|
|
578
|
+
# Signal completion
|
|
579
|
+
await queue.put(None)
|
|
580
|
+
|
|
581
|
+
async def consumer(queue: Queue, name: str):
|
|
582
|
+
"""Consume items from queue."""
|
|
583
|
+
while True:
|
|
584
|
+
item = await queue.get()
|
|
585
|
+
|
|
586
|
+
if item is None:
|
|
587
|
+
# Completion signal
|
|
588
|
+
queue.task_done()
|
|
589
|
+
break
|
|
590
|
+
|
|
591
|
+
logger.info(f"{name} consumed: {item}")
|
|
592
|
+
await process_item(item)
|
|
593
|
+
queue.task_done()
|
|
594
|
+
|
|
595
|
+
async def main():
|
|
596
|
+
queue = Queue(maxsize=10)
|
|
597
|
+
|
|
598
|
+
# Create producer and consumers
|
|
599
|
+
producer_task = asyncio.create_task(producer(queue, 20))
|
|
600
|
+
consumer_tasks = [
|
|
601
|
+
asyncio.create_task(consumer(queue, f"Consumer-{i}"))
|
|
602
|
+
for i in range(3)
|
|
603
|
+
]
|
|
604
|
+
|
|
605
|
+
# Wait for producer to finish
|
|
606
|
+
await producer_task
|
|
607
|
+
|
|
608
|
+
# Wait for queue to be empty
|
|
609
|
+
await queue.join()
|
|
610
|
+
|
|
611
|
+
# Cancel consumers
|
|
612
|
+
for task in consumer_tasks:
|
|
613
|
+
task.cancel()
|
|
614
|
+
|
|
615
|
+
await asyncio.gather(*consumer_tasks, return_exceptions=True)
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
### Async Iterators
|
|
619
|
+
|
|
620
|
+
```python
|
|
621
|
+
class AsyncIterator:
|
|
622
|
+
"""Custom async iterator."""
|
|
623
|
+
|
|
624
|
+
def __init__(self, count: int):
|
|
625
|
+
self.count = count
|
|
626
|
+
self.current = 0
|
|
627
|
+
|
|
628
|
+
def __aiter__(self):
|
|
629
|
+
return self
|
|
630
|
+
|
|
631
|
+
async def __anext__(self):
|
|
632
|
+
if self.current >= self.count:
|
|
633
|
+
raise StopAsyncIteration
|
|
634
|
+
|
|
635
|
+
await asyncio.sleep(0.1)
|
|
636
|
+
value = self.current
|
|
637
|
+
self.current += 1
|
|
638
|
+
return value
|
|
639
|
+
|
|
640
|
+
# Usage
|
|
641
|
+
async def use_async_iterator():
|
|
642
|
+
async for value in AsyncIterator(10):
|
|
643
|
+
print(value)
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
## Best Practices
|
|
647
|
+
|
|
648
|
+
### DO
|
|
649
|
+
|
|
650
|
+
✅ **Use async/await for I/O-bound operations** - Network, file I/O, database queries
|
|
651
|
+
|
|
652
|
+
✅ **Use asyncio.gather() for concurrent tasks** - Run multiple tasks simultaneously
|
|
653
|
+
|
|
654
|
+
✅ **Use async context managers** - For async resource management
|
|
655
|
+
|
|
656
|
+
✅ **Handle CancelledError properly** - Clean up resources before re-raising
|
|
657
|
+
|
|
658
|
+
✅ **Use asyncio.create_task()** - For background tasks
|
|
659
|
+
|
|
660
|
+
✅ **Use semaphores for rate limiting** - Control concurrent operations
|
|
661
|
+
|
|
662
|
+
✅ **Use task groups (Python 3.11+)** - For structured concurrency
|
|
663
|
+
|
|
664
|
+
✅ **Shield critical operations** - Use asyncio.shield() for operations that must complete
|
|
665
|
+
|
|
666
|
+
✅ **Use async generators** - For streaming data
|
|
667
|
+
|
|
668
|
+
✅ **Set timeouts** - Prevent tasks from running indefinitely
|
|
669
|
+
|
|
670
|
+
### DON'T
|
|
671
|
+
|
|
672
|
+
❌ **Don't use async for CPU-bound operations** - Use multiprocessing instead
|
|
673
|
+
|
|
674
|
+
```python
|
|
675
|
+
# Bad - Async doesn't help with CPU-bound work
|
|
676
|
+
async def cpu_intensive():
|
|
677
|
+
result = 0
|
|
678
|
+
for i in range(10_000_000):
|
|
679
|
+
result += i
|
|
680
|
+
return result
|
|
681
|
+
|
|
682
|
+
# Good - Use ProcessPoolExecutor for CPU-bound work
|
|
683
|
+
from concurrent.futures import ProcessPoolExecutor
|
|
684
|
+
|
|
685
|
+
async def cpu_intensive_async():
|
|
686
|
+
loop = asyncio.get_event_loop()
|
|
687
|
+
with ProcessPoolExecutor() as pool:
|
|
688
|
+
result = await loop.run_in_executor(pool, cpu_intensive_sync)
|
|
689
|
+
return result
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
❌ **Don't mix blocking and async code** - Use run_in_executor for blocking calls
|
|
693
|
+
|
|
694
|
+
```python
|
|
695
|
+
# Bad - Blocking call in async function
|
|
696
|
+
async def bad_async():
|
|
697
|
+
result = requests.get("https://api.example.com") # Blocks!
|
|
698
|
+
return result.json()
|
|
699
|
+
|
|
700
|
+
# Good - Use async HTTP client
|
|
701
|
+
async def good_async():
|
|
702
|
+
async with aiohttp.ClientSession() as session:
|
|
703
|
+
async with session.get("https://api.example.com") as response:
|
|
704
|
+
return await response.json()
|
|
705
|
+
|
|
706
|
+
# Good - Use run_in_executor for blocking calls
|
|
707
|
+
async def blocking_in_executor():
|
|
708
|
+
loop = asyncio.get_event_loop()
|
|
709
|
+
result = await loop.run_in_executor(
|
|
710
|
+
None, # Use default executor
|
|
711
|
+
requests.get,
|
|
712
|
+
"https://api.example.com"
|
|
713
|
+
)
|
|
714
|
+
return result.json()
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
❌ **Don't forget to await** - Forgetting await returns a coroutine object
|
|
718
|
+
|
|
719
|
+
```python
|
|
720
|
+
# Bad - Forgot to await
|
|
721
|
+
async def bad():
|
|
722
|
+
result = fetch_data() # Returns coroutine, doesn't execute!
|
|
723
|
+
return result
|
|
724
|
+
|
|
725
|
+
# Good - Properly awaited
|
|
726
|
+
async def good():
|
|
727
|
+
result = await fetch_data()
|
|
728
|
+
return result
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
❌ **Don't swallow CancelledError** - Always re-raise after cleanup
|
|
732
|
+
|
|
733
|
+
```python
|
|
734
|
+
# Bad - Swallows cancellation
|
|
735
|
+
async def bad_cancellation():
|
|
736
|
+
try:
|
|
737
|
+
await long_operation()
|
|
738
|
+
except asyncio.CancelledError:
|
|
739
|
+
logger.info("Cancelled")
|
|
740
|
+
# Forgot to re-raise!
|
|
741
|
+
|
|
742
|
+
# Good - Re-raises after cleanup
|
|
743
|
+
async def good_cancellation():
|
|
744
|
+
try:
|
|
745
|
+
await long_operation()
|
|
746
|
+
except asyncio.CancelledError:
|
|
747
|
+
logger.info("Cancelled, cleaning up")
|
|
748
|
+
await cleanup()
|
|
749
|
+
raise # Re-raise to complete cancellation
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
❌ **Don't create tasks without tracking them** - Can lead to resource leaks
|
|
753
|
+
|
|
754
|
+
```python
|
|
755
|
+
# Bad - Fire and forget
|
|
756
|
+
async def bad():
|
|
757
|
+
asyncio.create_task(background_work()) # Task not tracked!
|
|
758
|
+
|
|
759
|
+
# Good - Track tasks
|
|
760
|
+
async def good():
|
|
761
|
+
task = asyncio.create_task(background_work())
|
|
762
|
+
# Store task reference or await it later
|
|
763
|
+
tasks.append(task)
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
## Common Patterns
|
|
767
|
+
|
|
768
|
+
### Retry with Exponential Backoff
|
|
769
|
+
|
|
770
|
+
```python
|
|
771
|
+
async def retry_with_backoff(
|
|
772
|
+
coro_func,
|
|
773
|
+
max_attempts: int = 3,
|
|
774
|
+
base_delay: float = 1.0,
|
|
775
|
+
max_delay: float = 60.0,
|
|
776
|
+
):
|
|
777
|
+
"""Retry async function with exponential backoff.
|
|
778
|
+
|
|
779
|
+
Args:
|
|
780
|
+
coro_func: Async function to retry
|
|
781
|
+
max_attempts: Maximum number of attempts
|
|
782
|
+
base_delay: Initial delay in seconds
|
|
783
|
+
max_delay: Maximum delay in seconds
|
|
784
|
+
|
|
785
|
+
Returns:
|
|
786
|
+
Result of successful call
|
|
787
|
+
|
|
788
|
+
Raises:
|
|
789
|
+
Last exception if all attempts fail
|
|
790
|
+
"""
|
|
791
|
+
for attempt in range(max_attempts):
|
|
792
|
+
try:
|
|
793
|
+
return await coro_func()
|
|
794
|
+
except Exception as e:
|
|
795
|
+
if attempt == max_attempts - 1:
|
|
796
|
+
raise
|
|
797
|
+
|
|
798
|
+
delay = min(base_delay * (2 ** attempt), max_delay)
|
|
799
|
+
logger.warning(
|
|
800
|
+
f"Attempt {attempt + 1} failed: {e}. "
|
|
801
|
+
f"Retrying in {delay}s..."
|
|
802
|
+
)
|
|
803
|
+
await asyncio.sleep(delay)
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
### Batch Processing
|
|
807
|
+
|
|
808
|
+
```python
|
|
809
|
+
async def process_in_batches(
|
|
810
|
+
items: List[Any],
|
|
811
|
+
batch_size: int,
|
|
812
|
+
process_func,
|
|
813
|
+
):
|
|
814
|
+
"""Process items in batches.
|
|
815
|
+
|
|
816
|
+
Args:
|
|
817
|
+
items: Items to process
|
|
818
|
+
batch_size: Number of items per batch
|
|
819
|
+
process_func: Async function to process each item
|
|
820
|
+
|
|
821
|
+
Returns:
|
|
822
|
+
List of results
|
|
823
|
+
"""
|
|
824
|
+
results = []
|
|
825
|
+
|
|
826
|
+
for i in range(0, len(items), batch_size):
|
|
827
|
+
batch = items[i:i + batch_size]
|
|
828
|
+
batch_results = await asyncio.gather(
|
|
829
|
+
*[process_func(item) for item in batch]
|
|
830
|
+
)
|
|
831
|
+
results.extend(batch_results)
|
|
832
|
+
|
|
833
|
+
# Optional: Add delay between batches
|
|
834
|
+
if i + batch_size < len(items):
|
|
835
|
+
await asyncio.sleep(0.1)
|
|
836
|
+
|
|
837
|
+
return results
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
### Timeout for Multiple Operations
|
|
841
|
+
|
|
842
|
+
```python
|
|
843
|
+
async def fetch_with_individual_timeouts(
|
|
844
|
+
urls: List[str],
|
|
845
|
+
timeout: float = 5.0,
|
|
846
|
+
):
|
|
847
|
+
"""Fetch URLs with individual timeouts.
|
|
848
|
+
|
|
849
|
+
Args:
|
|
850
|
+
urls: List of URLs to fetch
|
|
851
|
+
timeout: Timeout for each request
|
|
852
|
+
|
|
853
|
+
Returns:
|
|
854
|
+
List of results (or None for timeouts)
|
|
855
|
+
"""
|
|
856
|
+
async def fetch_with_timeout(url: str):
|
|
857
|
+
try:
|
|
858
|
+
async with asyncio.timeout(timeout):
|
|
859
|
+
return await fetch_data(url)
|
|
860
|
+
except asyncio.TimeoutError:
|
|
861
|
+
logger.warning(f"Timeout fetching {url}")
|
|
862
|
+
return None
|
|
863
|
+
|
|
864
|
+
return await asyncio.gather(
|
|
865
|
+
*[fetch_with_timeout(url) for url in urls]
|
|
866
|
+
)
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
## Summary
|
|
870
|
+
|
|
871
|
+
**Key Takeaways:**
|
|
872
|
+
|
|
873
|
+
1. **Use async/await for I/O-bound operations** - Not CPU-bound
|
|
874
|
+
2. **Use asyncio.gather()** - For running multiple tasks concurrently
|
|
875
|
+
3. **Use async context managers** - For async resource management
|
|
876
|
+
4. **Handle cancellation properly** - Clean up and re-raise CancelledError
|
|
877
|
+
5. **Use semaphores** - For rate limiting and controlling concurrency
|
|
878
|
+
6. **Set timeouts** - Prevent indefinite waiting
|
|
879
|
+
7. **Don't mix blocking and async code** - Use run_in_executor for blocking calls
|
|
880
|
+
8. **Track all tasks** - Prevent resource leaks
|
|
881
|
+
9. **Use task groups (Python 3.11+)** - For structured concurrency
|
|
882
|
+
10. **Shield critical operations** - Use asyncio.shield() when needed
|
|
883
|
+
|
|
884
|
+
|