claude-flow-novice 1.3.0 → 1.3.2
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/.claude-flow-novice/preferences/generation.json +147 -0
- package/.claude-flow-novice/preferences/language-configs/javascript.json +51 -0
- package/.claude-flow-novice/preferences/language-configs/python.json +50 -0
- package/.claude-flow-novice/preferences/language-configs/rust.json +237 -0
- package/.claude-flow-novice/preferences/language-configs/typescript.json +54 -0
- package/.claude-flow-novice/preferences/project-local.json +91 -0
- package/.claude-flow-novice/preferences/resource-delegation.json +120 -0
- package/.claude-flow-novice/preferences/team-shared.json +195 -0
- package/.claude-flow-novice/preferences/user-global.json +247 -0
- package/.claude-flow-novice/templates/claude-md-templates/CLAUDE-JAVASCRIPT.md +769 -0
- package/.claude-flow-novice/templates/claude-md-templates/CLAUDE-PYTHON.md +1214 -0
- package/.claude-flow-novice/templates/claude-md-templates/CLAUDE-RUST.md +475 -0
- package/.claude-flow-novice/templates/claude-md-templates/CLAUDE-TYPESCRIPT.md +851 -0
- package/.claude-flow-novice/templates/claude-md-templates/README.md +263 -0
- package/CLAUDE.md +81 -0
- package/README-NPM.md +0 -0
- package/package.json +11 -7
- package/scripts/build/README.md +167 -0
- package/scripts/build/build-config.js +27 -0
- package/scripts/build/build-prompt-copier.sh +30 -0
- package/scripts/build/performance-monitor.js +869 -0
- package/scripts/build/prepare-publish.js +150 -0
- package/scripts/build/typescript-fixer.js +621 -0
- package/scripts/build/unified-builder.sh +428 -0
- package/scripts/build/update-bin-version.js +32 -0
- package/scripts/dev/README.md +264 -0
- package/scripts/dev/claude-flow-wrapper.sh +35 -0
- package/scripts/dev/claude-monitor.py +419 -0
- package/scripts/dev/claude-sparc.sh +562 -0
- package/scripts/dev/claude-wrapper.sh +17 -0
- package/scripts/dev/demo-phase3-compliance.js +172 -0
- package/scripts/dev/demo-task-system.ts +224 -0
- package/scripts/dev/deployment-validator.js +315 -0
- package/scripts/dev/spawn-claude-terminal.sh +32 -0
- package/scripts/dev/start-portal.sh +506 -0
- package/scripts/dev/start-web-ui.js +15 -0
- package/scripts/dev/stop-portal.sh +311 -0
- package/scripts/dev/validate-examples.ts +288 -0
- package/scripts/dev/validate-phase2.cjs +451 -0
- package/scripts/dev/validate-phase2.js +785 -0
- package/scripts/dev/validate-phase3.cjs +208 -0
- package/scripts/dev/validate-security-remediation.js +1 -0
- package/scripts/legacy/README.md +272 -0
- package/scripts/legacy/batch-fix-ts.sh +54 -0
- package/scripts/legacy/build-migration.sh +105 -0
- package/scripts/legacy/build-monitor.js +209 -0
- package/scripts/legacy/build-with-filter.sh +84 -0
- package/scripts/legacy/build-workaround.sh +71 -0
- package/scripts/legacy/fix-ts-advanced.js +358 -0
- package/scripts/legacy/fix-ts-final.sh +50 -0
- package/scripts/legacy/fix-ts-targeted.sh +49 -0
- package/scripts/legacy/fix-typescript-errors.js +305 -0
- package/scripts/legacy/force-build.sh +63 -0
- package/scripts/legacy/optimize-performance.js +400 -0
- package/scripts/legacy/performance-monitor.js +263 -0
- package/scripts/legacy/performance-monitoring.js +532 -0
- package/scripts/legacy/performance-test-runner.js +645 -0
- package/scripts/legacy/quick-fix-ts.js +281 -0
- package/scripts/legacy/safe-build.sh +63 -0
- package/scripts/migration/README.md +434 -0
- package/scripts/migration/install-arm64.js +78 -0
- package/scripts/migration/install.js +83 -0
- package/scripts/migration/migrate-hooks.js +173 -0
- package/scripts/migration/migration-examples.ts +318 -0
- package/scripts/optimization/build-optimizer.js +438 -0
- package/scripts/optimization/config-validator.js +761 -0
- package/scripts/optimization/test-optimization.js +432 -0
- package/scripts/optimization/unified-activation.js +839 -0
- package/scripts/performance/ACTIVATION_COMMANDS.md +292 -0
- package/scripts/performance/sqlite-enhanced-activation.sh +583 -0
- package/scripts/performance/test-enhanced-backend.sh +504 -0
- package/scripts/performance-test-runner.js +698 -0
- package/scripts/security/README.md +339 -0
- package/scripts/security/install-git-hooks.sh +132 -0
- package/scripts/security/ruv-swarm-safe.js +74 -0
- package/scripts/test/README.md +236 -0
- package/scripts/test/check-links.ts +274 -0
- package/scripts/test/check-performance-regression.ts +168 -0
- package/scripts/test/coverage-report.ts +692 -0
- package/scripts/test/generate-swarm-tests.js +633 -0
- package/scripts/test/integration-test-validation.cjs +253 -0
- package/scripts/test/load-test-swarm.js +576 -0
- package/scripts/test/run-phase3-compliance-tests.js +427 -0
- package/scripts/test/test-batch-tasks.ts +29 -0
- package/scripts/test/test-byzantine-resolution.js +246 -0
- package/scripts/test/test-claude-spawn-options.sh +63 -0
- package/scripts/test/test-cli-wizard.js +331 -0
- package/scripts/test/test-comprehensive.js +401 -0
- package/scripts/test/test-coordination-features.ts +238 -0
- package/scripts/test/test-fallback-systems.js +276 -0
- package/scripts/test/test-init-command.ts +302 -0
- package/scripts/test/test-mcp.ts +251 -0
- package/scripts/test/test-runner.ts +568 -0
- package/scripts/test/test-swarm-integration.sh +92 -0
- package/scripts/test/test-swarm.ts +142 -0
- package/scripts/test/validation-summary.ts +408 -0
- package/scripts/utils/README.md +261 -0
- package/scripts/utils/clean-build-artifacts.sh +94 -0
- package/scripts/utils/cleanup-root.sh +69 -0
- package/scripts/utils/fix-cliffy-imports.js +307 -0
- package/scripts/utils/fix-duplicate-imports.js +114 -0
- package/scripts/utils/fix-error-handling.cjs +70 -0
- package/scripts/utils/fix-import-paths.js +104 -0
- package/scripts/utils/fix-imports.js +116 -0
- package/scripts/utils/fix-shebang.js +78 -0
- package/scripts/utils/fix-test-modules.js +27 -0
- package/scripts/utils/fix-timezone-issue-246.js +200 -0
- package/scripts/utils/fix-ts-comprehensive.py +182 -0
- package/scripts/utils/fix-ts-targeted-batch.js +250 -0
- package/scripts/utils/remove-benchmark-conflicts.sh +140 -0
- package/scripts/utils/simple-test-fixer.js +190 -0
- package/scripts/utils/validate-metrics-structure.cjs +144 -0
- package/scripts/verify-mcp-server.js +86 -0
- package/src/cli/simple-commands/__tests__/agent.test.js +291 -0
- package/src/cli/simple-commands/__tests__/memory.test.js +8 -0
- package/src/cli/simple-commands/__tests__/swarm.test.js +371 -0
- package/src/cli/simple-commands/__tests__/task.test.js +8 -0
- package/src/cli/simple-commands/agent.js +216 -0
- package/src/cli/simple-commands/analysis.js +570 -0
- package/src/cli/simple-commands/automation-executor.js +1603 -0
- package/src/cli/simple-commands/automation.js +627 -0
- package/src/cli/simple-commands/batch-manager.js +338 -0
- package/src/cli/simple-commands/claude-telemetry.js +311 -0
- package/src/cli/simple-commands/claude-track.js +102 -0
- package/src/cli/simple-commands/concurrent-display.js +348 -0
- package/src/cli/simple-commands/config.js +319 -0
- package/src/cli/simple-commands/coordination.js +307 -0
- package/src/cli/simple-commands/enhanced-ui-views.js +654 -0
- package/src/cli/simple-commands/enhanced-webui-complete.js +1038 -0
- package/src/cli/simple-commands/fix-hook-variables.js +363 -0
- package/src/cli/simple-commands/github/gh-coordinator.js +605 -0
- package/src/cli/simple-commands/github/github-api.js +624 -0
- package/src/cli/simple-commands/github/init.js +543 -0
- package/src/cli/simple-commands/github.js +377 -0
- package/src/cli/simple-commands/goal.js +145 -0
- package/src/cli/simple-commands/hive-mind/auto-save-middleware.js +311 -0
- package/src/cli/simple-commands/hive-mind/communication.js +740 -0
- package/src/cli/simple-commands/hive-mind/core.js +1031 -0
- package/src/cli/simple-commands/hive-mind/db-optimizer.js +872 -0
- package/src/cli/simple-commands/hive-mind/mcp-wrapper.js +1364 -0
- package/src/cli/simple-commands/hive-mind/memory.js +1292 -0
- package/src/cli/simple-commands/hive-mind/performance-optimizer.js +618 -0
- package/src/cli/simple-commands/hive-mind/performance-test.js +373 -0
- package/src/cli/simple-commands/hive-mind/queen.js +809 -0
- package/src/cli/simple-commands/hive-mind/session-manager.js +1223 -0
- package/src/cli/simple-commands/hive-mind-optimize.js +361 -0
- package/src/cli/simple-commands/hive-mind-wizard.js +281 -0
- package/src/cli/simple-commands/hive-mind.js +3112 -0
- package/src/cli/simple-commands/hive.js +140 -0
- package/src/cli/simple-commands/hook-safety.js +671 -0
- package/src/cli/simple-commands/hooks.js +1268 -0
- package/src/cli/simple-commands/init/.claude/checkpoints/1756224542.json +7 -0
- package/src/cli/simple-commands/init/.claude/checkpoints/1756224544.json +8 -0
- package/src/cli/simple-commands/init/README.md +106 -0
- package/src/cli/simple-commands/init/VALIDATION_ROLLBACK.md +488 -0
- package/src/cli/simple-commands/init/agent-copier.js +347 -0
- package/src/cli/simple-commands/init/batch-init.js +663 -0
- package/src/cli/simple-commands/init/claude-commands/claude-flow-commands.js +438 -0
- package/src/cli/simple-commands/init/claude-commands/optimized-claude-flow-commands.js +876 -0
- package/src/cli/simple-commands/init/claude-commands/optimized-slash-commands.js +356 -0
- package/src/cli/simple-commands/init/claude-commands/optimized-sparc-commands.js +501 -0
- package/src/cli/simple-commands/init/claude-commands/slash-commands.js +57 -0
- package/src/cli/simple-commands/init/claude-commands/sparc-commands.js +296 -0
- package/src/cli/simple-commands/init/copy-revised-templates.js +175 -0
- package/src/cli/simple-commands/init/executable-wrapper.js +122 -0
- package/src/cli/simple-commands/init/gitignore-updater.js +137 -0
- package/src/cli/simple-commands/init/help.js +110 -0
- package/src/cli/simple-commands/init/hive-mind-init.js +749 -0
- package/src/cli/simple-commands/init/index.js +1953 -0
- package/src/cli/simple-commands/init/performance-monitor.js +344 -0
- package/src/cli/simple-commands/init/rollback/backup-manager.js +542 -0
- package/src/cli/simple-commands/init/rollback/index.js +399 -0
- package/src/cli/simple-commands/init/rollback/recovery-manager.js +778 -0
- package/src/cli/simple-commands/init/rollback/rollback-executor.js +521 -0
- package/src/cli/simple-commands/init/rollback/state-tracker.js +486 -0
- package/src/cli/simple-commands/init/sparc/roo-readme.js +61 -0
- package/src/cli/simple-commands/init/sparc/roomodes-config.js +102 -0
- package/src/cli/simple-commands/init/sparc/workflows.js +40 -0
- package/src/cli/simple-commands/init/sparc-structure.js +68 -0
- package/src/cli/simple-commands/init/template-copier.js +640 -0
- package/src/cli/simple-commands/init/templates/CLAUDE.md +1185 -0
- package/src/cli/simple-commands/init/templates/CLAUDE.md.optimized +265 -0
- package/src/cli/simple-commands/init/templates/claude-flow-universal +81 -0
- package/src/cli/simple-commands/init/templates/claude-flow.bat +18 -0
- package/src/cli/simple-commands/init/templates/claude-flow.ps1 +24 -0
- package/src/cli/simple-commands/init/templates/claude-md.js +1101 -0
- package/src/cli/simple-commands/init/templates/commands/analysis/bottleneck-detect.md +162 -0
- package/src/cli/simple-commands/init/templates/commands/automation/auto-agent.md +122 -0
- package/src/cli/simple-commands/init/templates/commands/coordination/swarm-init.md +85 -0
- package/src/cli/simple-commands/init/templates/commands/github/github-swarm.md +121 -0
- package/src/cli/simple-commands/init/templates/commands/helpers/standard-checkpoint-hooks.sh +179 -0
- package/src/cli/simple-commands/init/templates/commands/hooks/notification.md +113 -0
- package/src/cli/simple-commands/init/templates/commands/hooks/post-command.md +116 -0
- package/src/cli/simple-commands/init/templates/commands/hooks/post-edit.md +117 -0
- package/src/cli/simple-commands/init/templates/commands/hooks/post-task.md +112 -0
- package/src/cli/simple-commands/init/templates/commands/hooks/pre-command.md +113 -0
- package/src/cli/simple-commands/init/templates/commands/hooks/pre-edit.md +113 -0
- package/src/cli/simple-commands/init/templates/commands/hooks/pre-search.md +112 -0
- package/src/cli/simple-commands/init/templates/commands/hooks/pre-task.md +111 -0
- package/src/cli/simple-commands/init/templates/commands/hooks/session-end.md +118 -0
- package/src/cli/simple-commands/init/templates/commands/hooks/session-restore.md +118 -0
- package/src/cli/simple-commands/init/templates/commands/hooks/session-start.md +117 -0
- package/src/cli/simple-commands/init/templates/coordination-md.js +340 -0
- package/src/cli/simple-commands/init/templates/coordination.md +16 -0
- package/src/cli/simple-commands/init/templates/enhanced-templates.js +2347 -0
- package/src/cli/simple-commands/init/templates/github-safe-enhanced.js +331 -0
- package/src/cli/simple-commands/init/templates/github-safe.js +106 -0
- package/src/cli/simple-commands/init/templates/memory-bank-md.js +259 -0
- package/src/cli/simple-commands/init/templates/memory-bank.md +16 -0
- package/src/cli/simple-commands/init/templates/readme-files.js +72 -0
- package/src/cli/simple-commands/init/templates/safe-hook-patterns.js +430 -0
- package/src/cli/simple-commands/init/templates/settings.json +109 -0
- package/src/cli/simple-commands/init/templates/settings.json.enhanced +35 -0
- package/src/cli/simple-commands/init/templates/sparc-modes.js +1401 -0
- package/src/cli/simple-commands/init/templates/verification-claude-md.js +432 -0
- package/src/cli/simple-commands/init/validation/config-validator.js +354 -0
- package/src/cli/simple-commands/init/validation/health-checker.js +599 -0
- package/src/cli/simple-commands/init/validation/index.js +388 -0
- package/src/cli/simple-commands/init/validation/mode-validator.js +387 -0
- package/src/cli/simple-commands/init/validation/post-init-validator.js +390 -0
- package/src/cli/simple-commands/init/validation/pre-init-validator.js +290 -0
- package/src/cli/simple-commands/init/validation/test-runner.js +488 -0
- package/src/cli/simple-commands/init.js +4 -0
- package/src/cli/simple-commands/mcp-health.js +163 -0
- package/src/cli/simple-commands/mcp-integration-layer.js +689 -0
- package/src/cli/simple-commands/mcp.js +420 -0
- package/src/cli/simple-commands/memory-consolidation.js +631 -0
- package/src/cli/simple-commands/memory.js +345 -0
- package/src/cli/simple-commands/migrate-hooks.js +63 -0
- package/src/cli/simple-commands/monitor.js +417 -0
- package/src/cli/simple-commands/neural.js +148 -0
- package/src/cli/simple-commands/pair-autofix-only.js +755 -0
- package/src/cli/simple-commands/pair-basic.js +751 -0
- package/src/cli/simple-commands/pair-old.js +623 -0
- package/src/cli/simple-commands/pair-working.js +849 -0
- package/src/cli/simple-commands/pair.js +849 -0
- package/src/cli/simple-commands/performance-hooks.js +149 -0
- package/src/cli/simple-commands/performance-metrics.js +601 -0
- package/src/cli/simple-commands/process-ui-enhanced.js +821 -0
- package/src/cli/simple-commands/process-ui.js +274 -0
- package/src/cli/simple-commands/realtime-update-system.js +659 -0
- package/src/cli/simple-commands/sparc/architecture.js +1750 -0
- package/src/cli/simple-commands/sparc/commands.js +575 -0
- package/src/cli/simple-commands/sparc/completion.js +1831 -0
- package/src/cli/simple-commands/sparc/coordinator.js +1045 -0
- package/src/cli/simple-commands/sparc/index.js +321 -0
- package/src/cli/simple-commands/sparc/phase-base.js +430 -0
- package/src/cli/simple-commands/sparc/pseudocode.js +984 -0
- package/src/cli/simple-commands/sparc/refinement.js +1856 -0
- package/src/cli/simple-commands/sparc/specification.js +736 -0
- package/src/cli/simple-commands/sparc-modes/architect.js +125 -0
- package/src/cli/simple-commands/sparc-modes/ask.js +126 -0
- package/src/cli/simple-commands/sparc-modes/code.js +148 -0
- package/src/cli/simple-commands/sparc-modes/debug.js +112 -0
- package/src/cli/simple-commands/sparc-modes/devops.js +137 -0
- package/src/cli/simple-commands/sparc-modes/docs-writer.js +38 -0
- package/src/cli/simple-commands/sparc-modes/generic.js +34 -0
- package/src/cli/simple-commands/sparc-modes/index.js +201 -0
- package/src/cli/simple-commands/sparc-modes/integration.js +55 -0
- package/src/cli/simple-commands/sparc-modes/mcp.js +38 -0
- package/src/cli/simple-commands/sparc-modes/monitoring.js +38 -0
- package/src/cli/simple-commands/sparc-modes/optimization.js +38 -0
- package/src/cli/simple-commands/sparc-modes/security-review.js +130 -0
- package/src/cli/simple-commands/sparc-modes/sparc-orchestrator.js +167 -0
- package/src/cli/simple-commands/sparc-modes/spec-pseudocode.js +38 -0
- package/src/cli/simple-commands/sparc-modes/supabase-admin.js +149 -0
- package/src/cli/simple-commands/sparc-modes/swarm.js +436 -0
- package/src/cli/simple-commands/sparc-modes/tdd.js +112 -0
- package/src/cli/simple-commands/sparc-modes/tutorial.js +277 -0
- package/src/cli/simple-commands/sparc.js +530 -0
- package/src/cli/simple-commands/start-ui.js +147 -0
- package/src/cli/simple-commands/start-wrapper.js +285 -0
- package/src/cli/simple-commands/start.js +2 -0
- package/src/cli/simple-commands/status.js +303 -0
- package/src/cli/simple-commands/stream-chain-clean.js +221 -0
- package/src/cli/simple-commands/stream-chain-fixed.js +89 -0
- package/src/cli/simple-commands/stream-chain-real.js +408 -0
- package/src/cli/simple-commands/stream-chain-working.js +323 -0
- package/src/cli/simple-commands/stream-chain.js +491 -0
- package/src/cli/simple-commands/stream-processor.js +340 -0
- package/src/cli/simple-commands/swarm-executor.js +253 -0
- package/src/cli/simple-commands/swarm-metrics-integration.js +371 -0
- package/src/cli/simple-commands/swarm-ui.js +741 -0
- package/src/cli/simple-commands/swarm-webui-integration.js +311 -0
- package/src/cli/simple-commands/swarm.js +2277 -0
- package/src/cli/simple-commands/task.js +228 -0
- package/src/cli/simple-commands/templates/mle-star-workflow.json +294 -0
- package/src/cli/simple-commands/timestamp-fix.js +104 -0
- package/src/cli/simple-commands/token-tracker.js +372 -0
- package/src/cli/simple-commands/tool-execution-framework.js +555 -0
- package/src/cli/simple-commands/train-and-stream.js +354 -0
- package/src/cli/simple-commands/training-pipeline.js +874 -0
- package/src/cli/simple-commands/training.js +288 -0
- package/src/cli/simple-commands/verification-hooks.js +336 -0
- package/src/cli/simple-commands/verification-integration.js +464 -0
- package/src/cli/simple-commands/verification-training-integration.js +646 -0
- package/src/cli/simple-commands/verification.js +551 -0
- package/src/cli/simple-commands/web-server.js +929 -0
- package/src/cli/simple-commands/webui-validator.js +136 -0
- package/src/language/README.md +503 -0
- package/src/language/claude-md-generator.js +618 -0
- package/src/language/cli.js +422 -0
- package/src/language/example.js +347 -0
- package/src/language/integration-system.js +619 -0
- package/src/language/language-detector.js +581 -0
|
@@ -0,0 +1,1214 @@
|
|
|
1
|
+
# Claude Code Configuration - SPARC Development Environment (Python)
|
|
2
|
+
|
|
3
|
+
## 🚨 CRITICAL: CONCURRENT EXECUTION & FILE MANAGEMENT
|
|
4
|
+
|
|
5
|
+
**ABSOLUTE RULES**:
|
|
6
|
+
1. ALL operations MUST be concurrent/parallel in a single message
|
|
7
|
+
2. **NEVER save working files, text/mds and tests to the root folder**
|
|
8
|
+
3. ALWAYS organize files in appropriate subdirectories
|
|
9
|
+
4. **USE CLAUDE CODE'S TASK TOOL** for spawning agents concurrently, not just MCP
|
|
10
|
+
|
|
11
|
+
### ⚡ GOLDEN RULE: "1 MESSAGE = ALL RELATED OPERATIONS"
|
|
12
|
+
|
|
13
|
+
**MANDATORY PATTERNS:**
|
|
14
|
+
- **TodoWrite**: ALWAYS batch ALL todos in ONE call (5-10+ todos minimum)
|
|
15
|
+
- **Task tool (Claude Code)**: ALWAYS spawn ALL agents in ONE message with full instructions
|
|
16
|
+
- **File operations**: ALWAYS batch ALL reads/writes/edits in ONE message
|
|
17
|
+
- **Bash commands**: ALWAYS batch ALL terminal operations in ONE message
|
|
18
|
+
- **Memory operations**: ALWAYS batch ALL memory store/retrieve in ONE message
|
|
19
|
+
|
|
20
|
+
### 🎯 CRITICAL: Claude Code Task Tool for Agent Execution
|
|
21
|
+
|
|
22
|
+
**Claude Code's Task tool is the PRIMARY way to spawn agents:**
|
|
23
|
+
```javascript
|
|
24
|
+
// ✅ CORRECT: Use Claude Code's Task tool for parallel agent execution
|
|
25
|
+
[Single Message]:
|
|
26
|
+
Task("Python researcher", "Analyze Python patterns and package ecosystem...", "researcher")
|
|
27
|
+
Task("Python coder", "Implement core Python modules with type hints...", "coder")
|
|
28
|
+
Task("Python tester", "Create comprehensive tests with pytest and coverage...", "tester")
|
|
29
|
+
Task("Python reviewer", "Review code for Python best practices and PEP 8...", "reviewer")
|
|
30
|
+
Task("Python architect", "Design system architecture with Python patterns...", "system-architect")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 📁 Python File Organization Rules
|
|
34
|
+
|
|
35
|
+
**NEVER save to root folder. Use Python project structure:**
|
|
36
|
+
- `/src` or `/app` - Source Python files (.py)
|
|
37
|
+
- `/tests` - Test files (test_*.py, *_test.py)
|
|
38
|
+
- `/docs` - Documentation and markdown files
|
|
39
|
+
- `/scripts` - Utility and build scripts
|
|
40
|
+
- `/config` - Configuration files
|
|
41
|
+
- `/data` - Data files (for data science projects)
|
|
42
|
+
- `/notebooks` - Jupyter notebooks (for data science)
|
|
43
|
+
- `requirements.txt` - Production dependencies
|
|
44
|
+
- `requirements-dev.txt` - Development dependencies
|
|
45
|
+
- `pyproject.toml` - Modern Python project configuration
|
|
46
|
+
- `setup.py` - Package setup (legacy, prefer pyproject.toml)
|
|
47
|
+
|
|
48
|
+
## Project Overview
|
|
49
|
+
|
|
50
|
+
This Python project uses SPARC (Specification, Pseudocode, Architecture, Refinement, Completion) methodology with Claude-Flow orchestration for systematic Test-Driven Development with strong typing.
|
|
51
|
+
|
|
52
|
+
## Python-Specific SPARC Commands
|
|
53
|
+
|
|
54
|
+
### Core Commands
|
|
55
|
+
- `npx claude-flow sparc modes` - List available modes
|
|
56
|
+
- `npx claude-flow sparc run <mode> "<python-task>"` - Execute Python-specific mode
|
|
57
|
+
- `npx claude-flow sparc tdd "<python-feature>"` - Run complete TDD workflow for Python
|
|
58
|
+
- `npx claude-flow sparc info <mode>` - Get mode details
|
|
59
|
+
|
|
60
|
+
### Python Environment Commands
|
|
61
|
+
- `python -m venv venv` - Create virtual environment
|
|
62
|
+
- `source venv/bin/activate` - Activate virtual environment (Linux/Mac)
|
|
63
|
+
- `venv\Scripts\activate` - Activate virtual environment (Windows)
|
|
64
|
+
- `pip install -r requirements.txt` - Install dependencies
|
|
65
|
+
- `pip install -e .` - Install package in development mode
|
|
66
|
+
- `python -m pip install --upgrade pip` - Upgrade pip
|
|
67
|
+
|
|
68
|
+
### Python Development Commands
|
|
69
|
+
- `python -m pytest` - Run tests
|
|
70
|
+
- `python -m pytest --cov=src` - Run tests with coverage
|
|
71
|
+
- `python -m pytest --cov=src --cov-report=html` - Generate HTML coverage report
|
|
72
|
+
- `python -m flake8 src/` - Code linting
|
|
73
|
+
- `python -m black src/` - Code formatting
|
|
74
|
+
- `python -m isort src/` - Import sorting
|
|
75
|
+
- `python -m mypy src/` - Type checking
|
|
76
|
+
- `python -m bandit -r src/` - Security analysis
|
|
77
|
+
|
|
78
|
+
### Python Quality Commands
|
|
79
|
+
- `python -m pylint src/` - Advanced linting
|
|
80
|
+
- `python -m safety check` - Security vulnerability check
|
|
81
|
+
- `python -m pip-audit` - Audit pip packages for vulnerabilities
|
|
82
|
+
- `python -m pydocstyle src/` - Docstring style checking
|
|
83
|
+
|
|
84
|
+
## Python SPARC Workflow Phases
|
|
85
|
+
|
|
86
|
+
1. **Specification** - Requirements analysis with Python design patterns (`sparc run spec-pseudocode`)
|
|
87
|
+
2. **Pseudocode** - Algorithm design with Python idioms (`sparc run spec-pseudocode`)
|
|
88
|
+
3. **Architecture** - System design with Python modules and packages (`sparc run architect`)
|
|
89
|
+
4. **Refinement** - TDD implementation with pytest (`sparc tdd`)
|
|
90
|
+
5. **Completion** - Integration with proper packaging (`sparc run integration`)
|
|
91
|
+
|
|
92
|
+
## Python Code Style & Best Practices
|
|
93
|
+
|
|
94
|
+
- **PEP 8**: Follow Python Enhancement Proposal 8 style guide
|
|
95
|
+
- **Type Hints**: Use type annotations for better code documentation
|
|
96
|
+
- **Docstrings**: Comprehensive docstrings following PEP 257
|
|
97
|
+
- **Virtual Environments**: Always use virtual environments
|
|
98
|
+
- **Package Management**: Use pip-tools or poetry for dependency management
|
|
99
|
+
- **Testing**: Comprehensive testing with pytest
|
|
100
|
+
- **Error Handling**: Proper exception handling and custom exceptions
|
|
101
|
+
- **Logging**: Use the logging module instead of print statements
|
|
102
|
+
|
|
103
|
+
## 🚀 Python-Specific Agents (78+ Total)
|
|
104
|
+
|
|
105
|
+
### Core Python Development
|
|
106
|
+
`python-coder`, `python-architect`, `python-tester`, `python-reviewer`, `pep8-expert`
|
|
107
|
+
|
|
108
|
+
### Framework Specialists
|
|
109
|
+
`django-dev`, `flask-dev`, `fastapi-dev`, `tornado-dev`, `pyramid-dev`
|
|
110
|
+
|
|
111
|
+
### Data Science & ML
|
|
112
|
+
`data-scientist`, `ml-engineer`, `pandas-expert`, `numpy-specialist`, `sklearn-dev`
|
|
113
|
+
|
|
114
|
+
### Scientific Computing
|
|
115
|
+
`scipy-expert`, `matplotlib-specialist`, `jupyter-dev`, `research-scientist`
|
|
116
|
+
|
|
117
|
+
### Testing & Quality
|
|
118
|
+
`pytest-expert`, `unittest-specialist`, `coverage-analyst`, `mypy-expert`
|
|
119
|
+
|
|
120
|
+
### Package & Deployment
|
|
121
|
+
`pip-expert`, `poetry-specialist`, `docker-python`, `setuptools-expert`
|
|
122
|
+
|
|
123
|
+
### All Standard Agents Available
|
|
124
|
+
`coder`, `reviewer`, `tester`, `planner`, `researcher`, `system-architect`, `code-analyzer`, `performance-benchmarker`, `cicd-engineer`, `security-manager`
|
|
125
|
+
|
|
126
|
+
## 🎯 Python Development Patterns
|
|
127
|
+
|
|
128
|
+
### ✅ CORRECT PYTHON WORKFLOW
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
// Step 1: Set up Python project coordination
|
|
132
|
+
[Single Message - Coordination Setup]:
|
|
133
|
+
mcp__claude-flow__swarm_init { topology: "hierarchical", maxAgents: 6 }
|
|
134
|
+
mcp__claude-flow__agent_spawn { type: "python-architect" }
|
|
135
|
+
mcp__claude-flow__agent_spawn { type: "python-coder" }
|
|
136
|
+
mcp__claude-flow__agent_spawn { type: "pytest-expert" }
|
|
137
|
+
|
|
138
|
+
// Step 2: Parallel Python development execution
|
|
139
|
+
[Single Message - Parallel Agent Execution]:
|
|
140
|
+
Task("Python architect", "Design modular Python architecture with proper package structure. Store patterns in memory.", "python-architect")
|
|
141
|
+
Task("Python coder", "Implement modules with type hints and proper error handling. Follow PEP 8.", "python-coder")
|
|
142
|
+
Task("Python tester", "Create comprehensive pytest suite with fixtures and parameterization.", "pytest-expert")
|
|
143
|
+
Task("Python reviewer", "Review code for Python best practices, PEP 8, and type safety.", "python-reviewer")
|
|
144
|
+
Task("Package engineer", "Set up proper Python packaging with pyproject.toml.", "pip-expert")
|
|
145
|
+
|
|
146
|
+
// Batch ALL Python todos
|
|
147
|
+
TodoWrite { todos: [
|
|
148
|
+
{content: "Set up virtual environment and requirements", status: "in_progress", activeForm: "Setting up virtual environment"},
|
|
149
|
+
{content: "Configure pyproject.toml with project metadata", status: "pending", activeForm: "Configuring pyproject.toml"},
|
|
150
|
+
{content: "Implement core modules with type hints", status: "pending", activeForm: "Implementing core modules"},
|
|
151
|
+
{content: "Add comprehensive pytest test suite", status: "pending", activeForm: "Adding comprehensive pytest tests"},
|
|
152
|
+
{content: "Configure linting tools (flake8, black, isort)", status: "pending", activeForm: "Configuring linting tools"},
|
|
153
|
+
{content: "Add type checking with mypy", status: "pending", activeForm: "Adding type checking"},
|
|
154
|
+
{content: "Set up documentation with Sphinx", status: "pending", activeForm: "Setting up documentation"},
|
|
155
|
+
{content: "Configure CI/CD pipeline", status: "pending", activeForm: "Configuring CI/CD pipeline"}
|
|
156
|
+
]}
|
|
157
|
+
|
|
158
|
+
// Parallel Python file operations
|
|
159
|
+
Write "pyproject.toml"
|
|
160
|
+
Write "requirements.txt"
|
|
161
|
+
Write "src/__init__.py"
|
|
162
|
+
Write "src/main.py"
|
|
163
|
+
Write "tests/test_main.py"
|
|
164
|
+
Write ".flake8"
|
|
165
|
+
Write "mypy.ini"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Python Agent Coordination Protocol
|
|
169
|
+
|
|
170
|
+
### Every Python Agent MUST:
|
|
171
|
+
|
|
172
|
+
**1️⃣ BEFORE Work:**
|
|
173
|
+
```bash
|
|
174
|
+
npx claude-flow@alpha hooks pre-task --description "[python-task]"
|
|
175
|
+
python -m pytest --collect-only # Verify test discovery
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**2️⃣ DURING Work:**
|
|
179
|
+
```bash
|
|
180
|
+
python -m flake8 src/ # Check code style
|
|
181
|
+
python -m mypy src/ # Type checking
|
|
182
|
+
npx claude-flow@alpha hooks post-edit --file "[file]" --memory-key "python/[agent]/[step]"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**3️⃣ AFTER Work:**
|
|
186
|
+
```bash
|
|
187
|
+
python -m pytest # Run tests
|
|
188
|
+
python -m black src/ # Format code
|
|
189
|
+
npx claude-flow@alpha hooks post-task --task-id "[task]"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Python-Specific Configurations
|
|
193
|
+
|
|
194
|
+
### pyproject.toml Template
|
|
195
|
+
```toml
|
|
196
|
+
[build-system]
|
|
197
|
+
requires = ["hatchling"]
|
|
198
|
+
build-backend = "hatchling.build"
|
|
199
|
+
|
|
200
|
+
[project]
|
|
201
|
+
name = "python-project"
|
|
202
|
+
version = "0.1.0"
|
|
203
|
+
description = "A Python project with SPARC methodology"
|
|
204
|
+
readme = "README.md"
|
|
205
|
+
requires-python = ">=3.8"
|
|
206
|
+
license = {text = "MIT"}
|
|
207
|
+
keywords = ["python", "api", "cli"]
|
|
208
|
+
authors = [
|
|
209
|
+
{name = "Your Name", email = "your.email@example.com"},
|
|
210
|
+
]
|
|
211
|
+
classifiers = [
|
|
212
|
+
"Development Status :: 4 - Beta",
|
|
213
|
+
"Programming Language :: Python",
|
|
214
|
+
"Programming Language :: Python :: 3.8",
|
|
215
|
+
"Programming Language :: Python :: 3.9",
|
|
216
|
+
"Programming Language :: Python :: 3.10",
|
|
217
|
+
"Programming Language :: Python :: 3.11",
|
|
218
|
+
"Programming Language :: Python :: 3.12",
|
|
219
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
220
|
+
"Programming Language :: Python :: Implementation :: PyPy",
|
|
221
|
+
]
|
|
222
|
+
dependencies = [
|
|
223
|
+
"click>=8.0.0",
|
|
224
|
+
"requests>=2.28.0",
|
|
225
|
+
"pydantic>=1.10.0",
|
|
226
|
+
]
|
|
227
|
+
|
|
228
|
+
[project.optional-dependencies]
|
|
229
|
+
dev = [
|
|
230
|
+
"pytest>=7.0.0",
|
|
231
|
+
"pytest-cov>=4.0.0",
|
|
232
|
+
"pytest-mock>=3.10.0",
|
|
233
|
+
"black>=22.0.0",
|
|
234
|
+
"flake8>=5.0.0",
|
|
235
|
+
"isort>=5.10.0",
|
|
236
|
+
"mypy>=1.0.0",
|
|
237
|
+
"bandit>=1.7.0",
|
|
238
|
+
"safety>=2.0.0",
|
|
239
|
+
]
|
|
240
|
+
docs = [
|
|
241
|
+
"sphinx>=5.0.0",
|
|
242
|
+
"sphinx-rtd-theme>=1.0.0",
|
|
243
|
+
]
|
|
244
|
+
test = [
|
|
245
|
+
"pytest>=7.0.0",
|
|
246
|
+
"pytest-cov>=4.0.0",
|
|
247
|
+
"pytest-xdist>=3.0.0",
|
|
248
|
+
"hypothesis>=6.70.0",
|
|
249
|
+
]
|
|
250
|
+
|
|
251
|
+
[project.urls]
|
|
252
|
+
Documentation = "https://github.com/username/python-project#readme"
|
|
253
|
+
Issues = "https://github.com/username/python-project/issues"
|
|
254
|
+
Source = "https://github.com/username/python-project"
|
|
255
|
+
|
|
256
|
+
[project.scripts]
|
|
257
|
+
my-cli = "python_project.cli:main"
|
|
258
|
+
|
|
259
|
+
[tool.hatch.version]
|
|
260
|
+
path = "src/python_project/__about__.py"
|
|
261
|
+
|
|
262
|
+
[tool.hatch.envs.default]
|
|
263
|
+
dependencies = [
|
|
264
|
+
"coverage[toml]>=6.5",
|
|
265
|
+
"pytest",
|
|
266
|
+
]
|
|
267
|
+
[tool.hatch.envs.default.scripts]
|
|
268
|
+
test = "pytest {args:tests}"
|
|
269
|
+
test-cov = "coverage run -m pytest {args:tests}"
|
|
270
|
+
cov-report = [
|
|
271
|
+
"- coverage combine",
|
|
272
|
+
"coverage report",
|
|
273
|
+
]
|
|
274
|
+
cov = [
|
|
275
|
+
"test-cov",
|
|
276
|
+
"cov-report",
|
|
277
|
+
]
|
|
278
|
+
|
|
279
|
+
[tool.coverage.run]
|
|
280
|
+
source_pkgs = ["python_project", "tests"]
|
|
281
|
+
branch = true
|
|
282
|
+
parallel = true
|
|
283
|
+
omit = [
|
|
284
|
+
"src/python_project/__about__.py",
|
|
285
|
+
]
|
|
286
|
+
|
|
287
|
+
[tool.coverage.paths]
|
|
288
|
+
python_project = ["src/python_project", "*/python-project/src/python_project"]
|
|
289
|
+
tests = ["tests", "*/python-project/tests"]
|
|
290
|
+
|
|
291
|
+
[tool.coverage.report]
|
|
292
|
+
exclude_lines = [
|
|
293
|
+
"no cov",
|
|
294
|
+
"if __name__ == .__main__.:",
|
|
295
|
+
"if TYPE_CHECKING:",
|
|
296
|
+
]
|
|
297
|
+
|
|
298
|
+
[tool.black]
|
|
299
|
+
target-version = ["py38"]
|
|
300
|
+
line-length = 88
|
|
301
|
+
skip-string-normalization = true
|
|
302
|
+
|
|
303
|
+
[tool.isort]
|
|
304
|
+
profile = "black"
|
|
305
|
+
multi_line_output = 3
|
|
306
|
+
include_trailing_comma = true
|
|
307
|
+
force_grid_wrap = 0
|
|
308
|
+
use_parentheses = true
|
|
309
|
+
ensure_newline_before_comments = true
|
|
310
|
+
line_length = 88
|
|
311
|
+
|
|
312
|
+
[tool.mypy]
|
|
313
|
+
python_version = "3.8"
|
|
314
|
+
warn_return_any = true
|
|
315
|
+
warn_unused_configs = true
|
|
316
|
+
disallow_untyped_defs = true
|
|
317
|
+
disallow_incomplete_defs = true
|
|
318
|
+
check_untyped_defs = true
|
|
319
|
+
disallow_untyped_decorators = true
|
|
320
|
+
no_implicit_optional = true
|
|
321
|
+
warn_redundant_casts = true
|
|
322
|
+
warn_unused_ignores = true
|
|
323
|
+
warn_no_return = true
|
|
324
|
+
warn_unreachable = true
|
|
325
|
+
strict_equality = true
|
|
326
|
+
|
|
327
|
+
[tool.pylint.messages_control]
|
|
328
|
+
disable = [
|
|
329
|
+
"missing-docstring",
|
|
330
|
+
"too-few-public-methods",
|
|
331
|
+
]
|
|
332
|
+
|
|
333
|
+
[tool.bandit]
|
|
334
|
+
exclude_dirs = ["tests"]
|
|
335
|
+
skips = ["B101", "B601"]
|
|
336
|
+
|
|
337
|
+
[tool.pytest.ini_options]
|
|
338
|
+
minversion = "6.0"
|
|
339
|
+
addopts = [
|
|
340
|
+
"--strict-config",
|
|
341
|
+
"--strict-markers",
|
|
342
|
+
"--doctest-modules",
|
|
343
|
+
"--cov=src",
|
|
344
|
+
"--cov-report=term-missing",
|
|
345
|
+
"--cov-fail-under=85",
|
|
346
|
+
]
|
|
347
|
+
testpaths = ["tests"]
|
|
348
|
+
pythonpath = ["src"]
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### requirements.txt Template
|
|
352
|
+
```
|
|
353
|
+
# Production dependencies
|
|
354
|
+
click>=8.0.0
|
|
355
|
+
requests>=2.28.0
|
|
356
|
+
pydantic>=1.10.0
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### requirements-dev.txt Template
|
|
360
|
+
```
|
|
361
|
+
# Development dependencies
|
|
362
|
+
-r requirements.txt
|
|
363
|
+
|
|
364
|
+
# Testing
|
|
365
|
+
pytest>=7.0.0
|
|
366
|
+
pytest-cov>=4.0.0
|
|
367
|
+
pytest-mock>=3.10.0
|
|
368
|
+
pytest-xdist>=3.0.0
|
|
369
|
+
hypothesis>=6.70.0
|
|
370
|
+
|
|
371
|
+
# Code quality
|
|
372
|
+
black>=22.0.0
|
|
373
|
+
flake8>=5.0.0
|
|
374
|
+
isort>=5.10.0
|
|
375
|
+
mypy>=1.0.0
|
|
376
|
+
pylint>=2.15.0
|
|
377
|
+
|
|
378
|
+
# Security
|
|
379
|
+
bandit>=1.7.0
|
|
380
|
+
safety>=2.0.0
|
|
381
|
+
|
|
382
|
+
# Documentation
|
|
383
|
+
sphinx>=5.0.0
|
|
384
|
+
sphinx-rtd-theme>=1.0.0
|
|
385
|
+
|
|
386
|
+
# Development tools
|
|
387
|
+
pre-commit>=2.20.0
|
|
388
|
+
tox>=4.0.0
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### .flake8 Configuration
|
|
392
|
+
```ini
|
|
393
|
+
[flake8]
|
|
394
|
+
max-line-length = 88
|
|
395
|
+
extend-ignore = E203, W503, E501
|
|
396
|
+
exclude =
|
|
397
|
+
.git,
|
|
398
|
+
__pycache__,
|
|
399
|
+
.venv,
|
|
400
|
+
venv,
|
|
401
|
+
.eggs,
|
|
402
|
+
*.egg,
|
|
403
|
+
build,
|
|
404
|
+
dist,
|
|
405
|
+
.pytest_cache
|
|
406
|
+
per-file-ignores =
|
|
407
|
+
__init__.py:F401
|
|
408
|
+
tests/*:S101
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### mypy.ini Configuration
|
|
412
|
+
```ini
|
|
413
|
+
[mypy]
|
|
414
|
+
python_version = 3.8
|
|
415
|
+
warn_return_any = True
|
|
416
|
+
warn_unused_configs = True
|
|
417
|
+
disallow_untyped_defs = True
|
|
418
|
+
disallow_incomplete_defs = True
|
|
419
|
+
check_untyped_defs = True
|
|
420
|
+
disallow_untyped_decorators = True
|
|
421
|
+
no_implicit_optional = True
|
|
422
|
+
warn_redundant_casts = True
|
|
423
|
+
warn_unused_ignores = True
|
|
424
|
+
warn_no_return = True
|
|
425
|
+
warn_unreachable = True
|
|
426
|
+
strict_equality = True
|
|
427
|
+
|
|
428
|
+
[mypy-tests.*]
|
|
429
|
+
disallow_untyped_defs = False
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Testing Strategies
|
|
433
|
+
|
|
434
|
+
### Pytest Configuration and Tests
|
|
435
|
+
```python
|
|
436
|
+
# tests/conftest.py
|
|
437
|
+
import pytest
|
|
438
|
+
from typing import Generator
|
|
439
|
+
from unittest.mock import Mock
|
|
440
|
+
|
|
441
|
+
@pytest.fixture
|
|
442
|
+
def sample_data() -> dict:
|
|
443
|
+
"""Fixture providing sample test data."""
|
|
444
|
+
return {
|
|
445
|
+
"id": "123",
|
|
446
|
+
"name": "Test User",
|
|
447
|
+
"email": "test@example.com"
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
@pytest.fixture
|
|
451
|
+
def mock_database() -> Generator[Mock, None, None]:
|
|
452
|
+
"""Fixture providing a mock database."""
|
|
453
|
+
mock_db = Mock()
|
|
454
|
+
yield mock_db
|
|
455
|
+
mock_db.reset_mock()
|
|
456
|
+
|
|
457
|
+
@pytest.fixture(scope="session")
|
|
458
|
+
def test_config() -> dict:
|
|
459
|
+
"""Session-scoped fixture for test configuration."""
|
|
460
|
+
return {
|
|
461
|
+
"testing": True,
|
|
462
|
+
"database_url": "sqlite:///:memory:"
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
```python
|
|
467
|
+
# tests/test_user_service.py
|
|
468
|
+
import pytest
|
|
469
|
+
from unittest.mock import Mock, patch
|
|
470
|
+
from typing import Dict, Any
|
|
471
|
+
|
|
472
|
+
from src.user_service import UserService, User
|
|
473
|
+
from src.exceptions import ValidationError, NotFoundError
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
class TestUserService:
|
|
477
|
+
"""Test cases for UserService class."""
|
|
478
|
+
|
|
479
|
+
@pytest.fixture
|
|
480
|
+
def user_service(self, mock_database: Mock) -> UserService:
|
|
481
|
+
"""Create UserService instance for testing."""
|
|
482
|
+
return UserService(database=mock_database)
|
|
483
|
+
|
|
484
|
+
def test_create_user_success(
|
|
485
|
+
self,
|
|
486
|
+
user_service: UserService,
|
|
487
|
+
sample_data: Dict[str, Any],
|
|
488
|
+
mock_database: Mock
|
|
489
|
+
) -> None:
|
|
490
|
+
"""Test successful user creation."""
|
|
491
|
+
# Arrange
|
|
492
|
+
mock_database.save.return_value = User(**sample_data)
|
|
493
|
+
|
|
494
|
+
# Act
|
|
495
|
+
result = user_service.create_user(sample_data)
|
|
496
|
+
|
|
497
|
+
# Assert
|
|
498
|
+
assert isinstance(result, User)
|
|
499
|
+
assert result.name == sample_data["name"]
|
|
500
|
+
assert result.email == sample_data["email"]
|
|
501
|
+
mock_database.save.assert_called_once()
|
|
502
|
+
|
|
503
|
+
def test_create_user_invalid_email(self, user_service: UserService) -> None:
|
|
504
|
+
"""Test user creation with invalid email."""
|
|
505
|
+
invalid_data = {"name": "Test", "email": "invalid-email"}
|
|
506
|
+
|
|
507
|
+
with pytest.raises(ValidationError, match="Invalid email format"):
|
|
508
|
+
user_service.create_user(invalid_data)
|
|
509
|
+
|
|
510
|
+
@pytest.mark.parametrize("email", [
|
|
511
|
+
"valid@example.com",
|
|
512
|
+
"user.name+tag@example.co.uk",
|
|
513
|
+
"test123@subdomain.example.org"
|
|
514
|
+
])
|
|
515
|
+
def test_valid_emails(self, user_service: UserService, email: str) -> None:
|
|
516
|
+
"""Test various valid email formats."""
|
|
517
|
+
data = {"name": "Test User", "email": email}
|
|
518
|
+
# Mock the database to avoid actual calls
|
|
519
|
+
with patch.object(user_service.database, 'save') as mock_save:
|
|
520
|
+
mock_save.return_value = User(**data)
|
|
521
|
+
result = user_service.create_user(data)
|
|
522
|
+
assert result.email == email
|
|
523
|
+
|
|
524
|
+
@pytest.mark.asyncio
|
|
525
|
+
async def test_async_user_fetch(self, user_service: UserService) -> None:
|
|
526
|
+
"""Test async user fetching."""
|
|
527
|
+
user_id = "123"
|
|
528
|
+
expected_user = User(id=user_id, name="Test", email="test@example.com")
|
|
529
|
+
|
|
530
|
+
with patch.object(user_service, 'fetch_user_async') as mock_fetch:
|
|
531
|
+
mock_fetch.return_value = expected_user
|
|
532
|
+
result = await user_service.fetch_user_async(user_id)
|
|
533
|
+
assert result == expected_user
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Property-Based Testing with Hypothesis
|
|
537
|
+
```python
|
|
538
|
+
# tests/test_properties.py
|
|
539
|
+
from hypothesis import given, strategies as st
|
|
540
|
+
from src.utils import normalize_string, calculate_age
|
|
541
|
+
from datetime import date
|
|
542
|
+
|
|
543
|
+
class TestStringNormalization:
|
|
544
|
+
"""Property-based tests for string normalization."""
|
|
545
|
+
|
|
546
|
+
@given(st.text())
|
|
547
|
+
def test_normalize_idempotent(self, text: str) -> None:
|
|
548
|
+
"""Normalizing twice should be the same as normalizing once."""
|
|
549
|
+
normalized_once = normalize_string(text)
|
|
550
|
+
normalized_twice = normalize_string(normalized_once)
|
|
551
|
+
assert normalized_once == normalized_twice
|
|
552
|
+
|
|
553
|
+
@given(st.text(min_size=1))
|
|
554
|
+
def test_normalize_non_empty_input_produces_output(self, text: str) -> None:
|
|
555
|
+
"""Non-empty input should produce non-empty output."""
|
|
556
|
+
result = normalize_string(text)
|
|
557
|
+
assert len(result) > 0
|
|
558
|
+
|
|
559
|
+
@given(st.dates(min_value=date(1900, 1, 1), max_value=date.today()))
|
|
560
|
+
def test_calculate_age_always_positive(self, birth_date: date) -> None:
|
|
561
|
+
"""Age calculation should always produce non-negative values."""
|
|
562
|
+
age = calculate_age(birth_date)
|
|
563
|
+
assert age >= 0
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
## Type Hints and Data Classes
|
|
567
|
+
|
|
568
|
+
### Type Definitions
|
|
569
|
+
```python
|
|
570
|
+
# src/types.py
|
|
571
|
+
from typing import Dict, List, Optional, Union, TypeVar, Generic, Protocol
|
|
572
|
+
from dataclasses import dataclass
|
|
573
|
+
from enum import Enum
|
|
574
|
+
from datetime import datetime
|
|
575
|
+
|
|
576
|
+
# Type variables
|
|
577
|
+
T = TypeVar('T')
|
|
578
|
+
K = TypeVar('K')
|
|
579
|
+
V = TypeVar('V')
|
|
580
|
+
|
|
581
|
+
# Enums
|
|
582
|
+
class UserRole(Enum):
|
|
583
|
+
"""User role enumeration."""
|
|
584
|
+
ADMIN = "admin"
|
|
585
|
+
USER = "user"
|
|
586
|
+
MODERATOR = "moderator"
|
|
587
|
+
|
|
588
|
+
class Status(Enum):
|
|
589
|
+
"""Status enumeration."""
|
|
590
|
+
ACTIVE = "active"
|
|
591
|
+
INACTIVE = "inactive"
|
|
592
|
+
PENDING = "pending"
|
|
593
|
+
|
|
594
|
+
# Data classes
|
|
595
|
+
@dataclass
|
|
596
|
+
class User:
|
|
597
|
+
"""User data class with type hints."""
|
|
598
|
+
id: str
|
|
599
|
+
name: str
|
|
600
|
+
email: str
|
|
601
|
+
role: UserRole
|
|
602
|
+
created_at: datetime
|
|
603
|
+
updated_at: Optional[datetime] = None
|
|
604
|
+
metadata: Optional[Dict[str, Union[str, int, bool]]] = None
|
|
605
|
+
|
|
606
|
+
def __post_init__(self) -> None:
|
|
607
|
+
"""Post-initialization validation."""
|
|
608
|
+
if not self.email or "@" not in self.email:
|
|
609
|
+
raise ValueError("Invalid email format")
|
|
610
|
+
|
|
611
|
+
if self.metadata is None:
|
|
612
|
+
self.metadata = {}
|
|
613
|
+
|
|
614
|
+
# Protocols for structural typing
|
|
615
|
+
class Serializable(Protocol):
|
|
616
|
+
"""Protocol for serializable objects."""
|
|
617
|
+
|
|
618
|
+
def to_dict(self) -> Dict[str, Union[str, int, bool]]:
|
|
619
|
+
"""Convert object to dictionary."""
|
|
620
|
+
...
|
|
621
|
+
|
|
622
|
+
@classmethod
|
|
623
|
+
def from_dict(cls, data: Dict[str, Union[str, int, bool]]) -> 'Serializable':
|
|
624
|
+
"""Create object from dictionary."""
|
|
625
|
+
...
|
|
626
|
+
|
|
627
|
+
# Generic classes
|
|
628
|
+
class Repository(Generic[T]):
|
|
629
|
+
"""Generic repository pattern."""
|
|
630
|
+
|
|
631
|
+
def __init__(self, model_class: type[T]) -> None:
|
|
632
|
+
self.model_class = model_class
|
|
633
|
+
self._storage: Dict[str, T] = {}
|
|
634
|
+
|
|
635
|
+
def save(self, item: T) -> T:
|
|
636
|
+
"""Save item to repository."""
|
|
637
|
+
item_id = getattr(item, 'id')
|
|
638
|
+
self._storage[item_id] = item
|
|
639
|
+
return item
|
|
640
|
+
|
|
641
|
+
def find_by_id(self, item_id: str) -> Optional[T]:
|
|
642
|
+
"""Find item by ID."""
|
|
643
|
+
return self._storage.get(item_id)
|
|
644
|
+
|
|
645
|
+
def find_all(self) -> List[T]:
|
|
646
|
+
"""Find all items."""
|
|
647
|
+
return list(self._storage.values())
|
|
648
|
+
|
|
649
|
+
# Union types
|
|
650
|
+
UserInput = Union[Dict[str, str], User]
|
|
651
|
+
ApiResponse = Union[Dict[str, str], List[Dict[str, str]]]
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
### Advanced Type Usage
|
|
655
|
+
```python
|
|
656
|
+
# src/advanced_types.py
|
|
657
|
+
from typing import (
|
|
658
|
+
Callable, Awaitable, TypedDict, Literal,
|
|
659
|
+
Final, ClassVar, overload
|
|
660
|
+
)
|
|
661
|
+
from functools import wraps
|
|
662
|
+
from dataclasses import dataclass, field
|
|
663
|
+
|
|
664
|
+
# TypedDict for structured dictionaries
|
|
665
|
+
class UserDict(TypedDict):
|
|
666
|
+
"""Typed dictionary for user data."""
|
|
667
|
+
id: str
|
|
668
|
+
name: str
|
|
669
|
+
email: str
|
|
670
|
+
age: int
|
|
671
|
+
|
|
672
|
+
class UserDictOptional(TypedDict, total=False):
|
|
673
|
+
"""Typed dictionary with optional fields."""
|
|
674
|
+
id: str
|
|
675
|
+
name: str
|
|
676
|
+
email: str
|
|
677
|
+
age: int # This is optional due to total=False
|
|
678
|
+
|
|
679
|
+
# Literal types
|
|
680
|
+
Mode = Literal["development", "testing", "production"]
|
|
681
|
+
HttpMethod = Literal["GET", "POST", "PUT", "DELETE"]
|
|
682
|
+
|
|
683
|
+
# Final and ClassVar
|
|
684
|
+
@dataclass
|
|
685
|
+
class Config:
|
|
686
|
+
"""Configuration with final and class variables."""
|
|
687
|
+
API_VERSION: Final[str] = "v1"
|
|
688
|
+
MAX_CONNECTIONS: ClassVar[int] = 100
|
|
689
|
+
|
|
690
|
+
environment: Mode
|
|
691
|
+
debug: bool = field(default=False)
|
|
692
|
+
|
|
693
|
+
def __post_init__(self) -> None:
|
|
694
|
+
"""Validate configuration."""
|
|
695
|
+
if self.environment == "production" and self.debug:
|
|
696
|
+
raise ValueError("Debug mode not allowed in production")
|
|
697
|
+
|
|
698
|
+
# Function overloading
|
|
699
|
+
@overload
|
|
700
|
+
def process_data(data: str) -> str: ...
|
|
701
|
+
|
|
702
|
+
@overload
|
|
703
|
+
def process_data(data: int) -> int: ...
|
|
704
|
+
|
|
705
|
+
@overload
|
|
706
|
+
def process_data(data: List[str]) -> List[str]: ...
|
|
707
|
+
|
|
708
|
+
def process_data(data: Union[str, int, List[str]]) -> Union[str, int, List[str]]:
|
|
709
|
+
"""Process data with type-specific logic."""
|
|
710
|
+
if isinstance(data, str):
|
|
711
|
+
return data.upper()
|
|
712
|
+
elif isinstance(data, int):
|
|
713
|
+
return data * 2
|
|
714
|
+
elif isinstance(data, list):
|
|
715
|
+
return [item.upper() for item in data]
|
|
716
|
+
else:
|
|
717
|
+
raise TypeError(f"Unsupported type: {type(data)}")
|
|
718
|
+
|
|
719
|
+
# Decorator with types
|
|
720
|
+
def validate_types(func: Callable[..., T]) -> Callable[..., T]:
|
|
721
|
+
"""Decorator to validate function arguments at runtime."""
|
|
722
|
+
@wraps(func)
|
|
723
|
+
def wrapper(*args, **kwargs) -> T:
|
|
724
|
+
# Runtime type validation logic here
|
|
725
|
+
return func(*args, **kwargs)
|
|
726
|
+
return wrapper
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
## Error Handling and Exceptions
|
|
730
|
+
|
|
731
|
+
### Custom Exception Classes
|
|
732
|
+
```python
|
|
733
|
+
# src/exceptions.py
|
|
734
|
+
from typing import Dict, Any, Optional
|
|
735
|
+
|
|
736
|
+
class AppError(Exception):
|
|
737
|
+
"""Base application error class."""
|
|
738
|
+
|
|
739
|
+
def __init__(
|
|
740
|
+
self,
|
|
741
|
+
message: str,
|
|
742
|
+
error_code: Optional[str] = None,
|
|
743
|
+
context: Optional[Dict[str, Any]] = None
|
|
744
|
+
) -> None:
|
|
745
|
+
super().__init__(message)
|
|
746
|
+
self.message = message
|
|
747
|
+
self.error_code = error_code or self.__class__.__name__
|
|
748
|
+
self.context = context or {}
|
|
749
|
+
|
|
750
|
+
class ValidationError(AppError):
|
|
751
|
+
"""Raised when data validation fails."""
|
|
752
|
+
pass
|
|
753
|
+
|
|
754
|
+
class NotFoundError(AppError):
|
|
755
|
+
"""Raised when a resource is not found."""
|
|
756
|
+
pass
|
|
757
|
+
|
|
758
|
+
class DatabaseError(AppError):
|
|
759
|
+
"""Raised when database operations fail."""
|
|
760
|
+
pass
|
|
761
|
+
|
|
762
|
+
class AuthenticationError(AppError):
|
|
763
|
+
"""Raised when authentication fails."""
|
|
764
|
+
pass
|
|
765
|
+
|
|
766
|
+
class AuthorizationError(AppError):
|
|
767
|
+
"""Raised when authorization fails."""
|
|
768
|
+
pass
|
|
769
|
+
|
|
770
|
+
# Exception handling utilities
|
|
771
|
+
def handle_api_errors(func: Callable[..., T]) -> Callable[..., T]:
|
|
772
|
+
"""Decorator to handle and log API errors."""
|
|
773
|
+
@wraps(func)
|
|
774
|
+
def wrapper(*args, **kwargs) -> T:
|
|
775
|
+
try:
|
|
776
|
+
return func(*args, **kwargs)
|
|
777
|
+
except ValidationError as e:
|
|
778
|
+
logger.warning(f"Validation error: {e.message}", extra=e.context)
|
|
779
|
+
raise
|
|
780
|
+
except NotFoundError as e:
|
|
781
|
+
logger.info(f"Resource not found: {e.message}", extra=e.context)
|
|
782
|
+
raise
|
|
783
|
+
except DatabaseError as e:
|
|
784
|
+
logger.error(f"Database error: {e.message}", extra=e.context)
|
|
785
|
+
raise
|
|
786
|
+
except Exception as e:
|
|
787
|
+
logger.exception(f"Unexpected error in {func.__name__}: {e}")
|
|
788
|
+
raise AppError("Internal server error") from e
|
|
789
|
+
return wrapper
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
## Logging Configuration
|
|
793
|
+
|
|
794
|
+
### Structured Logging
|
|
795
|
+
```python
|
|
796
|
+
# src/logging_config.py
|
|
797
|
+
import logging
|
|
798
|
+
import logging.config
|
|
799
|
+
import json
|
|
800
|
+
from typing import Dict, Any
|
|
801
|
+
from datetime import datetime
|
|
802
|
+
|
|
803
|
+
class JSONFormatter(logging.Formatter):
|
|
804
|
+
"""Custom JSON formatter for structured logging."""
|
|
805
|
+
|
|
806
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
807
|
+
"""Format log record as JSON."""
|
|
808
|
+
log_data = {
|
|
809
|
+
"timestamp": datetime.utcnow().isoformat(),
|
|
810
|
+
"level": record.levelname,
|
|
811
|
+
"logger": record.name,
|
|
812
|
+
"message": record.getMessage(),
|
|
813
|
+
"module": record.module,
|
|
814
|
+
"function": record.funcName,
|
|
815
|
+
"line": record.lineno,
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
if record.exc_info:
|
|
819
|
+
log_data["exception"] = self.formatException(record.exc_info)
|
|
820
|
+
|
|
821
|
+
# Add any extra fields
|
|
822
|
+
for key, value in record.__dict__.items():
|
|
823
|
+
if key not in log_data and not key.startswith('_'):
|
|
824
|
+
log_data[key] = value
|
|
825
|
+
|
|
826
|
+
return json.dumps(log_data)
|
|
827
|
+
|
|
828
|
+
def setup_logging(level: str = "INFO", use_json: bool = False) -> None:
|
|
829
|
+
"""Set up application logging."""
|
|
830
|
+
config: Dict[str, Any] = {
|
|
831
|
+
"version": 1,
|
|
832
|
+
"disable_existing_loggers": False,
|
|
833
|
+
"formatters": {
|
|
834
|
+
"standard": {
|
|
835
|
+
"format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
|
|
836
|
+
},
|
|
837
|
+
"json": {
|
|
838
|
+
"()": JSONFormatter
|
|
839
|
+
}
|
|
840
|
+
},
|
|
841
|
+
"handlers": {
|
|
842
|
+
"console": {
|
|
843
|
+
"class": "logging.StreamHandler",
|
|
844
|
+
"level": level,
|
|
845
|
+
"formatter": "json" if use_json else "standard",
|
|
846
|
+
"stream": "ext://sys.stdout"
|
|
847
|
+
},
|
|
848
|
+
"file": {
|
|
849
|
+
"class": "logging.handlers.RotatingFileHandler",
|
|
850
|
+
"level": level,
|
|
851
|
+
"formatter": "json" if use_json else "standard",
|
|
852
|
+
"filename": "app.log",
|
|
853
|
+
"maxBytes": 10485760, # 10MB
|
|
854
|
+
"backupCount": 5
|
|
855
|
+
}
|
|
856
|
+
},
|
|
857
|
+
"loggers": {
|
|
858
|
+
"": { # Root logger
|
|
859
|
+
"level": level,
|
|
860
|
+
"handlers": ["console", "file"]
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
logging.config.dictConfig(config)
|
|
866
|
+
|
|
867
|
+
# Usage
|
|
868
|
+
logger = logging.getLogger(__name__)
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
## Performance Optimization
|
|
872
|
+
|
|
873
|
+
### Profiling and Optimization
|
|
874
|
+
```python
|
|
875
|
+
# src/profiling.py
|
|
876
|
+
import cProfile
|
|
877
|
+
import functools
|
|
878
|
+
import time
|
|
879
|
+
from typing import Callable, TypeVar, Any
|
|
880
|
+
from memory_profiler import profile
|
|
881
|
+
|
|
882
|
+
F = TypeVar('F', bound=Callable[..., Any])
|
|
883
|
+
|
|
884
|
+
def timing_decorator(func: F) -> F:
|
|
885
|
+
"""Decorator to measure function execution time."""
|
|
886
|
+
@functools.wraps(func)
|
|
887
|
+
def wrapper(*args, **kwargs) -> Any:
|
|
888
|
+
start_time = time.perf_counter()
|
|
889
|
+
result = func(*args, **kwargs)
|
|
890
|
+
end_time = time.perf_counter()
|
|
891
|
+
execution_time = end_time - start_time
|
|
892
|
+
logger.info(f"{func.__name__} executed in {execution_time:.4f} seconds")
|
|
893
|
+
return result
|
|
894
|
+
return wrapper
|
|
895
|
+
|
|
896
|
+
def profile_function(func: F) -> F:
|
|
897
|
+
"""Decorator to profile function performance."""
|
|
898
|
+
@functools.wraps(func)
|
|
899
|
+
def wrapper(*args, **kwargs) -> Any:
|
|
900
|
+
profiler = cProfile.Profile()
|
|
901
|
+
profiler.enable()
|
|
902
|
+
result = func(*args, **kwargs)
|
|
903
|
+
profiler.disable()
|
|
904
|
+
profiler.dump_stats(f"{func.__name__}_profile.prof")
|
|
905
|
+
return result
|
|
906
|
+
return wrapper
|
|
907
|
+
|
|
908
|
+
# Memory optimization techniques
|
|
909
|
+
class MemoryOptimizedClass:
|
|
910
|
+
"""Example of memory optimization using __slots__."""
|
|
911
|
+
__slots__ = ['id', 'name', 'value']
|
|
912
|
+
|
|
913
|
+
def __init__(self, id: str, name: str, value: int) -> None:
|
|
914
|
+
self.id = id
|
|
915
|
+
self.name = name
|
|
916
|
+
self.value = value
|
|
917
|
+
|
|
918
|
+
# Generator for memory-efficient iteration
|
|
919
|
+
def read_large_file(filename: str) -> Generator[str, None, None]:
|
|
920
|
+
"""Memory-efficient file reading using generators."""
|
|
921
|
+
with open(filename, 'r', encoding='utf-8') as file:
|
|
922
|
+
for line in file:
|
|
923
|
+
yield line.strip()
|
|
924
|
+
|
|
925
|
+
# Caching decorator
|
|
926
|
+
def lru_cache_with_ttl(maxsize: int = 128, ttl: int = 3600):
|
|
927
|
+
"""LRU cache with time-to-live."""
|
|
928
|
+
def decorator(func: F) -> F:
|
|
929
|
+
cache: Dict[str, tuple] = {}
|
|
930
|
+
|
|
931
|
+
@functools.wraps(func)
|
|
932
|
+
def wrapper(*args, **kwargs) -> Any:
|
|
933
|
+
key = str(args) + str(sorted(kwargs.items()))
|
|
934
|
+
current_time = time.time()
|
|
935
|
+
|
|
936
|
+
if key in cache:
|
|
937
|
+
result, timestamp = cache[key]
|
|
938
|
+
if current_time - timestamp < ttl:
|
|
939
|
+
return result
|
|
940
|
+
else:
|
|
941
|
+
del cache[key]
|
|
942
|
+
|
|
943
|
+
result = func(*args, **kwargs)
|
|
944
|
+
|
|
945
|
+
if len(cache) >= maxsize:
|
|
946
|
+
# Remove oldest entry
|
|
947
|
+
oldest_key = min(cache.keys(), key=lambda k: cache[k][1])
|
|
948
|
+
del cache[oldest_key]
|
|
949
|
+
|
|
950
|
+
cache[key] = (result, current_time)
|
|
951
|
+
return result
|
|
952
|
+
|
|
953
|
+
return wrapper
|
|
954
|
+
return decorator
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
## Documentation with Sphinx
|
|
958
|
+
|
|
959
|
+
### Sphinx Configuration (docs/conf.py)
|
|
960
|
+
```python
|
|
961
|
+
import os
|
|
962
|
+
import sys
|
|
963
|
+
sys.path.insert(0, os.path.abspath('../src'))
|
|
964
|
+
|
|
965
|
+
project = 'Python Project'
|
|
966
|
+
copyright = '2024, Your Name'
|
|
967
|
+
author = 'Your Name'
|
|
968
|
+
release = '0.1.0'
|
|
969
|
+
|
|
970
|
+
extensions = [
|
|
971
|
+
'sphinx.ext.autodoc',
|
|
972
|
+
'sphinx.ext.viewcode',
|
|
973
|
+
'sphinx.ext.napoleon',
|
|
974
|
+
'sphinx.ext.intersphinx',
|
|
975
|
+
'sphinx.ext.coverage',
|
|
976
|
+
]
|
|
977
|
+
|
|
978
|
+
templates_path = ['_templates']
|
|
979
|
+
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
|
980
|
+
|
|
981
|
+
html_theme = 'sphinx_rtd_theme'
|
|
982
|
+
html_static_path = ['_static']
|
|
983
|
+
|
|
984
|
+
autodoc_default_options = {
|
|
985
|
+
'members': True,
|
|
986
|
+
'member-order': 'bysource',
|
|
987
|
+
'special-members': '__init__',
|
|
988
|
+
'undoc-members': True,
|
|
989
|
+
'exclude-members': '__weakref__'
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
napoleon_google_docstring = True
|
|
993
|
+
napoleon_numpy_docstring = True
|
|
994
|
+
napoleon_include_init_with_doc = False
|
|
995
|
+
napoleon_include_private_with_doc = False
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
### Docstring Examples
|
|
999
|
+
```python
|
|
1000
|
+
# src/user_service.py
|
|
1001
|
+
from typing import List, Optional
|
|
1002
|
+
from .models import User
|
|
1003
|
+
from .exceptions import NotFoundError, ValidationError
|
|
1004
|
+
|
|
1005
|
+
class UserService:
|
|
1006
|
+
"""
|
|
1007
|
+
Service class for managing user operations.
|
|
1008
|
+
|
|
1009
|
+
This class provides methods for creating, updating, and retrieving users
|
|
1010
|
+
from the database with proper validation and error handling.
|
|
1011
|
+
|
|
1012
|
+
Args:
|
|
1013
|
+
database: Database connection instance
|
|
1014
|
+
validator: User data validator instance
|
|
1015
|
+
|
|
1016
|
+
Example:
|
|
1017
|
+
>>> service = UserService(database=db, validator=validator)
|
|
1018
|
+
>>> user = service.create_user({"name": "John", "email": "john@example.com"})
|
|
1019
|
+
>>> print(user.name)
|
|
1020
|
+
John
|
|
1021
|
+
"""
|
|
1022
|
+
|
|
1023
|
+
def __init__(self, database, validator) -> None:
|
|
1024
|
+
self.database = database
|
|
1025
|
+
self.validator = validator
|
|
1026
|
+
|
|
1027
|
+
def create_user(self, user_data: dict) -> User:
|
|
1028
|
+
"""
|
|
1029
|
+
Create a new user with the provided data.
|
|
1030
|
+
|
|
1031
|
+
Args:
|
|
1032
|
+
user_data: Dictionary containing user information with keys:
|
|
1033
|
+
- name (str): User's full name
|
|
1034
|
+
- email (str): User's email address
|
|
1035
|
+
- age (int, optional): User's age
|
|
1036
|
+
|
|
1037
|
+
Returns:
|
|
1038
|
+
User: The created user instance with generated ID and timestamps
|
|
1039
|
+
|
|
1040
|
+
Raises:
|
|
1041
|
+
ValidationError: If user data is invalid or email format is incorrect
|
|
1042
|
+
DatabaseError: If database operation fails
|
|
1043
|
+
|
|
1044
|
+
Example:
|
|
1045
|
+
>>> user_data = {"name": "Alice Smith", "email": "alice@example.com"}
|
|
1046
|
+
>>> user = service.create_user(user_data)
|
|
1047
|
+
>>> assert user.email == "alice@example.com"
|
|
1048
|
+
"""
|
|
1049
|
+
if not self.validator.validate_user_data(user_data):
|
|
1050
|
+
raise ValidationError("Invalid user data provided")
|
|
1051
|
+
|
|
1052
|
+
return self.database.save_user(user_data)
|
|
1053
|
+
|
|
1054
|
+
def get_user_by_id(self, user_id: str) -> Optional[User]:
|
|
1055
|
+
"""
|
|
1056
|
+
Retrieve a user by their unique identifier.
|
|
1057
|
+
|
|
1058
|
+
Args:
|
|
1059
|
+
user_id: The unique identifier for the user
|
|
1060
|
+
|
|
1061
|
+
Returns:
|
|
1062
|
+
The user instance if found, None otherwise
|
|
1063
|
+
|
|
1064
|
+
Raises:
|
|
1065
|
+
DatabaseError: If database query fails
|
|
1066
|
+
|
|
1067
|
+
Note:
|
|
1068
|
+
This method returns None if the user is not found, rather than
|
|
1069
|
+
raising an exception. Use get_user_by_id_strict() if you want
|
|
1070
|
+
an exception to be raised for missing users.
|
|
1071
|
+
"""
|
|
1072
|
+
return self.database.find_user_by_id(user_id)
|
|
1073
|
+
```
|
|
1074
|
+
|
|
1075
|
+
## CI/CD Configuration
|
|
1076
|
+
|
|
1077
|
+
### GitHub Actions (.github/workflows/python.yml)
|
|
1078
|
+
```yaml
|
|
1079
|
+
name: Python CI
|
|
1080
|
+
|
|
1081
|
+
on:
|
|
1082
|
+
push:
|
|
1083
|
+
branches: [ main, develop ]
|
|
1084
|
+
pull_request:
|
|
1085
|
+
branches: [ main ]
|
|
1086
|
+
|
|
1087
|
+
jobs:
|
|
1088
|
+
test:
|
|
1089
|
+
runs-on: ubuntu-latest
|
|
1090
|
+
strategy:
|
|
1091
|
+
matrix:
|
|
1092
|
+
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
|
|
1093
|
+
|
|
1094
|
+
steps:
|
|
1095
|
+
- uses: actions/checkout@v4
|
|
1096
|
+
|
|
1097
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
1098
|
+
uses: actions/setup-python@v4
|
|
1099
|
+
with:
|
|
1100
|
+
python-version: ${{ matrix.python-version }}
|
|
1101
|
+
|
|
1102
|
+
- name: Install dependencies
|
|
1103
|
+
run: |
|
|
1104
|
+
python -m pip install --upgrade pip
|
|
1105
|
+
pip install -r requirements-dev.txt
|
|
1106
|
+
pip install -e .
|
|
1107
|
+
|
|
1108
|
+
- name: Lint with flake8
|
|
1109
|
+
run: |
|
|
1110
|
+
flake8 src/ tests/
|
|
1111
|
+
|
|
1112
|
+
- name: Format check with black
|
|
1113
|
+
run: |
|
|
1114
|
+
black --check src/ tests/
|
|
1115
|
+
|
|
1116
|
+
- name: Import sorting check with isort
|
|
1117
|
+
run: |
|
|
1118
|
+
isort --check-only src/ tests/
|
|
1119
|
+
|
|
1120
|
+
- name: Type check with mypy
|
|
1121
|
+
run: |
|
|
1122
|
+
mypy src/
|
|
1123
|
+
|
|
1124
|
+
- name: Security check with bandit
|
|
1125
|
+
run: |
|
|
1126
|
+
bandit -r src/
|
|
1127
|
+
|
|
1128
|
+
- name: Test with pytest
|
|
1129
|
+
run: |
|
|
1130
|
+
pytest --cov=src --cov-report=xml --cov-report=term-missing
|
|
1131
|
+
|
|
1132
|
+
- name: Upload coverage to Codecov
|
|
1133
|
+
uses: codecov/codecov-action@v3
|
|
1134
|
+
with:
|
|
1135
|
+
file: ./coverage.xml
|
|
1136
|
+
|
|
1137
|
+
security:
|
|
1138
|
+
runs-on: ubuntu-latest
|
|
1139
|
+
steps:
|
|
1140
|
+
- uses: actions/checkout@v4
|
|
1141
|
+
- name: Set up Python
|
|
1142
|
+
uses: actions/setup-python@v4
|
|
1143
|
+
with:
|
|
1144
|
+
python-version: '3.11'
|
|
1145
|
+
|
|
1146
|
+
- name: Install dependencies
|
|
1147
|
+
run: |
|
|
1148
|
+
python -m pip install --upgrade pip
|
|
1149
|
+
pip install safety bandit
|
|
1150
|
+
|
|
1151
|
+
- name: Security audit with safety
|
|
1152
|
+
run: |
|
|
1153
|
+
safety check
|
|
1154
|
+
|
|
1155
|
+
- name: Security analysis with bandit
|
|
1156
|
+
run: |
|
|
1157
|
+
bandit -r src/
|
|
1158
|
+
```
|
|
1159
|
+
|
|
1160
|
+
### Tox Configuration (tox.ini)
|
|
1161
|
+
```ini
|
|
1162
|
+
[tox]
|
|
1163
|
+
envlist = py38,py39,py310,py311,py312,lint,type-check,security
|
|
1164
|
+
isolated_build = true
|
|
1165
|
+
|
|
1166
|
+
[testenv]
|
|
1167
|
+
deps =
|
|
1168
|
+
pytest>=7.0.0
|
|
1169
|
+
pytest-cov>=4.0.0
|
|
1170
|
+
pytest-mock>=3.10.0
|
|
1171
|
+
commands = pytest {posargs}
|
|
1172
|
+
|
|
1173
|
+
[testenv:lint]
|
|
1174
|
+
deps =
|
|
1175
|
+
flake8>=5.0.0
|
|
1176
|
+
black>=22.0.0
|
|
1177
|
+
isort>=5.10.0
|
|
1178
|
+
commands =
|
|
1179
|
+
flake8 src/ tests/
|
|
1180
|
+
black --check src/ tests/
|
|
1181
|
+
isort --check-only src/ tests/
|
|
1182
|
+
|
|
1183
|
+
[testenv:type-check]
|
|
1184
|
+
deps = mypy>=1.0.0
|
|
1185
|
+
commands = mypy src/
|
|
1186
|
+
|
|
1187
|
+
[testenv:security]
|
|
1188
|
+
deps =
|
|
1189
|
+
bandit>=1.7.0
|
|
1190
|
+
safety>=2.0.0
|
|
1191
|
+
commands =
|
|
1192
|
+
bandit -r src/
|
|
1193
|
+
safety check
|
|
1194
|
+
|
|
1195
|
+
[testenv:docs]
|
|
1196
|
+
deps =
|
|
1197
|
+
sphinx>=5.0.0
|
|
1198
|
+
sphinx-rtd-theme>=1.0.0
|
|
1199
|
+
commands = sphinx-build -b html docs docs/_build/html
|
|
1200
|
+
```
|
|
1201
|
+
|
|
1202
|
+
## Support Resources
|
|
1203
|
+
|
|
1204
|
+
- **Python Documentation**: https://docs.python.org/3/
|
|
1205
|
+
- **PEP 8 Style Guide**: https://peps.python.org/pep-0008/
|
|
1206
|
+
- **Pytest Documentation**: https://docs.pytest.org/
|
|
1207
|
+
- **Type Hints Guide**: https://docs.python.org/3/library/typing.html
|
|
1208
|
+
- **Mypy Documentation**: https://mypy.readthedocs.io/
|
|
1209
|
+
- **Black Formatter**: https://black.readthedocs.io/
|
|
1210
|
+
- **Sphinx Documentation**: https://www.sphinx-doc.org/
|
|
1211
|
+
|
|
1212
|
+
---
|
|
1213
|
+
|
|
1214
|
+
Remember: **Claude Flow coordinates, Claude Code creates Python!**
|