ruff-sync 0.1.6.dev1__tar.gz → 0.1.6.dev3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/plans/issue-116-config-validation.md +6 -6
  2. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/ruff-sync-usage/SKILL.md +3 -2
  3. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/ruff-sync-usage/references/troubleshooting.md +20 -0
  4. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/AGENTS.md +1 -0
  5. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/PKG-INFO +1 -1
  6. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/configuration.md +3 -0
  7. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/usage.md +4 -1
  8. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/pyproject.toml +1 -1
  9. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/core.py +1 -1
  10. ruff_sync-0.1.6.dev3/src/ruff_sync/validation.py +323 -0
  11. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_config_validation.py +238 -2
  12. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/uv.lock +1 -1
  13. ruff_sync-0.1.6.dev1/src/ruff_sync/validation.py +0 -125
  14. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/DEPENDENCIES.md +0 -0
  15. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/TESTING.md +0 -0
  16. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/decisions/0001-type-refactoring-strategy.md +0 -0
  17. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/decisions/0002-tui-node-ast.md +0 -0
  18. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/decisions/README.md +0 -0
  19. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/doc-fix.md +0 -0
  20. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/formatters-architecture.md +0 -0
  21. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/gitlab-reports.md +0 -0
  22. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/issue-102-context.md +0 -0
  23. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/plans/issue-100-roadmap-plan.md +0 -0
  24. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/ruff.toml +0 -0
  25. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/adr/SKILL.md +0 -0
  26. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/dirty-equals/SKILL.md +0 -0
  27. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/dirty-equals/references/common-matchers.md +0 -0
  28. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/dirty-equals/references/toml-matching.md +0 -0
  29. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/dirty-equals/trigger_eval.json +0 -0
  30. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/gh-issues/SKILL.md +0 -0
  31. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/mike/SKILL.md +0 -0
  32. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/mike/references/commands.md +0 -0
  33. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/mkdocs-generation/SKILL.md +0 -0
  34. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/mkdocs-generation/examples.md +0 -0
  35. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/mkdocs-generation/templates/api-reference.md +0 -0
  36. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/mkdocs-generation/templates/getting-started.md +0 -0
  37. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/mkdocs-generation/templates/index.md +0 -0
  38. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/mkdocs-generation/templates/mkdocs.yml +0 -0
  39. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/release-notes-generation/SKILL.md +0 -0
  40. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/ruff-sync-usage/references/ci-integration.md +0 -0
  41. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/ruff-sync-usage/references/configuration.md +0 -0
  42. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/skill-creator/SKILL.md +0 -0
  43. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/skill-creator/references/best-practices.md +0 -0
  44. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/skill-creator/references/evaluating-skills.md +0 -0
  45. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/skill-creator/references/optimizing-descriptions.md +0 -0
  46. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/skill-creator/references/quickstart.md +0 -0
  47. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/skill-creator/references/sources.md +0 -0
  48. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/skill-creator/references/using-scripts.md +0 -0
  49. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/skill-creator/scripts/scaffold_skill.py +0 -0
  50. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/textual/SKILL.md +0 -0
  51. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/textual/examples/basic_app.py +0 -0
  52. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/textual/examples/reactive_example.py +0 -0
  53. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/textual/references/events.md +0 -0
  54. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/textual/references/styling.md +0 -0
  55. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/textual/references/testing.md +0 -0
  56. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/textual/references/widgets.md +0 -0
  57. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/type-checking/SKILL.md +0 -0
  58. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/type-checking/evals.json +0 -0
  59. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/type-checking/references/advanced-narrowing.md +0 -0
  60. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/type-checking/references/error-code-lookup.md +0 -0
  61. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/type-checking/references/generics.md +0 -0
  62. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/type-checking/references/naming.md +0 -0
  63. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/type-checking/references/protocol-patterns.md +0 -0
  64. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/type-checking/references/quickstart.md +0 -0
  65. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/type-checking/references/refactoring-patterns.md +0 -0
  66. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/type-checking/scripts/audit_types.py +0 -0
  67. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/skills/warnings-control/SKILL.md +0 -0
  68. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/tui_design.md +0 -0
  69. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/tui_requirements.md +0 -0
  70. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/tui_rule_browsing.md +0 -0
  71. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/tui_rule_browsing_design.md +0 -0
  72. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/workflows/add-test-case.md +0 -0
  73. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.agents/workflows/update-screenshots.md +0 -0
  74. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.git-blame-ignore-revs +0 -0
  75. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.github/dependabot.yml +0 -0
  76. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.github/workflows/ci.yaml +0 -0
  77. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.github/workflows/complexity.yaml +0 -0
  78. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.gitignore +0 -0
  79. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.pre-commit-config.yaml +0 -0
  80. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/.pre-commit-hooks.yaml +0 -0
  81. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/CONTRIBUTING.md +0 -0
  82. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/LICENSE.md +0 -0
  83. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/README.md +0 -0
  84. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/codecov.yml +0 -0
  85. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/configs/data-science-engineering/ruff.toml +0 -0
  86. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/configs/fastapi/ruff.toml +0 -0
  87. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/configs/kitchen-sink/ruff.toml +0 -0
  88. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/agent-skill.md +0 -0
  89. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/favicon.png +0 -0
  90. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/github-job-summary.png +0 -0
  91. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/github-pr-annotation.png +0 -0
  92. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/inspect-main.png +0 -0
  93. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/inspect-search.png +0 -0
  94. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/logo.png +0 -0
  95. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/ruff_sync_banner.png +0 -0
  96. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/screenshots/dashboard.svg +0 -0
  97. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/screenshots/legend_help.svg +0 -0
  98. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/screenshots/rule_details.svg +0 -0
  99. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/screenshots/screenshot_sample.toml +0 -0
  100. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/assets/screenshots/search_omnibox.svg +0 -0
  101. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/best-practices.md +0 -0
  102. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/ci-integration.md +0 -0
  103. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/contributing.md +0 -0
  104. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/examples/advanced-config.toml +0 -0
  105. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/examples/basic-config.toml +0 -0
  106. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/gen_ref_pages.py +0 -0
  107. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/index.md +0 -0
  108. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/inspect.md +0 -0
  109. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/installation.md +0 -0
  110. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/overrides/main.html +0 -0
  111. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/overrides/partials/version_warning.html +0 -0
  112. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/pre-commit.md +0 -0
  113. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/pre-defined-configs.md +0 -0
  114. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/troubleshooting.md +0 -0
  115. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/docs/url-resolution.md +0 -0
  116. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/mkdocs.yml +0 -0
  117. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/scripts/check_dogfood.sh +0 -0
  118. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/scripts/generate_tui_screenshots.py +0 -0
  119. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/scripts/gitclone_dogfood.sh +0 -0
  120. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/scripts/pull_dogfood.sh +0 -0
  121. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/skills-lock.json +0 -0
  122. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/__init__.py +0 -0
  123. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/__main__.py +0 -0
  124. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/cli.py +0 -0
  125. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/config_io.py +0 -0
  126. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/constants.py +0 -0
  127. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/dependencies.py +0 -0
  128. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/formatters.py +0 -0
  129. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/pre_commit.py +0 -0
  130. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/system.py +0 -0
  131. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/tui/__init__.py +0 -0
  132. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/tui/app.py +0 -0
  133. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/tui/constants.py +0 -0
  134. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/tui/screens.py +0 -0
  135. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/tui/themes.py +0 -0
  136. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/tui/types_.py +0 -0
  137. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/tui/widgets.py +0 -0
  138. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/src/ruff_sync/types_.py +0 -0
  139. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tasks.py +0 -0
  140. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/__init__.py +0 -0
  141. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/conftest.py +0 -0
  142. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/multi_upstream_final.toml +0 -0
  143. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/multi_upstream_initial.toml +0 -0
  144. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/multi_upstream_up1.toml +0 -0
  145. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/multi_upstream_up2.toml +0 -0
  146. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/no_changes_final.toml +0 -0
  147. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/no_changes_initial.toml +0 -0
  148. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/no_changes_upstream.toml +0 -0
  149. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/no_dotted_keys_final.toml +0 -0
  150. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/no_dotted_keys_initial.toml +0 -0
  151. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/no_dotted_keys_upstream.toml +0 -0
  152. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/no_ruff_cfg_final.toml +0 -0
  153. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/no_ruff_cfg_initial.toml +0 -0
  154. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/no_ruff_cfg_upstream.toml +0 -0
  155. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/readme_excludes_final.toml +0 -0
  156. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/readme_excludes_initial.toml +0 -0
  157. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/readme_excludes_upstream.toml +0 -0
  158. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/standard_final.toml +0 -0
  159. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/standard_initial.toml +0 -0
  160. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/lifecycle_tomls/standard_upstream.toml +0 -0
  161. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/ruff.toml +0 -0
  162. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_basic.py +0 -0
  163. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_check.py +0 -0
  164. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_ci_integration.py +0 -0
  165. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_ci_validation.py +0 -0
  166. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_config_io.py +0 -0
  167. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_constants.py +0 -0
  168. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_corner_cases.py +0 -0
  169. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_dependencies.py +0 -0
  170. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_deprecation.py +0 -0
  171. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_e2e.py +0 -0
  172. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_formatters.py +0 -0
  173. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_git_fetch.py +0 -0
  174. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_minimal_imports.sh +0 -0
  175. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_pre_commit.py +0 -0
  176. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_project.py +0 -0
  177. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_rule_logic.py +0 -0
  178. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_scaffold.py +0 -0
  179. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_serialization.py +0 -0
  180. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_system.py +0 -0
  181. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_toml_operations.py +0 -0
  182. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_url_handling.py +0 -0
  183. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/test_whitespace.py +0 -0
  184. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/tui/__init__.py +0 -0
  185. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/tui/conftest.py +0 -0
  186. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/tui/test_themes.py +0 -0
  187. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/tui/test_tui.py +0 -0
  188. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/tui/test_tui_types.py +0 -0
  189. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/w_ruff_sync_cfg/pyproject.toml +0 -0
  190. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/wo_ruff_cfg/pyproject.toml +0 -0
  191. {ruff_sync-0.1.6.dev1 → ruff_sync-0.1.6.dev3}/tests/wo_ruff_sync_cfg/pyproject.toml +0 -0
