claude-dev-env 2.28.0 → 2.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/.agents/agents/AGENTS.md +0 -31
  2. package/.agents/agents/clean-coder.md +1 -1
  3. package/.agents/agents/test_agent_frontmatter.py +3 -1
  4. package/.agents/skills/AGENTS.md +0 -70
  5. package/.agents/skills/_shared/AGENTS.md +0 -44
  6. package/.agents/skills/_shared/advisor/AGENTS.md +0 -8
  7. package/.agents/skills/_shared/pr-loop/AGENTS.md +0 -57
  8. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -8
  9. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -34
  10. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -23
  11. package/.agents/skills/autoconverge/AGENTS.md +0 -35
  12. package/.agents/skills/autoconverge/reference/AGENTS.md +0 -15
  13. package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -25
  14. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -15
  15. package/.agents/skills/everything-search/AGENTS.md +0 -16
  16. package/.agents/skills/fresh-branch/AGENTS.md +0 -13
  17. package/.agents/skills/grok-spawn/AGENTS.md +0 -27
  18. package/.agents/skills/orchestrator/.claude/CLAUDE.md +1 -0
  19. package/.agents/skills/orchestrator/AGENTS.md +1 -0
  20. package/.agents/skills/orchestrator/SKILL.md +44 -53
  21. package/.agents/skills/orchestrator/reference/.claude/CLAUDE.md +1 -0
  22. package/.agents/skills/orchestrator/reference/AGENTS.md +1 -0
  23. package/.agents/skills/orchestrator/reference/consult-the-orchestrator.md +70 -0
  24. package/.agents/skills/orchestrator/reference/executor-consult-block.md +62 -0
  25. package/.agents/skills/orchestrator/reference/host-detect.md +15 -0
  26. package/.agents/skills/orchestrator/test_orchestrator_skill_contract.py +62 -0
  27. package/.agents/skills/orchestrator-refresh/SKILL.md +16 -34
  28. package/.agents/skills/rebase/AGENTS.md +0 -31
  29. package/.agents/skills/session-log/AGENTS.md +0 -31
  30. package/.agents/skills/session-tidy/AGENTS.md +0 -35
  31. package/.agents/skills/skill-builder/AGENTS.md +0 -48
  32. package/.agents/skills/skill-builder/references/AGENTS.md +0 -24
  33. package/.agents/skills/skill-builder/templates/AGENTS.md +0 -13
  34. package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -18
  35. package/.agents/skills/task-build/AGENTS.md +0 -28
  36. package/.agents/skills/update/AGENTS.md +0 -37
  37. package/.agents/skills-archived/AGENTS.md +0 -44
  38. package/.agents/skills-archived/anthropic-plan/AGENTS.md +0 -33
  39. package/.agents/skills-archived/anthropic-plan/scripts/AGENTS.md +0 -10
  40. package/.agents/skills-archived/anthropic-plan/scripts/anthropic_plan_scripts_constants/AGENTS.md +0 -15
  41. package/.agents/skills-archived/anthropic-plan/templates/AGENTS.md +0 -12
  42. package/.agents/skills-archived/anthropic-plan/workflow/AGENTS.md +0 -13
  43. package/.agents/skills-archived/auditing-claude-config/AGENTS.md +0 -20
  44. package/.agents/skills-archived/bugteam/AGENTS.md +0 -29
  45. package/.agents/skills-archived/bugteam/reference/AGENTS.md +0 -19
  46. package/.agents/skills-archived/bugteam/reference/obstacles/AGENTS.md +0 -23
  47. package/.agents/skills-archived/bugteam/scripts/AGENTS.md +0 -29
  48. package/.agents/skills-archived/bugteam/scripts/bugteam_scripts_constants/AGENTS.md +0 -17
  49. package/.agents/skills-archived/codex-review/AGENTS.md +0 -45
  50. package/.agents/skills-archived/codex-review/reference/AGENTS.md +0 -14
  51. package/.agents/skills-archived/codex-review/scripts/codex_review_scripts_constants/AGENTS.md +0 -17
  52. package/.agents/skills-archived/codex-review/test_skill_scaffold.py +13 -3
  53. package/.agents/skills-archived/copilot-review/AGENTS.md +0 -17
  54. package/.agents/skills-archived/pr-converge/AGENTS.md +0 -31
  55. package/.agents/skills-archived/pr-converge/pr_converge_skill_constants/AGENTS.md +0 -25
  56. package/.agents/skills-archived/pr-converge/reference/AGENTS.md +0 -27
  57. package/.agents/skills-archived/pr-converge/reference/obstacles/AGENTS.md +0 -22
  58. package/.agents/skills-archived/pr-converge/scripts/AGENTS.md +0 -45
  59. package/.agents/skills-archived/pr-converge/scripts/pr_converge_scripts_constants/AGENTS.md +0 -17
  60. package/.agents/skills-archived/pr-converge/workflows/AGENTS.md +0 -15
  61. package/.agents/skills-archived/pr-loop-cloud-transport/reference/identity-and-hooks.md +1 -1
  62. package/.agents/skills-archived/recall/AGENTS.md +0 -29
  63. package/.agents/skills-archived/remember/AGENTS.md +0 -30
  64. package/AGENTS.md +0 -112
  65. package/_shared/AGENTS.md +0 -16
  66. package/_shared/advisor/AGENTS.md +0 -21
  67. package/_shared/advisor/advisor-protocol.md +4 -1
  68. package/_shared/advisor/reference/consult-format.md +4 -2
  69. package/_shared/pr-loop/AGENTS.md +0 -27
  70. package/_shared/pr-loop/scripts/AGENTS.md +0 -49
  71. package/_shared/pr-loop/scripts/code_rules_gate_parts/AGENTS.md +0 -41
  72. package/_shared/pr-loop/scripts/codex_review_scripts_constants/AGENTS.md +0 -17
  73. package/_shared/pr-loop/scripts/pr_converge_scripts_constants/AGENTS.md +0 -17
  74. package/_shared/pr-loop/scripts/pr_converge_skill_constants/AGENTS.md +0 -25
  75. package/_shared/pr-loop/scripts/pr_loop_shared_constants/AGENTS.md +0 -25
  76. package/_shared/pr-loop/scripts/tests/AGENTS.md +0 -43
  77. package/_shared/process-tree/AGENTS.md +0 -40
  78. package/audit-rubrics/AGENTS.md +0 -42
  79. package/audit-rubrics/category_rubrics/AGENTS.md +0 -36
  80. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +16 -29
  81. package/audit-rubrics/prompts/AGENTS.md +0 -36
  82. package/audit-rubrics/prompts/category-o-docstring-vs-impl-drift.md +2 -2
  83. package/bin/AGENTS.md +0 -118
  84. package/bin/install.test.mjs +1 -1
  85. package/commands/AGENTS.md +0 -14
  86. package/docs/AGENTS.md +0 -31
  87. package/docs/CODE_RULES.md +3 -3
  88. package/docs/agent-spawn-protocol.md +1 -1
  89. package/docs/references/AGENTS.md +0 -16
  90. package/docs/references/prose-style-enforcement.md +5 -9
  91. package/hooks/AGENTS.md +0 -27
  92. package/hooks/advisory/AGENTS.md +0 -15
  93. package/hooks/blocking/AGENTS.md +0 -122
  94. package/hooks/blocking/claude_md_orphan_file_blocker_parts/AGENTS.md +0 -27
  95. package/hooks/blocking/code_rules_docstrings.py +10 -2138
  96. package/hooks/blocking/code_rules_enforcer.py +0 -121
  97. package/hooks/blocking/code_rules_imports_logging.py +1 -236
  98. package/hooks/blocking/code_rules_shared.py +23 -0
  99. package/hooks/blocking/code_rules_test_layout.py +8 -8
  100. package/hooks/blocking/config/AGENTS.md +0 -9
  101. package/hooks/blocking/config/prose_style_enforcement_constants.py +4 -2
  102. package/hooks/blocking/config/test_prose_style_enforcement_constants.py +5 -1
  103. package/hooks/blocking/inventory_intent_records/AGENTS.md +0 -25
  104. package/hooks/blocking/package_inventory_stale_blocker_parts/AGENTS.md +0 -25
  105. package/hooks/blocking/pii_prevention_blocker_parts/AGENTS.md +0 -23
  106. package/hooks/blocking/precommit_code_rules_gate.py +8 -43
  107. package/hooks/blocking/state_description_blocker.py +1 -7
  108. package/hooks/blocking/tdd_enforcer_parts/AGENTS.md +0 -29
  109. package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +0 -1
  110. package/hooks/blocking/test_code_rules_enforcer_dispatch_wiring.py +0 -8
  111. package/hooks/blocking/test_code_rules_enforcer_module_docstring_roster.py +11 -112
  112. package/hooks/blocking/test_code_rules_enforcer_narrow_edit.py +0 -1
  113. package/hooks/blocking/test_code_rules_enforcer_split_entry_1.py +1 -18
  114. package/hooks/blocking/test_code_rules_shared.py +12 -0
  115. package/hooks/blocking/test_precommit_code_rules_gate.py +32 -179
  116. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +0 -1
  117. package/hooks/blocking/test_state_description_blocker.py +6 -4
  118. package/hooks/blocking/test_stop_dispatcher.py +5 -29
  119. package/hooks/git-hooks/AGENTS.md +0 -31
  120. package/hooks/git-hooks/git_hooks_constants/AGENTS.md +0 -20
  121. package/hooks/hooks_constants/AGENTS.md +0 -104
  122. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -1
  123. package/hooks/hooks_constants/code_rules_enforcer_constants.py +3 -0
  124. package/hooks/hooks_constants/messages.py +0 -2
  125. package/hooks/hooks_constants/precommit_code_rules_gate_constants.py +3 -17
  126. package/hooks/hooks_constants/stop_dispatcher_constants.py +0 -2
  127. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +0 -1
  128. package/hooks/hooks_constants/test_code_rules_enforcer_constants.py +7 -0
  129. package/hooks/hooks_constants/test_messages.py +5 -3
  130. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +0 -2
  131. package/hooks/lifecycle/AGENTS.md +0 -17
  132. package/hooks/observability/AGENTS.md +0 -19
  133. package/hooks/session/AGENTS.md +0 -37
  134. package/hooks/validation/AGENTS.md +0 -19
  135. package/hooks/validators/AGENTS.md +0 -51
  136. package/hooks/workflow/AGENTS.md +0 -15
  137. package/output-styles/AGENTS.md +0 -14
  138. package/package.json +1 -1
  139. package/rules/AGENTS.md +0 -58
  140. package/rules/claims-as-quotes.md +0 -10
  141. package/rules/code-standards.md +6 -6
  142. package/rules/explore-thoroughly.md +0 -1
  143. package/rules/failure-blast-radius.md +0 -8
  144. package/rules/falsify-before-green.md +0 -8
  145. package/rules/file-global-constants.md +2 -2
  146. package/rules/filesystem-search.md +1 -1
  147. package/rules/git-workflow.md +1 -9
  148. package/rules/hedging-claims.md +2 -6
  149. package/rules/long-horizon-autonomy.md +1 -1
  150. package/rules/measurement-denominators.md +0 -9
  151. package/rules/research-mode.md +0 -6
  152. package/rules/verify-before-asking.md +0 -5
  153. package/rules/verify-runtime-state.md +0 -5
  154. package/scripts/AGENTS.md +0 -55
  155. package/scripts/codex_compat_materializer.py +0 -12
  156. package/scripts/dev_env_scripts_constants/AGENTS.md +0 -20
  157. package/scripts/sync_to_cursor/AGENTS.md +0 -22
  158. package/scripts/sync_to_cursor/rules.py +0 -10
  159. package/scripts/tests/AGENTS.md +0 -34
  160. package/scripts/tests/test_engine.py +0 -1
  161. package/scripts/tests/test_rules.py +0 -1
  162. package/scripts/tests/test_sync_to_cursor.py +0 -1
  163. package/system-prompts/AGENTS.md +0 -24
  164. package/system-prompts/software-engineer.xml +3 -3
  165. package/hooks/blocking/code_rules_dead_argparse_argument.py +0 -554
  166. package/hooks/blocking/code_rules_dead_config_field.py +0 -568
  167. package/hooks/blocking/code_rules_dead_dataclass_field.py +0 -348
  168. package/hooks/blocking/code_rules_dead_module_constant.py +0 -757
  169. package/hooks/blocking/code_rules_dead_split_branch.py +0 -225
  170. package/hooks/blocking/code_rules_mock_completeness.py +0 -295
  171. package/hooks/blocking/code_rules_scope_binding.py +0 -151
  172. package/hooks/blocking/code_rules_unused_imports.py +0 -197
  173. package/hooks/blocking/hedging_language_blocker.py +0 -221
  174. package/hooks/blocking/intent_only_ending_blocker.py +0 -148
  175. package/hooks/blocking/test_code_rules_enforcer_dead_argparse_argument.py +0 -534
  176. package/hooks/blocking/test_code_rules_enforcer_dead_config_field.py +0 -846
  177. package/hooks/blocking/test_code_rules_enforcer_dead_dataclass_field.py +0 -507
  178. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +0 -679
  179. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant_alias.py +0 -133
  180. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant_read_cap.py +0 -103
  181. package/hooks/blocking/test_code_rules_enforcer_dead_split_branch.py +0 -105
  182. package/hooks/blocking/test_code_rules_enforcer_docstring_args_span_scope.py +0 -425
  183. package/hooks/blocking/test_code_rules_enforcer_docstring_cardinal_family.py +0 -176
  184. package/hooks/blocking/test_code_rules_enforcer_docstring_delegation_summary.py +0 -385
  185. package/hooks/blocking/test_code_rules_enforcer_docstring_fallback_branch.py +0 -398
  186. package/hooks/blocking/test_code_rules_enforcer_docstring_field_runmode_outcome.py +0 -129
  187. package/hooks/blocking/test_code_rules_enforcer_docstring_inline_literal_claim.py +0 -93
  188. package/hooks/blocking/test_code_rules_enforcer_docstring_length_constant_superlative.py +0 -198
  189. package/hooks/blocking/test_code_rules_enforcer_docstring_mark_glyph_enumeration.py +0 -262
  190. package/hooks/blocking/test_code_rules_enforcer_docstring_no_consumer.py +0 -93
  191. package/hooks/blocking/test_code_rules_enforcer_docstring_no_network.py +0 -115
  192. package/hooks/blocking/test_code_rules_enforcer_docstring_raises_largezipfile.py +0 -226
  193. package/hooks/blocking/test_code_rules_enforcer_docstring_returns_plural_cardinality.py +0 -207
  194. package/hooks/blocking/test_code_rules_enforcer_docstring_step_dispatch.py +0 -262
  195. package/hooks/blocking/test_code_rules_enforcer_docstring_type_checking_gate.py +0 -164
  196. package/hooks/blocking/test_code_rules_enforcer_docstring_unguarded_payload.py +0 -188
  197. package/hooks/blocking/test_code_rules_enforcer_import_block_sort.py +0 -157
  198. package/hooks/blocking/test_code_rules_enforcer_split_mocks_1.py +0 -303
  199. package/hooks/blocking/test_code_rules_enforcer_split_mocks_2.py +0 -111
  200. package/hooks/blocking/test_code_rules_enforcer_unused_imports.py +0 -656
  201. package/hooks/blocking/test_hedging_language_blocker.py +0 -261
  202. package/hooks/blocking/test_intent_only_ending_blocker.py +0 -209
  203. package/hooks/hooks_constants/dead_argparse_argument_constants.py +0 -28
  204. package/hooks/hooks_constants/dead_config_field_constants.py +0 -39
  205. package/hooks/hooks_constants/dead_dataclass_field_constants.py +0 -25
  206. package/hooks/hooks_constants/dead_module_constant_constants.py +0 -30
  207. package/hooks/hooks_constants/hedging_uncertainty_constants.py +0 -42
  208. package/hooks/hooks_constants/test_dispatcher_constants_docstrings.py +0 -44
  209. package/rules/conservative-action.md +0 -17
  210. package/rules/context7.md +0 -8
  211. package/rules/few-words.md +0 -3
  212. package/rules/parallel-tools.md +0 -23
