-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
836 lines (745 loc) · 29.8 KB
/
Copy pathpyproject.toml
File metadata and controls
836 lines (745 loc) · 29.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
# NOTE: This project uses UV as the package manager.
# Dependencies are defined in [project.dependencies] and [project.optional-dependencies] sections below.
# UV uses standard PEP 621 pyproject.toml format with uv.lock for reproducible builds.
[project]
name = "python-libs"
version = "0.1.0"
description = "Shared Python libraries for ByronWilliamsCPA projects - JWT auth, GCS utilities, and more"
authors = [
{name = "Byron Williams", email = "byronawilliams@gmail.com"}
]
readme = "README.md"
requires-python = ">=3.10,<3.15"
license = {text = "MIT"}
keywords = []
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.12",
]
# Root workspace has no direct production dependencies
# All production deps are in individual packages (packages/*/pyproject.toml)
dependencies = [
# Shared utilities only - packages define their own deps
"pydantic>=2.0.0",
"pydantic-settings>=2.0.0",
"structlog>=23.1.0",
"rich>=13.5.0",
# Cross-Version Compatibility Dependencies
# =========================================
# This template targets Python 3.10-3.14. Add version-specific dependencies
# here if your code needs compatibility shims or replacements.
#
# COMMON BACKPORTS FOR 3.10 COMPATIBILITY:
# "tomli>=2.0.0; python_version < '3.11'", # TOML parser (tomllib added in 3.11)
# "exceptiongroup>=1.1.0; python_version < '3.11'", # Exception groups (added in 3.11)
# "typing-extensions>=4.12.0", # Backport newer typing features
#
# AVAILABLE IN 3.11+:
# - tomllib: Native TOML parser
# - asyncio.TaskGroup: Structured concurrency
# - typing.Self, TypeVarTuple, Never, LiteralString
# - ExceptionGroup and except* syntax
#
# PEP 594 REMOVALS IN 3.13 (add replacements if needed):
# Removed modules: aifc, audioop, cgi, cgitb, chunk, crypt, imghdr, mailcap,
# msilib, nis, nntplib, ossaudiodev, pipes, sndhdr, spwd, sunau, telnetlib,
# uu, xdrlib
#
# Examples of version-specific dependencies:
# # Backport for Python 3.10
# "tomli>=2.0.0; python_version < '3.11'",
#
# # Replacement for removed modules in 3.13+
# "legacy-cgi>=2.6.1; python_version >= '3.13'", # If you need cgi module
# "filetype>=1.2.0", # Better alternative to imghdr/sndhdr
#
# # Typing enhancements
# "typing-extensions>=4.12.0; python_version < '3.13'", # For latest typing features
#
# PYTHON 3.14+ CONSIDERATIONS:
# - from __future__ import annotations is deprecated (but still works until 2029+)
# - Free-threaded mode (python3.14t) may need GIL-compatible packages
# - NotImplemented in boolean context raises TypeError (was warning)
# - PEP 649: Deferred annotation evaluation (impacts runtime introspection)
#
# Examples for 3.14+ compatibility:
# # Free-threaded mode support (check package documentation)
# "numpy>=2.1.0; python_version >= '3.14'", # Supports free-threaded mode
#
# UV handles these automatically based on the Python version being used.
# See: https://docs.astral.sh/uv/concepts/dependencies/#dependency-specifiers
]
# Optional dependency groups
[project.optional-dependencies]
# Development dependencies
dev = [
# Testing
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"pytest-asyncio>=0.21.0",
"pytest-xdist>=3.3.0",
"hypothesis>=6.82.0",
# Code Quality (always included)
"ruff>=0.9.0",
"basedpyright>=1.18.0", # Stricter type checker (replaces mypy)
"bandit>=1.7.0",
"vulture>=2.11", # Dead code detection
"pip-audit>=2.7.0", # Python vulnerability scanning
"pydoclint>=0.8.4", # Docstring argument validation
# Pre-commit
"pre-commit>=3.3.0",
# Documentation
"mkdocs>=1.6.0",
"mkdocs-material>=9.5.0",
"mkdocstrings[python]>=0.26.0",
"griffe-pydantic>=1.1.0",
"mkdocs-gen-files>=0.5.0",
"mkdocs-section-index>=0.3.0",
"mkdocs-autorefs>=1.2.0",
"mkdocs-git-revision-date-localized-plugin>=1.3.0",
"python-frontmatter>=1.1.0",
"ruamel-yaml>=0.18.0",
# Development Tools
"interrogate>=1.7.0",
"jupyter>=1.0.0",
"ipykernel>=6.25.0",
"safety>=3.7.0",
"nox>=2024.10.16", # Fixed: was 2025 (typo)
"nox-uv>=0.6.3", # Fixed: max available version is 0.6.3, not 1.0.0
# Google Cloud Assured OSS (optional - uncomment if using Assured OSS)
"google-auth>=2.0.0",
# "google-cloud-assured-oss>=0.1.0", # Package not yet available in PyPI
"google-api-core>=2.0.0",
"python-dotenv>=1.0.0", # For loading .env files
# Package dependencies for type checking
# These are optional deps from workspace packages needed for basedpyright
"fastapi>=0.100.0",
"starlette>=0.27.0",
"redis>=5.0.0",
"google-cloud-storage>=2.10.0",
"google-genai>=1.0.0",
"email-validator>=2.0.0",
"pyjwt>=2.8.0",
"cryptography>=41.0.0",
"httpx>=0.25.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
# Root package is for shared utilities only; main code is in packages/*
packages = ["src/python_libs"]
# Note: Individual packages (packages/*/pyproject.toml) define their own build targets
# Ruff Configuration - Consolidated Linting & Formatting
[tool.ruff]
line-length = 88
target-version = "py312"
exclude = [
".git",
".mypy_cache",
".ruff_cache",
".venv",
"__pycache__",
"dist",
"build",
]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
docstring-code-format = true
docstring-code-line-length = "dynamic"
[tool.ruff.lint]
# Rule selection aligned with Google Python Style Guide + PyStrict enhancements
# Reference: https://google.github.io/styleguide/pyguide.html
# Reference: https://github.com/Ranteck/PyStrict-strict-python
select = [
# Core Python style (Google-aligned)
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # Pyflakes
"I", # isort (import sorting)
"N", # pep8-naming (Google naming conventions)
"D", # pydocstyle (Google docstring style)
"UP", # pyupgrade (modern Python syntax)
# Type annotations (Google requires type hints)
"ANN", # flake8-annotations (type hint enforcement)
"TCH", # flake8-type-checking (TYPE_CHECKING imports)
"FA", # flake8-future-annotations (use from __future__ import annotations)
# Code quality (Pylint-equivalent rules)
"C4", # flake8-comprehensions
"C90", # mccabe complexity
"PL", # Pylint rules (Google uses Pylint)
"B", # flake8-bugbear
"SIM", # flake8-simplify
"ARG", # flake8-unused-arguments
"RET", # flake8-return
"PIE", # flake8-pie
# Security
"S", # flake8-bandit
# Best practices
"T10", # flake8-debugger (no debugger statements in production)
"T20", # flake8-print (no print in production)
"PT", # flake8-pytest-style
"Q", # flake8-quotes
"PTH", # flake8-use-pathlib
"A", # flake8-builtins
"DTZ", # flake8-datetimez
# Performance and modernization
"PERF", # Performance anti-patterns
"FURB", # Refurb - modernization
# Additional quality
"LOG", # Logging best practices
"G", # flake8-logging-format (logging string formatting)
"TRY", # Exception handling
"ERA", # Commented-out code
"FBT", # Boolean trap detection
"ASYNC",# Async/await best practices
"RUF", # Ruff-specific rules
# PyStrict additions (stricter standards)
"BLE", # flake8-blind-except (no bare except or except Exception)
"EM", # flake8-errmsg (error message best practices)
"SLF", # flake8-self (private member access)
"INP", # flake8-no-pep420 (require __init__.py in packages)
"ISC", # flake8-implicit-str-concat (implicit string concatenation)
"PGH", # pygrep-hooks (deprecated type comments, blanket ignores)
"RSE", # flake8-raise (raise statement best practices)
"TID", # flake8-tidy-imports (banned imports, relative imports)
"YTT", # flake8-2020 (Python version checks)
]
ignore = [
# Formatting (handled by ruff format)
"E501", # line too long (handled by formatter)
"COM812", # missing trailing comma (handled by formatter)
"ISC001", # implicit string concatenation (handled by formatter)
# Docstring style (Google convention conflicts)
"D203", # one-blank-line-before-class (conflicts with D211)
"D212", # multi-line-summary-first-line (conflicts with D213)
"D105", # missing docstring in magic method (__str__, etc.)
"D107", # missing docstring in __init__ (class docstring sufficient)
# Type annotations (pragmatic exceptions)
# Note: ANN101/ANN102 removed - rules deprecated in Ruff (self/cls annotation not needed)
"ANN401", # dynamically typed expressions (Any) - sometimes necessary
# Pylint rules (too strict for all cases)
"PLR0913", # too many arguments (>5) - sometimes necessary for APIs
"PLR2004", # magic value comparison - too noisy
"PLW2901", # outer loop variable overwritten - sometimes intentional
# Practical exceptions
"B008", # function calls in defaults (Pydantic/FastAPI pattern)
"S101", # assert (pytest uses assert statements)
"PTH123", # open() vs pathlib (sometimes direct open is clearer)
"FBT001", # Boolean positional arg (acceptable in DSLs)
"FBT002", # Boolean default arg (acceptable in DSLs)
"TRY003", # Long exception messages (descriptive is good)
# Python 3.10 compatibility (packages support Python 3.10+)
"UP017", # Use datetime.UTC alias (not available in Python 3.10)
]
# McCabe Complexity Configuration (Google/Pylint alignment)
[tool.ruff.lint.mccabe]
max-complexity = 10 # Google/Pylint default
# Pylint Configuration (Function complexity limits)
[tool.ruff.lint.pylint]
max-statements = 100 # Function length hard limit
max-branches = 12 # Nesting/branching limit
max-nested-blocks = 4 # Explicit nesting limit
max-returns = 6 # Return statement limit
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.ruff.lint.isort]
known-first-party = ["python_libs", "cloudflare_auth", "gcs_utilities", "gemini_image"]
[tool.ruff.lint.per-file-ignores]
# Module init files
"__init__.py" = ["F401", "D104"]
# Test files (relaxed rules for test code)
"tests/**/*.py" = [
"ANN", # Type annotations not required in tests
"ARG", # Unused arguments (fixtures)
"D", # Docstrings not required in tests
"PLR", # Pylint refactor suggestions
"PLC0415", # Imports inside test functions are idiomatic
"ERA", # Commented code (test debugging)
"SLF", # Private member access (testing internals)
"BLE", # Blind except (test error handling)
"EM", # Error messages (test exceptions)
"TRY", # Exception handling (test assertions)
"INP", # No __init__.py required for test directories
# Security rules OK to skip in tests (specific, not blanket S)
"S101", # assert_used - pytest uses asserts
"S105", # hardcoded_password_string - test credentials are fake
"S106", # hardcoded_password_funcarg - test fixtures with fake passwords
"S107", # hardcoded_password_default - test default values
"S108", # hardcoded_tmp_directory - test temp paths are intentional
"S311", # random - non-crypto random in tests is fine
"S113", # request_without_timeout - test HTTP calls may be mocked
]
# Package test files (same relaxed rules as above)
"packages/*/tests/**/*.py" = [
"ANN", # Type annotations not required in tests
"ARG", # Unused arguments (fixtures)
"D", # Docstrings not required in tests
"PLR", # Pylint refactor suggestions
"PLC0415", # Imports inside test functions are idiomatic
"ERA", # Commented code (test debugging)
"SLF", # Private member access (testing internals)
"BLE", # Blind except (test error handling)
"EM", # Error messages (test exceptions)
"TRY", # Exception handling (test assertions)
"INP", # No __init__.py required for test directories
"PT011", # pytest.raises match parameter (not always needed)
"F841", # Unused variables (test setup/teardown)
# Security rules OK to skip in tests (specific, not blanket S)
"S101", # assert_used - pytest uses asserts
"S105", # hardcoded_password_string - test credentials are fake
"S106", # hardcoded_password_funcarg - test fixtures with fake passwords
"S107", # hardcoded_password_default - test default values
"S108", # hardcoded_tmp_directory - test temp paths are intentional
"S311", # random - non-crypto random in tests is fine
"S113", # request_without_timeout - test HTTP calls may be mocked
]
# Scripts (utility code - not packages)
"scripts/**/*.py" = [
"ANN", "D", "T20", "TRY", "PTH", "PLR",
"INP", # Scripts are not packages
"EM", # Utility scripts don't need perfect error messages
"T10", # Debugger allowed during script development
"BLE", # Blind except (error handling in scripts)
"C901", # Complexity allowed in utility scripts
"RUF012", # Class variable annotations (not needed in scripts)
"SIM", # Simplification suggestions (scripts prioritize clarity)
"F821", # Allow dynamic imports
"G201", # Logging patterns (scripts may use .error with exc_info)
# Security rules OK to skip in scripts (specific, not blanket S)
"S101", # assert_used - scripts may use asserts for validation
"S104", # hardcoded_bind_all_interfaces - dev scripts may bind 0.0.0.0
"S108", # hardcoded_tmp_directory - scripts use /tmp intentionally
"S311", # random - non-crypto random in scripts is fine
"S603", # subprocess_without_shell_equals_true - scripts validate inputs
"S607", # start_process_with_partial_path - scripts use PATH
]
# CLI files (command-line interfaces use print for output)
"**/cli.py" = [
"T20", # Print statements are expected in CLI tools
]
# Benchmarks (performance testing)
"benchmarks/**/*.py" = [
"ANN", "D", "T20", "ARG", "TRY", "PLR",
"INP", # Benchmarks are not packages
"EM", # Benchmark exceptions
]
# Tools (development utilities)
"tools/**/*.py" = [
"ANN", "D", "T20", "TRY", "PLR",
"INP", # Tools are not packages
"EM", # Tool exceptions
"BLE", # Blind except (error handling in tools)
"C901", # Complexity allowed in utility scripts
]
# Nox configuration
"noxfile.py" = ["ANN", "D", "T20", "PLR", "INP", "PLC0415", "ERA001", "SIM105"]
# Fuzz testing (Atheris harnesses have specific patterns)
"fuzz/**/*.py" = [
"N802", # TestOneInput required by Atheris
"S110", # try-except-pass is intentional for fuzzing
"BLE", # Blind except is necessary in fuzz targets
"INP", # Fuzz tests are not packages
"ANN", "D", "TRY",
]
# Claude skills and scripts
".claude/**/*.py" = [
"T20", # Print allowed for CLI output
"C901", # Complexity allowed in utility scripts
"ANN", "D", "TRY", "PLR",
"INP", # Not packages
]
# API health checks - Example code with template patterns
"src/*/api/health.py" = [
"ERA001", # Commented code shows implementation examples
"BLE001", # Blind except in health checks for maximum resilience
"PLC0415", # Local imports to avoid circular dependencies
]
# Security middleware - SSRF protection with intentional patterns
"src/*/middleware/security.py" = [
"S104", # 0.0.0.0 in BLOCKED_HOSTS list is intentional
"BLE001", # Blind except for URL parsing resilience
"PLC0415", # Local imports to avoid circular dependencies
"TRY300", # Return in try block is clearer for simple cases
"ANN001", # call_next typing is complex (Starlette middleware)
"RUF012", # ClassVar not needed for constants
"C416", # Dict comprehension is clearer than dict()
"SIM102", # Nested if is more readable for security checks
]
# Financial utilities - Template documentation style
"src/*/utils/financial.py" = [
"D200", # Multi-line docstring for template documentation
]
# Logging utilities - Structlog processor interface
"src/*/utils/logging.py" = [
"ARG001", # Unused args required by structlog processor interface
"TC002", # Processor needs to be runtime-available
]
# Quality gate script - Intentional URL handling
"scripts/check_quality_gate.py" = [
"S310", # URL schemes are validated before use (see nosec comment)
]
# Cloudflare auth middleware - Complex authentication logic
"packages/cloudflare-auth/src/cloudflare_auth/middleware*.py" = [
"TRY300", # Return in try block is clearer for auth flow
"TRY301", # Raising in try block is standard for auth middleware
"PLC0415", # Local imports to avoid circular dependencies
]
# Cloudflare auth whitelist - Validation logic
"packages/cloudflare-auth/src/cloudflare_auth/whitelist.py" = [
"TRY300", # Return in try block is clearer
"TRY301", # Raising in try block is standard
"TRY401", # Exception in log is intentional for audit
"SLF001", # Internal access to validator internals is intentional
"PGH003", # Generic type ignore is acceptable for optional import
"PERF401", # List comprehension vs append is clearer here
]
# Cloudflare auth redis sessions - Session management logic
"packages/cloudflare-auth/src/cloudflare_auth/redis_sessions.py" = [
"TRY300", # Return in try block is clearer for session flow
"TRY401", # Exception in log message is intentional
]
# Cloudflare auth security helpers - Security patterns
"packages/cloudflare-auth/src/cloudflare_auth/security_helpers.py" = [
"G201", # Using .error with exc_info is intentional for security logging
"TRY300", # Return patterns in try blocks
"SLF001", # Function attribute pattern for singleton
]
# Cloudflare auth validators - JWT validation logic
"packages/cloudflare-auth/src/cloudflare_auth/validators.py" = [
"TRY300", # Return in try block is clearer for validation
"TRY301", # Raising in try block is standard for validation
"TRY401", # Exception in log is intentional
]
# Cloudflare auth utils - Utility functions
"packages/cloudflare-auth/src/cloudflare_auth/utils.py" = [
"BLE001", # Blind except is intentional for resilient parsing
"ANN001", # Regex match type annotation not needed
"ANN202", # Private function return type annotation not needed
]
# Cloudflare auth tests - Test patterns
"packages/cloudflare-auth/tests/*.py" = [
"ANN201", # Return type annotations not needed for fixtures
"PERF401", # List comprehension vs extend is fine in tests
]
# GCS utilities client - Storage operations
"packages/gcs-utilities/src/gcs_utilities/client.py" = [
"G004", # F-string logging is cleaner for GCS operations
"TRY300", # Return in try block is clearer for storage ops
"TRY301", # Raising in try block is standard for storage errors
"TRY401", # Exception in log is intentional
"PTH101", # os.chmod preferred for credential file permissions
"PTH108", # os.unlink preferred for credential file cleanup
"PTH110", # os.path.exists preferred for credential file check
"PERF401", # List comprehension vs append is clearer here
]
# BasedPyright Configuration
# Replaces MyPy with faster, stricter type checking
# Reference: https://docs.basedpyright.com
[tool.basedpyright]
pythonVersion = "3.12"
pythonPlatform = "All"
# Type checking mode: basic, standard, strict, all
# "strict" aligns with Google Python Style Guide requirements
typeCheckingMode = "strict"
# Source paths
include = ["src", "packages/cloudflare-auth/src", "packages/gcs-utilities/src", "packages/gemini-image/src"]
exclude = [
"**/__pycache__",
"**/node_modules",
".venv",
"build",
"dist",
]
# Extra paths for workspace packages (allows basedpyright to find local packages)
extraPaths = [
"packages/cloudflare-auth/src",
"packages/gcs-utilities/src",
"packages/gemini-image/src",
]
# Strict mode customizations
reportMissingImports = "error"
reportMissingTypeStubs = "warning"
reportUnusedImport = "error"
reportUnusedClass = "error"
reportUnusedFunction = "error"
reportUnusedVariable = "error"
reportDuplicateImport = "error"
reportPrivateUsage = "warning"
reportTypeCommentUsage = "warning"
reportConstantRedefinition = "error"
reportIncompatibleMethodOverride = "error"
reportIncompatibleVariableOverride = "error"
reportInconsistentConstructor = "error"
reportOverlappingOverload = "error"
reportUninitializedInstanceVariable = "warning"
reportInvalidStringEscapeSequence = "error"
reportUnknownParameterType = "warning"
reportUnknownArgumentType = "warning"
reportUnknownLambdaType = "warning"
reportUnknownVariableType = "warning"
reportUnknownMemberType = "warning"
reportMissingParameterType = "warning"
reportMissingTypeArgument = "warning"
reportCallInDefaultInitializer = "warning"
reportUnnecessaryIsInstance = "warning"
reportUnnecessaryCast = "warning"
reportUnnecessaryComparison = "warning"
reportUnnecessaryContains = "warning"
reportAssertAlwaysTrue = "error"
reportSelfClsParameterName = "error"
reportImplicitStringConcatenation = "warning"
reportUndefinedVariable = "error"
reportUnboundVariable = "error"
reportUnhashable = "error"
reportInvalidTypeVarUse = "error"
# BasedPyright-specific enhancements
reportUnreachable = "error" # Detect unreachable code
reportAny = "warning" # Flag usage of Any type
reportExplicitAny = "warning" # Flag explicit Any annotations
reportIgnoreCommentWithoutRule = "warning" # Require specific ignore rules
# PyStrict strict inference settings
strictListInference = true # Infer list element types strictly
strictDictionaryInference = true # Infer dict key/value types strictly
strictSetInference = true # Infer set element types strictly
strictParameterNoneValue = true # Require explicit Optional for None defaults
analyzeUnannotatedFunctions = true # Analyze functions without type hints
deprecateTypingAliases = true # Warn on deprecated typing module aliases
# Pytest Configuration
[tool.pytest.ini_options]
minversion = "7.0"
pythonpath = [".", "src", "packages/cloudflare-auth/src", "packages/gcs-utilities/src", "packages/gemini-image/src"]
# Only include root tests in default testpaths to avoid conftest.py collisions
# Package tests should be run separately: uv run pytest packages/<name>/tests
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"-ra",
"--strict-markers",
"--strict-config",
"--cov=src/python_libs",
"--cov-report=html",
"--cov-report=term-missing:skip-covered",
"--cov-report=xml",
"--cov-fail-under=80",
]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
"integration: marks tests as integration tests",
"unit: marks tests as unit tests",
"benchmark: marks tests as benchmark tests",
"py310: marks tests specific to Python 3.10",
"py311plus: marks tests requiring Python 3.11+",
"py313plus: marks tests requiring Python 3.13+ (PEP 594 removals)",
"py314plus: marks tests requiring Python 3.14+ (free-threaded, PEP 649)",
]
# Coverage Configuration
# Note: Coverage source is specified via pytest's --cov argument in addopts above
[tool.coverage.run]
branch = true
relative_files = true # Required for SonarCloud in GitHub Actions
omit = [
# Test files
"*/tests/*",
"*/test_*.py",
# Python internals
"*/__pycache__/*",
"*/site-packages/*",
# Development artifacts (from image_detection best practices)
"validation/*", # Validation/verification scripts
"benchmarks/*", # Benchmarking framework
"data/*", # Data processing scripts
"scripts/*", # Utility scripts
"notebooks/*", # Jupyter notebooks
"tmp_cleanup/*", # Temporary files
]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"raise AssertionError",
"raise NotImplementedError",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]
precision = 2
show_missing = true
# Interrogate Configuration (Docstring Coverage)
[tool.interrogate]
verbose = 1
fail-under = 85
exclude = ["tests", "docs", "build", "dist"]
ignore-init-method = true
ignore-init-module = true
color = true
# Pydoclint Configuration (Docstring Argument Validation)
# Validates that docstring arguments match function signatures
# Reference: https://github.com/jsh9/pydoclint
[tool.pydoclint]
style = "google"
exclude = '\.git|tests/|scripts/|benchmarks/|tools/|noxfile\.py|\.claude/'
arg-type-hints-in-docstring = true
arg-type-hints-in-signature = true
skip-checking-raises = false
require-return-section-when-returning-nothing = false
require-return-section-when-returning-values = false
require-yield-section-when-yielding-values = false
# Mutation Testing Configuration (mutmut)
[tool.mutmut]
paths_to_mutate = "src/"
backup = false
runner = "uv run pytest -x --assert=plain -o addopts=''"
tests_dir = "tests/"
dict_synonyms = "Struct, NamedStruct"
# Bandit Security Configuration
# Run: uv run bandit -c pyproject.toml -r src/
# Reference: https://bandit.readthedocs.io/
[tool.bandit]
# Directories to exclude from scanning
exclude_dirs = [
"tests",
"scripts",
"benchmarks",
"tools",
"fuzz",
"docs",
".venv",
"venv",
"build",
"dist",
]
# Skip these checks (false positives or acceptable in context)
skips = [
"B101", # assert_used - pytest uses assert statements
"B104", # hardcoded_bind_all_interfaces - often intentional for dev servers
"B311", # random - non-crypto random is fine for non-security purposes
"B404", # import_subprocess - subprocess is needed, usage is checked
"B603", # subprocess_without_shell_equals_true - we validate inputs
]
# Targets to scan (can be overridden on command line)
targets = ["src"]
# Severity and confidence levels
# Run with -ll (medium+) or -lll (high only) for less noise
# These are applied when using -c pyproject.toml
[tool.bandit.assert_used]
skips = ["**/test_*.py", "**/*_test.py"]
# Vulture Configuration (Dead Code Detection)
# Detects unused code to maintain clean codebase
# Run: uv run vulture src/
[tool.vulture]
min_confidence = 80
paths = ["src/"]
exclude = [
"tests/",
"docs/",
".venv/",
"venv/",
"build/",
"dist/",
]
# Whitelist common false positives
ignore_names = [
"visit_*", # AST visitor methods
"setUp",
"tearDown",
"setUpClass",
"tearDownClass",
"__*__", # Magic methods
]
# UV Configuration
[tool.uv]
# Note: UV now recommends using [dependency-groups] instead of dev-dependencies
# We use [project.optional-dependencies] for dev dependencies (PEP 621 standard)
# UV Workspace Configuration - enables monorepo with multiple packages
[tool.uv.workspace]
members = ["packages/*"]
# Workspace source references - allow packages to depend on each other
[tool.uv.sources]
byronwilliamscpa-cloudflare-auth = { workspace = true }
byronwilliamscpa-cloudflare-api = { workspace = true }
byronwilliamscpa-gcs-utilities = { workspace = true }
byronwilliamscpa-gemini-image = { workspace = true }
# Package Index Configuration
# Google Assured OSS as primary source with PyPI fallback
# See .env.example for required Google Cloud credentials and configuration
#
# Indexes are configured at runtime via environment variables:
# - GOOGLE_CLOUD_PROJECT: Your GCP project ID
# - ASSURED_OSS_REGION: Region (us, europe, asia)
# - ASSURED_OSS_REPOSITORY: Repository name (default: assuredoss)
# - USE_ASSURED_OSS: Enable/disable Assured OSS (true/false)
#
# Index URL format:
# https://{ASSURED_OSS_REGION}-python.pkg.dev/{GOOGLE_CLOUD_PROJECT}/{ASSURED_OSS_REPOSITORY}/simple/
#
# UV automatically falls back to PyPI when packages are not found in Assured OSS.
# Authentication uses GOOGLE_APPLICATION_CREDENTIALS or GOOGLE_APPLICATION_CREDENTIALS_B64.
# Artifact Registry Publishing Configuration
# Used by `uv publish` to upload packages to private GCP Artifact Registry
# The publish URL is passed via CLI in the GitHub Actions workflow
# Format: https://{REGION}-python.pkg.dev/{PROJECT}/{REPOSITORY}/
#
# For local publishing, set environment variables and run:
# uv publish --publish-url https://us-central1-python.pkg.dev/assured-oss-457903/python-libs/
#
# Authentication is handled via gcloud credential helper or service account key.
# Semantic Release Configuration
# Automates versioning and changelog generation based on conventional commits
# Reference: https://python-semantic-release.readthedocs.io/
[tool.semantic_release]
# Version location in this file
version_toml = ["pyproject.toml:project.version"]
# Commit message parsing
commit_parser = "conventional_commits"
commit_parser_options = { parse_squash_commits = true, ignore_merge_commits = true }
# Version behavior
major_on_zero = false # Don't bump to 1.0.0 automatically
allow_zero_version = true # Allow 0.x.x versions
# Branches configuration
[tool.semantic_release.branches.main]
match = "(main|master)"
prerelease = false
[tool.semantic_release.branches.develop]
match = "develop"
prerelease = true
prerelease_token = "dev"
[tool.semantic_release.branches.release]
match = "release/*"
prerelease = true
prerelease_token = "rc"
# Changelog configuration
[tool.semantic_release.changelog]
template_dir = "templates"
changelog_file = "CHANGELOG.md"
exclude_commit_patterns = [
"^chore\\(release\\):",
"^ci:",
"^build:",
]
[tool.semantic_release.changelog.environment]
block_start_string = "{%"
block_end_string = "%}"
variable_start_string = "{{"
variable_end_string = "}}"
comment_start_string = "{#"
comment_end_string = "#}"
trim_blocks = true
lstrip_blocks = true
keep_trailing_newline = true
# Remote configuration
[tool.semantic_release.remote]
type = "github"
token = { env = "GH_TOKEN" }
# Publishing configuration
[tool.semantic_release.publish]
dist_glob_patterns = ["dist/*"]
upload_to_vcs_release = true