@@ -24,12 +24,12 @@ passing both.
24
24
  > Use this to pick your agent tier. Simple phases can be handled by a weak/cheap model;
25
25
  > Complex phases need a capable reasoning model.
26
26
 
27
- | Priority | Label | Complexity | Feature | Scope |
28
- |---|---|---|---|---|
29
- | 1 (Must Have) | 🔴 | 🟡 Moderate | TOML syntax + Ruff CLI validation | New `validation.py` module; gated by `--validate` in `pull()` |
30
- | 2 (Should Have) | 🟠 | 🟢 Simple | Python version consistency check | `validation.py` + warn when `--validate` is active |
31
- | 3 (Could Have) | 🟡 | 🔴 Complex | Rule deprecation warnings | `validation.py` + subprocess + JSON + DI; gated by `--validate` |
32
- | 4 (Nice to Have) | 🟢 | 🟢 Simple | `--strict` flag | Upgrades warnings to failures; implies `--validate` |
27
+ | Priority | Label | Complexity | Feature | Scope | Status |
28
+ |---|---|---|---|---|---|
29
+ | 1 (Must Have) | 🔴 | 🟡 Moderate | TOML syntax + Ruff CLI validation | New `validation.py` module; gated by `--validate` in `pull()` | ✅ Completed |
30
+ | 2 (Should Have) | 🟠 | 🟢 Simple | Python version consistency check | `validation.py` + warn when `--validate` is active | ✅ Completed |
31
+ | 3 (Could Have) | 🟡 | 🔴 Complex | Rule deprecation warnings | `validation.py` + subprocess + JSON + DI; gated by `--validate` | ✅ Completed |
32
+ | 4 (Nice to Have) | 🟢 | 🟢 Simple | `--strict` flag | Upgrades warnings to failures; implies `--validate` | ✅ Completed |
33
33
 