@@ -1,534 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import importlib.util
4
- from pathlib import Path
5
-
6
- ENFORCER_PATH = Path(__file__).resolve().parent / "code_rules_enforcer.py"
7
- specification = importlib.util.spec_from_file_location("code_rules_enforcer", ENFORCER_PATH)
8
- assert specification is not None and specification.loader is not None
9
- code_rules_enforcer = importlib.util.module_from_spec(specification)
10
- specification.loader.exec_module(code_rules_enforcer)
11
-
12
- PRODUCTION_FILE_PATH = "packages/app/services/render_report.py"
13
- TEST_FILE_PATH = "packages/app/services/test_render_report.py"
14
- MIGRATION_FILE_PATH = "packages/app/migrations/0001_initial.py"
15
-
16
-
17
- def _check(source: str, file_path: str) -> list[str]:
18
- return code_rules_enforcer.check_dead_argparse_arguments(source, file_path)
19
-
20
-
21
- def test_should_flag_optional_argument_whose_dest_is_never_read() -> None:
22
- source = (
23
- "import argparse\n"
24
- "\n"
25
- "def build() -> None:\n"
26
- " argument_parser = argparse.ArgumentParser()\n"
27
- " argument_parser.add_argument('--repo', default='.')\n"
28
- " parsed_arguments = argument_parser.parse_args()\n"
29
- " print('done')\n"
30
- )
31
- issues = _check(source, PRODUCTION_FILE_PATH)
32
- assert any("'repo'" in each_issue for each_issue in issues), (
33
- f"Expected dead '--repo' argument flagged, got: {issues}"
34
- )
35
- assert any("Line 5" in each_issue for each_issue in issues), (
36
- f"Expected the add_argument line reported, got: {issues}"
37
- )
38
-
39
-
40
- def test_should_not_flag_when_dest_is_read_via_attribute_access() -> None:
41
- source = (
42
- "import argparse\n"
43
- "\n"
44
- "def build() -> str:\n"
45
- " argument_parser = argparse.ArgumentParser()\n"
46
- " argument_parser.add_argument('--repo', default='.')\n"
47
- " parsed_arguments = argument_parser.parse_args()\n"
48
- " return parsed_arguments.repo\n"
49
- )
50
- assert _check(source, PRODUCTION_FILE_PATH) == []
51
-
52
-
53
- def test_should_not_flag_a_positional_argument() -> None:
54
- source = (
55
- "import argparse\n"
56
- "\n"
57
- "def build() -> None:\n"
58
- " argument_parser = argparse.ArgumentParser()\n"
59
- " argument_parser.add_argument('path')\n"
60
- " parsed_arguments = argument_parser.parse_args()\n"
61
- " print('done')\n"
62
- )
63
- assert _check(source, PRODUCTION_FILE_PATH) == []
64
-
65
-
66
- def test_should_not_flag_help_action_argument() -> None:
67
- source = (
68
- "import argparse\n"
69
- "\n"
70
- "def build() -> None:\n"
71
- " argument_parser = argparse.ArgumentParser(add_help=False)\n"
72
- " argument_parser.add_argument('--help', action='help')\n"
73
- " parsed_arguments = argument_parser.parse_args()\n"
74
- " print('done')\n"
75
- )
76
- assert _check(source, PRODUCTION_FILE_PATH) == []
77
-
78
-
79
- def test_should_not_flag_version_action_argument() -> None:
80
- source = (
81
- "import argparse\n"
82
- "\n"
83
- "def build() -> None:\n"
84
- " argument_parser = argparse.ArgumentParser()\n"
85
- " argument_parser.add_argument('--version', action='version', version='1.0')\n"
86
- " parsed_arguments = argument_parser.parse_args()\n"
87
- " print('done')\n"
88
- )
89
- assert _check(source, PRODUCTION_FILE_PATH) == []
90
-
91
-
92
- def test_should_respect_explicit_dest_when_unread() -> None:
93
- source = (
94
- "import argparse\n"
95
- "\n"
96
- "def build() -> None:\n"
97
- " argument_parser = argparse.ArgumentParser()\n"
98
- " argument_parser.add_argument('--repo', dest='repository')\n"
99
- " parsed_arguments = argument_parser.parse_args()\n"
100
- " print('done')\n"
101
- )
102
- issues = _check(source, PRODUCTION_FILE_PATH)
103
- assert any("'repository'" in each_issue for each_issue in issues), (
104
- f"Expected the explicit dest flagged, got: {issues}"
105
- )
106
- assert not any("'repo'" in each_issue for each_issue in issues), (
107
- f"The option string must not be flagged when dest is explicit, got: {issues}"
108
- )
109
-
110
-
111
- def test_should_respect_explicit_dest_when_read() -> None:
112
- source = (
113
- "import argparse\n"
114
- "\n"
115
- "def build() -> str:\n"
116
- " argument_parser = argparse.ArgumentParser()\n"
117
- " argument_parser.add_argument('--repo', dest='repository')\n"
118
- " parsed_arguments = argument_parser.parse_args()\n"
119
- " return parsed_arguments.repository\n"
120
- )
121
- assert _check(source, PRODUCTION_FILE_PATH) == []
122
-
123
-
124
- def test_should_skip_argument_with_non_literal_dest() -> None:
125
- source = (
126
- "import argparse\n"
127
- "\n"
128
- "DEST_NAME = 'repository'\n"
129
- "\n"
130
- "def build() -> str:\n"
131
- " argument_parser = argparse.ArgumentParser()\n"
132
- " argument_parser.add_argument('--repo', dest=DEST_NAME)\n"
133
- " parsed_arguments = argument_parser.parse_args()\n"
134
- " return parsed_arguments.repository\n"
135
- )
136
- assert _check(source, PRODUCTION_FILE_PATH) == []
137
-
138
-
139
- def test_should_derive_dest_from_dashed_long_option() -> None:
140
- source = (
141
- "import argparse\n"
142
- "\n"
143
- "def build() -> bool:\n"
144
- " argument_parser = argparse.ArgumentParser()\n"
145
- " argument_parser.add_argument('--dry-run', action='store_true')\n"
146
- " parsed_arguments = argument_parser.parse_args()\n"
147
- " return parsed_arguments.dry_run\n"
148
- )
149
- assert _check(source, PRODUCTION_FILE_PATH) == []
150
-
151
-
152
- def test_should_flag_dashed_long_option_when_dest_unread() -> None:
153
- source = (
154
- "import argparse\n"
155
- "\n"
156
- "def build() -> None:\n"
157
- " argument_parser = argparse.ArgumentParser()\n"
158
- " argument_parser.add_argument('--dry-run', action='store_true')\n"
159
- " parsed_arguments = argument_parser.parse_args()\n"
160
- " print('done')\n"
161
- )
162
- issues = _check(source, PRODUCTION_FILE_PATH)
163
- assert any("'dry_run'" in each_issue for each_issue in issues), (
164
- f"Expected the dashed long option dest flagged, got: {issues}"
165
- )
166
-
167
-
168
- def test_should_derive_dest_from_long_option_when_short_precedes() -> None:
169
- source = (
170
- "import argparse\n"
171
- "\n"
172
- "def build() -> None:\n"
173
- " argument_parser = argparse.ArgumentParser()\n"
174
- " argument_parser.add_argument('-r', '--repo')\n"
175
- " parsed_arguments = argument_parser.parse_args()\n"
176
- " print('done')\n"
177
- )
178
- issues = _check(source, PRODUCTION_FILE_PATH)
179
- assert any("'repo'" in each_issue for each_issue in issues), (
180
- f"Expected dest derived from the long option, got: {issues}"
181
- )
182
-
183
-
184
- def test_should_suppress_when_namespace_is_forwarded_to_a_call() -> None:
185
- source = (
186
- "import argparse\n"
187
- "\n"
188
- "def run(parsed_arguments: argparse.Namespace) -> None:\n"
189
- " print('run')\n"
190
- "\n"
191
- "def build() -> None:\n"
192
- " argument_parser = argparse.ArgumentParser()\n"
193
- " argument_parser.add_argument('--repo', default='.')\n"
194
- " parsed_arguments = argument_parser.parse_args()\n"
195
- " run(parsed_arguments)\n"
196
- )
197
- assert _check(source, PRODUCTION_FILE_PATH) == []
198
-
199
-
200
- def test_should_suppress_when_tuple_unpacked_namespace_is_forwarded() -> None:
201
- source = (
202
- "import argparse\n"
203
- "\n"
204
- "def main(parsed_arguments: argparse.Namespace) -> None:\n"
205
- " print('run')\n"
206
- "\n"
207
- "def build() -> None:\n"
208
- " argument_parser = argparse.ArgumentParser()\n"
209
- " argument_parser.add_argument('--verbose', action='store_true')\n"
210
- " parsed_arguments, remaining = argument_parser.parse_known_args()\n"
211
- " main(parsed_arguments)\n"
212
- )
213
- assert _check(source, PRODUCTION_FILE_PATH) == []
214
-
215
-
216
- def test_should_suppress_when_aliased_namespace_is_forwarded() -> None:
217
- source = (
218
- "import argparse\n"
219
- "\n"
220
- "def run(parsed_arguments: argparse.Namespace) -> None:\n"
221
- " print('run')\n"
222
- "\n"
223
- "def build() -> None:\n"
224
- " argument_parser = argparse.ArgumentParser()\n"
225
- " argument_parser.add_argument('--repo', default='.')\n"
226
- " parsed_arguments = argument_parser.parse_args()\n"
227
- " alias = parsed_arguments\n"
228
- " run(alias)\n"
229
- )
230
- assert _check(source, PRODUCTION_FILE_PATH) == []
231
-
232
-
233
- def test_should_suppress_when_namespace_consumed_by_vars() -> None:
234
- source = (
235
- "import argparse\n"
236
- "\n"
237
- "def build() -> dict:\n"
238
- " argument_parser = argparse.ArgumentParser()\n"
239
- " argument_parser.add_argument('--repo', default='.')\n"
240
- " parsed_arguments = argument_parser.parse_args()\n"
241
- " return vars(parsed_arguments)\n"
242
- )
243
- assert _check(source, PRODUCTION_FILE_PATH) == []
244
-
245
-
246
- def test_should_suppress_when_namespace_dict_accessed() -> None:
247
- source = (
248
- "import argparse\n"
249
- "\n"
250
- "def build() -> dict:\n"
251
- " argument_parser = argparse.ArgumentParser()\n"
252
- " argument_parser.add_argument('--repo', default='.')\n"
253
- " parsed_arguments = argument_parser.parse_args()\n"
254
- " return parsed_arguments.__dict__\n"
255
- )
256
- assert _check(source, PRODUCTION_FILE_PATH) == []
257
-
258
-
259
- def test_should_be_silent_for_test_files() -> None:
260
- source = (
261
- "import argparse\n"
262
- "\n"
263
- "def build() -> None:\n"
264
- " argument_parser = argparse.ArgumentParser()\n"
265
- " argument_parser.add_argument('--repo', default='.')\n"
266
- " parsed_arguments = argument_parser.parse_args()\n"
267
- " print('done')\n"
268
- )
269
- assert _check(source, TEST_FILE_PATH) == []
270
-
271
-
272
- def test_should_be_silent_for_migration_files() -> None:
273
- source = (
274
- "import argparse\n"
275
- "\n"
276
- "def build() -> None:\n"
277
- " argument_parser = argparse.ArgumentParser()\n"
278
- " argument_parser.add_argument('--repo', default='.')\n"
279
- " parsed_arguments = argument_parser.parse_args()\n"
280
- " print('done')\n"
281
- )
282
- assert _check(source, MIGRATION_FILE_PATH) == []
283
-
284
-
285
- def test_should_tolerate_syntax_error() -> None:
286
- assert _check("def broken(:\n", PRODUCTION_FILE_PATH) == []
287
-
288
-
289
- def test_should_return_empty_when_no_add_argument_present() -> None:
290
- source = "def build() -> int:\n return 1\n"
291
- assert _check(source, PRODUCTION_FILE_PATH) == []
292
-
293
-
294
- def test_should_suppress_when_namespace_unpacked_with_double_star() -> None:
295
- source = (
296
- "import argparse\n"
297
- "\n"
298
- "def run(repo: str) -> None:\n"
299
- " print(repo)\n"
300
- "\n"
301
- "def build() -> None:\n"
302
- " argument_parser = argparse.ArgumentParser()\n"
303
- " argument_parser.add_argument('--repo', default='.')\n"
304
- " parsed_arguments = argument_parser.parse_args()\n"
305
- " run(**vars(parsed_arguments))\n"
306
- )
307
- assert _check(source, PRODUCTION_FILE_PATH) == []
308
-
309
-
310
- def test_should_not_flag_when_dest_read_via_literal_getattr() -> None:
311
- source = (
312
- "import argparse\n"
313
- "\n"
314
- "def build() -> str:\n"
315
- " argument_parser = argparse.ArgumentParser()\n"
316
- " argument_parser.add_argument('--repo', default='.')\n"
317
- " parsed_arguments = argument_parser.parse_args()\n"
318
- " return getattr(parsed_arguments, 'repo')\n"
319
- )
320
- assert _check(source, PRODUCTION_FILE_PATH) == []
321
-
322
-
323
- def test_should_suppress_when_namespace_stored_on_attribute_target() -> None:
324
- source = (
325
- "import argparse\n"
326
- "\n"
327
- "class App:\n"
328
- " def build(self) -> None:\n"
329
- " argument_parser = argparse.ArgumentParser()\n"
330
- " argument_parser.add_argument('--repo', default='.')\n"
331
- " argument_parser.add_argument('--verbose', action='store_true')\n"
332
- " self.parsed_arguments = argument_parser.parse_args()\n"
333
- "\n"
334
- " def run(self) -> dict:\n"
335
- " return dict(**vars(self.parsed_arguments))\n"
336
- )
337
- assert _check(source, PRODUCTION_FILE_PATH) == []
338
-
339
-
340
- def test_should_suppress_when_parse_method_is_aliased() -> None:
341
- source = (
342
- "import argparse\n"
343
- "\n"
344
- "def run(parsed_arguments: argparse.Namespace) -> None:\n"
345
- " print('run')\n"
346
- "\n"
347
- "def build() -> None:\n"
348
- " argument_parser = argparse.ArgumentParser()\n"
349
- " argument_parser.add_argument('--repo', default='.')\n"
350
- " parse = argument_parser.parse_args\n"
351
- " parsed_arguments = parse()\n"
352
- " run(parsed_arguments)\n"
353
- )
354
- assert _check(source, PRODUCTION_FILE_PATH) == []
355
-
356
-
357
- def test_should_suppress_when_namespace_forwarded_inside_container() -> None:
358
- source = (
359
- "import argparse\n"
360
- "\n"
361
- "def run(payload: dict) -> None:\n"
362
- " print('run')\n"
363
- "\n"
364
- "def build() -> None:\n"
365
- " argument_parser = argparse.ArgumentParser()\n"
366
- " argument_parser.add_argument('--repo', default='.')\n"
367
- " parsed_arguments = argument_parser.parse_args()\n"
368
- " run({'args': parsed_arguments})\n"
369
- )
370
- assert _check(source, PRODUCTION_FILE_PATH) == []
371
-
372
-
373
- def test_should_suppress_when_namespace_keyword_object_is_consumed() -> None:
374
- source = (
375
- "import argparse\n"
376
- "\n"
377
- "def build() -> dict:\n"
378
- " options = argparse.Namespace()\n"
379
- " argument_parser = argparse.ArgumentParser()\n"
380
- " argument_parser.add_argument('--repo', default='.')\n"
381
- " argument_parser.parse_args(namespace=options)\n"
382
- " return vars(options)\n"
383
- )
384
- assert _check(source, PRODUCTION_FILE_PATH) == []
385
-
386
-
387
- def test_should_suppress_when_namespace_keyword_object_is_forwarded() -> None:
388
- source = (
389
- "import argparse\n"
390
- "\n"
391
- "def run(parsed_arguments: argparse.Namespace) -> None:\n"
392
- " print('run')\n"
393
- "\n"
394
- "def build() -> None:\n"
395
- " options = argparse.Namespace()\n"
396
- " argument_parser = argparse.ArgumentParser()\n"
397
- " argument_parser.add_argument('--repo', default='.')\n"
398
- " argument_parser.parse_args(namespace=options)\n"
399
- " run(options)\n"
400
- )
401
- assert _check(source, PRODUCTION_FILE_PATH) == []
402
-
403
-
404
- def test_should_flag_when_namespace_keyword_object_only_attribute_read() -> None:
405
- source = (
406
- "import argparse\n"
407
- "\n"
408
- "def build() -> str:\n"
409
- " options = argparse.Namespace()\n"
410
- " argument_parser = argparse.ArgumentParser()\n"
411
- " argument_parser.add_argument('--repo', default='.')\n"
412
- " argument_parser.add_argument('--verbose', action='store_true')\n"
413
- " argument_parser.parse_args(namespace=options)\n"
414
- " return options.repo\n"
415
- )
416
- issues = _check(source, PRODUCTION_FILE_PATH)
417
- assert any("'verbose'" in each_issue for each_issue in issues), (
418
- f"Expected the unread '--verbose' flag flagged, got: {issues}"
419
- )
420
- assert not any("'repo'" in each_issue for each_issue in issues), (
421
- f"The read namespace= attribute must not be flagged, got: {issues}"
422
- )
423
-
424
-
425
- def test_should_suppress_when_parse_result_consumed_by_vars_inline() -> None:
426
- source = (
427
- "import argparse\n"
428
- "\n"
429
- "def build() -> dict:\n"
430
- " argument_parser = argparse.ArgumentParser()\n"
431
- " argument_parser.add_argument('--repo', default='.')\n"
432
- " return vars(argument_parser.parse_args())\n"
433
- )
434
- assert _check(source, PRODUCTION_FILE_PATH) == []
435
-
436
-
437
- def test_should_suppress_when_parse_result_returned_inline() -> None:
438
- source = (
439
- "import argparse\n"
440
- "\n"
441
- "def build() -> argparse.Namespace:\n"
442
- " argument_parser = argparse.ArgumentParser()\n"
443
- " argument_parser.add_argument('--repo', default='.')\n"
444
- " return argument_parser.parse_args()\n"
445
- )
446
- assert _check(source, PRODUCTION_FILE_PATH) == []
447
-
448
-
449
- def test_should_suppress_when_parse_result_double_star_unpacked_inline() -> None:
450
- source = (
451
- "import argparse\n"
452
- "\n"
453
- "def run(repo: str) -> None:\n"
454
- " print(repo)\n"
455
- "\n"
456
- "def build() -> None:\n"
457
- " argument_parser = argparse.ArgumentParser()\n"
458
- " argument_parser.add_argument('--repo', default='.')\n"
459
- " run(**vars(argument_parser.parse_args()))\n"
460
- )
461
- assert _check(source, PRODUCTION_FILE_PATH) == []
462
-
463
-
464
- def test_should_flag_when_annotated_namespace_dest_is_unread() -> None:
465
- source = (
466
- "import argparse\n"
467
- "\n"
468
- "def build() -> None:\n"
469
- " argument_parser = argparse.ArgumentParser()\n"
470
- " argument_parser.add_argument('--repo', default='.')\n"
471
- " parsed_arguments: argparse.Namespace = argument_parser.parse_args()\n"
472
- " print('done')\n"
473
- )
474
- issues = _check(source, PRODUCTION_FILE_PATH)
475
- assert any("'repo'" in each_issue for each_issue in issues), (
476
- f"Expected the dead flag flagged through the annotated binding, got: {issues}"
477
- )
478
-
479
-
480
- def test_should_not_flag_when_annotated_namespace_dest_is_read() -> None:
481
- source = (
482
- "import argparse\n"
483
- "\n"
484
- "def build() -> str:\n"
485
- " argument_parser = argparse.ArgumentParser()\n"
486
- " argument_parser.add_argument('--repo', default='.')\n"
487
- " parsed_arguments: argparse.Namespace = argument_parser.parse_args()\n"
488
- " return parsed_arguments.repo\n"
489
- )
490
- assert _check(source, PRODUCTION_FILE_PATH) == []
491
-
492
-
493
- def test_should_suppress_when_annotated_namespace_is_forwarded() -> None:
494
- source = (
495
- "import argparse\n"
496
- "\n"
497
- "def run(parsed_arguments: argparse.Namespace) -> None:\n"
498
- " print('run')\n"
499
- "\n"
500
- "def build() -> None:\n"
501
- " argument_parser = argparse.ArgumentParser()\n"
502
- " argument_parser.add_argument('--repo', default='.')\n"
503
- " parsed_arguments: argparse.Namespace = argument_parser.parse_args()\n"
504
- " run(parsed_arguments)\n"
505
- )
506
- assert _check(source, PRODUCTION_FILE_PATH) == []
507
-
508
-
509
- def test_should_suppress_when_parse_result_bound_by_walrus() -> None:
510
- source = (
511
- "import argparse\n"
512
- "\n"
513
- "def build() -> dict:\n"
514
- " argument_parser = argparse.ArgumentParser()\n"
515
- " argument_parser.add_argument('--repo', default='.')\n"
516
- " return vars(parsed_arguments := argument_parser.parse_args())\n"
517
- )
518
- assert _check(source, PRODUCTION_FILE_PATH) == []
519
-
520
-
521
- def test_validate_content_runs_dead_argparse_check() -> None:
522
- source = (
523
- "import argparse\n"
524
- "\n"
525
- "def build() -> None:\n"
526
- " argument_parser = argparse.ArgumentParser()\n"
527
- " argument_parser.add_argument('--repo', default='.')\n"
528
- " parsed_arguments = argument_parser.parse_args()\n"
529
- " print('done')\n"
530
- )
531
- issues = code_rules_enforcer.validate_content(source, PRODUCTION_FILE_PATH)
532
- assert any("'repo'" in each_issue for each_issue in issues), (
533
- f"Expected the enforcer dispatch to surface the dead argument, got: {issues}"
534
- )