34
34
  ---
35
35
 
@@ -127,8 +127,9 @@ ruff-sync git@github.com:my-org/standards.git # SSH (shallow clone)
127
127
  ## Gotchas
128
128
 
129
129
  - **`exclude` uses dotted paths, not TOML paths.** `lint.per-file-ignores` refers to the `per-file-ignores` key inside `[tool.ruff.lint]`. Do NOT write `tool.ruff.lint.per-file-ignores`.
130
- - **`--validate` is opt-in.** Validation is off by default. Pass `--validate` (or `--strict`) to run the merged config through Ruff before writing. The sync is aborted if Ruff rejects the config, leaving the local file untouched.
131
- - **`--strict` implies `--validate`.** If you want warnings treated as failures, only `--strict` is needed don't pass both.
130
+ - **`--validate` is opt-in.** Validation is off by default. Pass `--validate` (or `--strict`) to run the merged config through Ruff before writing. The sync is aborted if Ruff rejects the config, leaving the local file untouched. This includes a **Python version consistency check** that compares upstream `target-version` against local `requires-python`.
131
+ - **Excluding `target-version` skips consistency validation.** If `target-version` (or `tool.ruff.target-version`) is in the `exclude` list, `ruff-sync` will skip the version consistency check and log a warning. This is useful for projects that intentionally deviate from upstream Python versions.
132
+ - **`--strict` implies `--validate`.** If you want warnings (like version mismatches or deprecated rules) treated as failures, only `--strict` is needed — don't pass both.
132
133
  - **Validation soft-fails if `ruff` is not on PATH.** If the `ruff` binary can't be found, a warning is logged and the sync continues normally.
133
134
  - **Use `--init` only for new projects.** `ruff-sync` requires an existing `pyproject.toml` or `ruff.toml`. Pass `--init` to scaffold one if the directory is empty. This will automatically generate a `[tool.ruff-sync]` configuration block for future syncs.
134
135
  - **Use `--save` to persist CLI arguments.** If you want to update an existing `pyproject.toml` with a new upstream URL or exclusion, pass `--save` to write the new configuration to the file.
@@ -77,6 +77,26 @@ ruff-sync # pulls config AND updates the hook rev (if pre-commit-versio
77
77
  ```
78
78
 
79
79
  To suppress this check entirely, omit `--pre-commit` from `ruff-sync check` or set `pre-commit-version-sync = false`.
80
+ ---
81
+
82
+ ## Python Version Mismatch Warning
83
+
84
+ **Symptom:** Sync succeeds but logs a warning like:
85
+ ```
86
+ ⚠️ Version mismatch: upstream [tool.ruff] target-version='py39' targets Python 3.9, but local [project] requires-python='>=3.10' requires Python >= 3.10.
87
+ ```
88
+
89
+ **Cause:** The upstream configuration is targeting an older Python version than your project requires. This can lead to Ruff not using newer rules or features available to your project.
90
+
91
+ **Fix:**
92
+ 1. **Update Upstream:** The ideal fix is to update the `target-version` in the upstream repository to a newer version (e.g., `py311`).
93
+ 2. **Exclude the key:** If you need to stay on a specific version locally, add `target-version` to your `exclude` list:
94
+ ```toml
95
+ [tool.ruff-sync]
96
+ exclude = ["target-version"]
97
+ ```
98
+
99
+ In **`--strict`** mode, this warning is upgraded to a hard failure and will abort the sync.
80
100
 
81
101
  ---
82
102
 
@@ -20,6 +20,7 @@ Specific workflows, libraries, and tools are documented in `.agents/skills/`. Be
20
20
 
21
21
  - **Python** ≥ 3.10 (target version `py310`)
22
22
  - **Package Manager**: [uv](https://docs.astral.sh/uv/) — Use `uv run <command>` for all executions to ensure the correct environment.
23
+ - **Note on PATH**: On macOS, `uv` is often installed in `~/.local/bin`. If `uv` is not found, add this to your `PATH`: `export PATH="$PATH:$HOME/.local/bin"`.
23
24
  - **Linter / Formatter**: [Ruff](https://docs.astral.sh/ruff/) (`>=0.15.0`)
24
25
  - **Type Checker**: [mypy](https://mypy-lang.org/) (strict mode)
25
26
  - **Test Framework**: [pytest](https://docs.pytest.org/) with `pytest-asyncio`, `respx`, `pyfakefs` (See [Testing Standards](.agents/TESTING.md))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ruff-sync
3
- Version: 0.1.6.dev1
3
+ Version: 0.1.6.dev3
4
4
  Summary: Synchronize Ruff linter configuration across projects
5
5
  Project-URL: Homepage, https://github.com/Kilo59/ruff-sync
6
6
  Project-URL: Documentation, https://kilo59.github.io/ruff-sync/
@@ -62,6 +62,9 @@ If your projects are on different Python versions but share linting rules:
62
62
  exclude = ["target-version"]
63
63
  ```
64
64
 
65
+ > [!NOTE]
66
+ > Excluding `target-version` also automatically skips the Python version consistency check otherwise performed during `--validate` or `--strict` runs.
67
+
65
68
  #### Sequential merging of multiple sources
66
69
 
67
70
  You can specify multiple upstream sources as a list. They will be merged in order—from top to bottom—with later sources overriding or extending earlier ones.
@@ -122,12 +122,15 @@ ruff-sync --validate
122
122
 
123
123
  If Ruff rejects the merged config (e.g., because the upstream introduced an unknown key), the sync is aborted and your local file is left untouched.
124
124
 
125
- For stricter enforcement, use `--strict`. This upgrades any validation *warnings* such as a Python version mismatch between `[tool.ruff] target-version` and `[project] requires-python` — into hard failures:
125
+ For stricter enforcement, use `--strict`. This upgrades any validation *warnings* into hard failures. This includes a **Python version consistency check** that compares the upstream `[tool.ruff] target-version` against your local `[project] requires-python`:
126
126
 
127
127
  ```bash
128
128
  ruff-sync --strict
129
129
  ```
130
130
 
131
+ > [!TIP]
132
+ > If you intentionally manage your Python version locally and it differs from the upstream, you can add `target-version` to your `exclude` list. `ruff-sync` will then skip the consistency check and log a warning explaining why.
133
+
131
134
  > [!NOTE]
132
135
  > `--strict` implies `--validate`. You do not need to pass both flags.
133
136
  >
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ruff-sync"
3
- version = "0.1.6.dev1"
3
+ version = "0.1.6.dev3"
4
4
  description = "Synchronize Ruff linter configuration across projects"
5
5
  keywords = ["ruff", "linter", "config", "synchronize", "python", "linting", "automation", "tomlkit", "pre-commit"]
6
6
  authors = [
@@ -1164,7 +1164,7 @@ async def pull(
1164
1164
 
1165
1165
  is_ruff_toml = is_ruff_toml_file(_source_toml_path.name)
1166
1166
  if not validate_merged_config(
1167
- source_doc, is_ruff_toml=is_ruff_toml, strict=args.strict
1167
+ source_doc, is_ruff_toml=is_ruff_toml, strict=args.strict, exclude=args.exclude
1168
1168
  ):
1169
1169
  fmt.error(
1170
1170
  "❌ Merged config failed validation. Local file left unchanged.",
@@ -0,0 +1,323 @@
1
+ """Validation logic for ruff-sync merged configurations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import functools
6
+ import json
7
+ import logging
8
+ import pathlib
9
+ import re
10
+ import subprocess
11
+ import tempfile
12
+ from typing import TYPE_CHECKING
13
+
14
+ import tomlkit
15
+ from tomlkit import TOMLDocument
16
+
17
+ if TYPE_CHECKING:
18
+ from collections.abc import Iterable
19
+
20
+ __all__ = [
21
+ "validate_merged_config",
22
+ "validate_ruff_accepts_config",
23
+ "validate_toml_syntax",
24
+ ]
25
+
26
+ LOGGER = logging.getLogger(__name__)
27
+
28
+ _RUFF_TARGET_VERSION_PATTERN = re.compile(r"^py(\d)(\d+)$")
29
+
30
+
31
+ def _ruff_target_to_tuple(target_version: str) -> tuple[int, int] | None:
32
+ """Parse a Ruff target-version string (e.g. 'py311') into a (major, minor) tuple."""
33
+ m = _RUFF_TARGET_VERSION_PATTERN.match(target_version)
34
+ if not m:
35
+ return None
36
+ return int(m.group(1)), int(m.group(2))
37
+
38
+
39
+ def _requires_python_min_version(requires_python: str) -> tuple[int, int] | None:
40
+ """Extract the minimum Python version from a PEP 440 requires-python string.
41
+
42
+ Examples:
43
+ '>=3.10' -> (3, 10)
44
+ '^3.11' -> (3, 11)
45
+ '~=3.9' -> (3, 9)
46
+ """
47
+ # TODO: Consider using packaging.specifiers.SpecifierSet optionally if available
48
+ # Match all version specifiers of the form X.Y
49
+ matches = re.findall(r"(\d+)\.(\d+)", requires_python)
50
+ if matches:
51
+ # Convert to list of (int, int) and return the minimum semantic version
52
+ versions = [(int(major), int(minor)) for major, minor in matches]
53
+ return min(versions)
54
+ return None
55
+
56
+
57
+ def check_python_version_consistency(
58
+ doc: TOMLDocument, strict: bool = False, exclude: Iterable[str] = ()
59
+ ) -> bool:
60
+ """Warn if the merged ruff target-version conflicts with requires-python.
61
+
62
+ Args:
63
+ doc: The merged TOML document (pyproject.toml format).
64
+ strict: If True, treat version mismatch as a failure.
65
+ exclude: List of keys excluded from the ruff configuration.
66
+
67
+ Returns:
68
+ True if versions are consistent or if check is skipped.
69
+ False if strict=True and versions are inconsistent.
70
+ """
71
+ if "target-version" in exclude or "tool.ruff.target-version" in exclude:
72
+ LOGGER.warning(
73
+ "Skipping Python version consistency check: 'target-version' is "
74
+ "excluded in [tool.ruff-sync]."
75
+ )
76
+ return True
77
+ try:
78
+ ruff_section = doc.get("tool", {}).get("ruff", {})
79
+ target_version = ruff_section.get("target-version")
80
+ requires_python = doc.get("project", {}).get("requires-python")
81
+ except (AttributeError, TypeError):
82
+ return True # Don't crash on unexpected doc shapes
83
+
84
+ if not target_version or not requires_python:
85
+ missing = []
86
+ if not target_version:
87
+ missing.append("[tool.ruff] target-version")
88
+ if not requires_python:
89
+ missing.append("[project] requires-python")
90
+ LOGGER.warning(f"Skipping Python version consistency check: missing {', '.join(missing)}.")
91
+ return True # Nothing to compare
92
+
93
+ ruff_min = _ruff_target_to_tuple(str(target_version))
94
+ proj_min = _requires_python_min_version(str(requires_python))
95
+
96
+ if ruff_min is None or proj_min is None:
97
+ return True # Couldn't parse one of the versions
98
+
99
+ if ruff_min < proj_min:
100
+ msg = (
101
+ f"Version mismatch: upstream [tool.ruff] target-version='{target_version}' "
102
+ f"targets Python {ruff_min[0]}.{ruff_min[1]}, but local [project] requires-python="
103
+ f"'{requires_python}' requires Python >= {proj_min[0]}.{proj_min[1]}. "
104
+ "Consider updating target-version in the upstream config."
105
+ )
106
+ if strict:
107
+ LOGGER.error(f"❌ {msg}")
108
+ return False
109
+ LOGGER.warning(f"⚠️ {msg}")
110
+
111
+ return True
112
+
113
+
114
+ _RULE_LIST_KEYS: frozenset[str] = frozenset({"select", "extend-select", "ignore", "extend-ignore"})
115
+
116
+
117
+ @functools.lru_cache(maxsize=1)
118
+ def _get_deprecated_rule_codes() -> frozenset[str]:
119
+ """Return the set of deprecated rule codes reported by the installed Ruff version.
120
+
121
+ Returns an empty frozenset if ruff is not found or output cannot be parsed.
122
+ """
123
+ try:
124
+ result = subprocess.run(
125
+ ["ruff", "rule", "--all", "--output-format", "json"], # noqa: S607
126
+ capture_output=True,
127
+ text=True,
128
+ timeout=30,
129
+ check=False,
130
+ )
131
+ if result.returncode != 0:
132
+ return frozenset()
133
+ rules = json.loads(result.stdout)
134
+ return frozenset(r["code"] for r in rules if r.get("deprecated") is True)
135
+ except (
136
+ FileNotFoundError,
137
+ subprocess.TimeoutExpired,
138
+ json.JSONDecodeError,
139
+ KeyError,
140
+ TypeError,
141
+ ):
142
+ return frozenset()
143
+
144
+
145
+ def check_deprecated_rules(
146
+ doc: TOMLDocument,
147
+ is_ruff_toml: bool = False,
148
+ strict: bool = False,
149
+ _deprecated_codes: frozenset[str] | None = None,
150
+ exclude: Iterable[str] = (),
151
+ ) -> bool:
152
+ """Warn if the merged config references any deprecated Ruff rules.
153
+
154
+ Args:
155
+ doc: The merged TOML document.
156
+ is_ruff_toml: True if the document is a standalone ruff.toml.
157
+ strict: If True, treat deprecated rules as a failure.
158
+ _deprecated_codes: Optional set of deprecated codes to use (for testing).
159
+ exclude: List of keys excluded from the ruff configuration.
160
+
161
+ Returns:
162
+ True if no deprecated rules are found, or if strict=False.
163
+ False if strict=True and deprecated rules are found.
164
+ """
165
+ deprecated_codes = (
166
+ _deprecated_codes if _deprecated_codes is not None else _get_deprecated_rule_codes()
167
+ )
168
+ if not deprecated_codes:
169
+ return True # Nothing to check (ruff not found or returned no deprecated rules)
170
+
171
+ if is_ruff_toml:
172
+ lint_section = doc.get("lint", {})
173
+ else:
174
+ lint_section = doc.get("tool", {}).get("ruff", {}).get("lint", {})
175
+
176
+ if not isinstance(lint_section, dict):
177
+ return True
178
+
179
+ found_deprecated = False
180
+ for key in _RULE_LIST_KEYS:
181
+ full_key = f"lint.{key}" if is_ruff_toml else f"tool.ruff.lint.{key}"
182
+ if key in exclude or full_key in exclude:
183
+ continue
184
+
185
+ rule_list = lint_section.get(key, [])
186
+ if not isinstance(rule_list, list):
187
+ continue
188
+ for rule_code in rule_list:
189
+ rule_str = str(rule_code).strip().upper()
190
+ if rule_str in deprecated_codes:
191
+ found_deprecated = True
192
+ msg = (
193
+ f"Upstream config uses deprecated rule '{rule_str}' "
194
+ f"(found in [{'lint' if is_ruff_toml else 'tool.ruff.lint'}].{key}). "
195
+ "This rule may be removed in a future Ruff version."
196
+ )
197
+ if strict:
198
+ LOGGER.error(f"❌ {msg}")
199
+ else:
200
+ LOGGER.warning(f"⚠️ {msg}")
201
+
202
+ return not (strict and found_deprecated)
203
+
204
+
205
+ def validate_toml_syntax(doc: TOMLDocument) -> bool:
206
+ """Return True if the document serializes to valid TOML.
207
+
208
+ tomlkit always produces valid TOML, so this catches any edge cases
209
+ where serialization itself raises an unexpected exception.
210
+ """
211
+ try:
212
+ tomlkit.parse(doc.as_string())
213
+ return True # noqa: TRY300
214
+ except tomlkit.exceptions.TOMLKitError:
215
+ LOGGER.exception("❌ Merged config failed TOML syntax check")
216
+ return False
217
+
218
+
219
+ def validate_ruff_accepts_config(
220
+ doc: TOMLDocument, is_ruff_toml: bool = False, strict: bool = False
221
+ ) -> bool:
222
+ """Return True if Ruff accepts the merged configuration.
223
+
224
+ Writes the merged config to a temporary file and runs:
225
+ ruff check --isolated --config <tmp> <dummy-py-file>
226
+
227
+ Args:
228
+ doc: The merged TOML document to validate.
229
+ is_ruff_toml: True if the document is a ruff.toml (not pyproject.toml).
230
+ strict: If True, treat configuration warnings (deprecated rules, etc.) as failures.
231
+
232
+ Returns:
233
+ True if Ruff accepts the config without errors, False otherwise.
234
+ """
235
+ # The filename matters: ruff.toml uses flat format, pyproject.toml uses [tool.ruff]
236
+ config_filename = "ruff.toml" if is_ruff_toml else "pyproject.toml"
237
+
238
+ with tempfile.TemporaryDirectory() as tmp_dir:
239
+ tmp_path = pathlib.Path(tmp_dir) / config_filename
240
+ tmp_path.write_text(doc.as_string(), encoding="utf-8")
241
+
242
+ # Create a minimal dummy Python file for ruff to lint
243
+ dummy_py = pathlib.Path(tmp_dir) / "dummy.py"
244
+ dummy_py.write_text("# ruff-sync config validation\n", encoding="utf-8")
245
+
246
+ config_flag = f"--config={tmp_path}"
247
+ # Using --config should be enough to isolate from project config
248
+ cmd = ["ruff", "check", config_flag, str(dummy_py)]
249
+ LOGGER.debug(f"Running ruff config validation: {' '.join(cmd)}")
250
+
251
+ try:
252
+ result = subprocess.run( # noqa: S603
253
+ cmd,
254
+ capture_output=True,
255
+ text=True,
256
+ timeout=30,
257
+ check=False,
258
+ )
259
+ except FileNotFoundError:
260
+ LOGGER.warning("⚠️ `ruff` not found on PATH — skipping Ruff config validation.")
261
+ return True # Soft fail: don't block if ruff isn't installed
262
+ except subprocess.TimeoutExpired:
263
+ LOGGER.warning("⚠️ Ruff config validation timed out — skipping.")
264
+ return True # Soft fail on timeout
265
+
266
+ # Exit 0 = no issues found, exit 1 = issues found — both mean ruff
267
+ # parsed the config successfully. Exit 2 = config/usage error.
268
+ if result.returncode not in (0, 1):
269
+ LOGGER.error(
270
+ f"❌ Ruff rejected the merged config (exit {result.returncode}):\n"
271
+ f"{result.stderr.strip()}"
272
+ )
273
+ return False
274
+
275
+ # If strict mode is enabled, check stderr for configuration warnings
276
+ if strict and result.stderr:
277
+ # Ruff emits "warning: ..." or "deprecated ..." to stderr for config issues
278
+ # that aren't fatal enough to cause exit code 2.
279
+ lower_stderr = result.stderr.lower()
280
+ if "warning:" in lower_stderr or "deprecated" in lower_stderr:
281
+ LOGGER.error(
282
+ "❌ Ruff validation warning(s) detected in strict mode:\n"
283
+ f"{result.stderr.strip()}"
284
+ )
285
+ return False
286
+
287
+ return True
288
+
289
+
290
+ def validate_merged_config(
291
+ doc: TOMLDocument,
292
+ is_ruff_toml: bool = False,
293
+ strict: bool = False,
294
+ exclude: Iterable[str] = (),
295
+ ) -> bool:
296
+ """Run all validation checks on the merged TOML document.
297
+
298
+ Returns True only if all checks pass. Returns False and logs errors
299
+ if any check fails.
300
+
301
+ Args:
302
+ doc: The merged TOML document to validate.
303
+ is_ruff_toml: True if the document is a standalone ruff.toml.
304
+ strict: If True, treat configuration warnings as hard failures.
305
+ exclude: List of keys excluded from the ruff configuration.
306
+
307
+ Returns:
308
+ True if all validation checks pass, False otherwise.
309
+ """
310
+ if not validate_toml_syntax(doc):
311
+ return False
312
+ if not validate_ruff_accepts_config(doc, is_ruff_toml=is_ruff_toml, strict=strict):
313
+ return False
314
+
315
+ version_ok = True
316
+ if not is_ruff_toml:
317
+ version_ok = check_python_version_consistency(doc, strict=strict, exclude=exclude)
318
+
319
+ deprecated_ok = check_deprecated_rules(
320
+ doc, is_ruff_toml=is_ruff_toml, strict=strict, exclude=exclude
321
+ )
322
+
323
+ return version_ok and deprecated_ok