apexcodexpy 0.2.1__tar.gz → 0.2.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apexcodexpy
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: The Non-Destructive Configuration Steward for Python Projects.
5
5
  License-File: LICENSE
6
6
  Author: Apex Dev
@@ -0,0 +1,7 @@
1
+ from codex.typer import root_cli, testing_cli
2
+
3
+
4
+ def cli() -> None:
5
+ root_cli.add_typer(testing_cli, name="test", short_help="Run tests.")
6
+
7
+ root_cli()
@@ -8,34 +8,14 @@ from codex.tasks import ComboResult, DependabotYaml, PyProjectToml, TaskResult
8
8
  from codex.tools import MyPy, Pip, Poetry, Program, Ruff
9
9
 
10
10
 
11
- @dataclass(frozen=True)
12
- class CiMode:
13
- codex: Codex
14
-
15
- def lint(self) -> TaskResult:
16
- return (
17
- ComboResult()
18
- .attach(install=self.codex.install())
19
- .attach(lint=self.codex.lint())
20
- )
21
-
22
- def test(self) -> TaskResult:
23
- return (
24
- ComboResult()
25
- .attach(install=self.codex.install())
26
- .attach(pytest=Poetry().run(Pytest.on(self.codex.target).run()))
27
- )
28
-
29
-
30
11
  @dataclass(frozen=True)
31
12
  class Codex:
32
13
  target: Path
33
14
 
34
- def ci(self, on: bool) -> CiMode | Codex:
35
- if on:
36
- return CiMode(self)
15
+ in_ci: bool = False
37
16
 
38
- return self
17
+ def ci(self, on: bool) -> Codex:
18
+ return Codex(self.target, in_ci=on)
39
19
 
40
20
  def sync(self, dry_run: bool = False) -> TaskResult:
41
21
  return (
@@ -45,10 +25,17 @@ class Codex:
45
25
  )
46
26
 
47
27
  def install(self) -> TaskResult:
28
+ return self._install(when=True)
29
+
30
+ def _install(self, when: bool) -> ComboResult:
48
31
  return (
49
- ComboResult()
50
- .attach(tools=Pip().install("pip", "poetry"))
51
- .attach(dependencies=Poetry().install())
32
+ (
33
+ ComboResult()
34
+ .attach(tools=Pip().install("pip", "poetry"))
35
+ .attach(dependencies=Poetry().install())
36
+ )
37
+ if when
38
+ else ComboResult()
52
39
  )
53
40
 
54
41
  def lock(self) -> TaskResult:
@@ -59,7 +46,7 @@ class Codex:
59
46
 
60
47
  def lint(self) -> TaskResult:
61
48
  return (
62
- ComboResult()
49
+ self._install(when=self.in_ci)
63
50
  .attach(poetry=Poetry().lint(self.target))
64
51
  .attach(black=Poetry().run(Ruff(on=self.target).format().flag(check=True)))
65
52
  .attach(ruff=Poetry().run(Ruff(on=self.target).lint()))
@@ -78,21 +65,16 @@ class Codex:
78
65
  )
79
66
 
80
67
  def test(self) -> TaskResult:
81
- return ComboResult().attach(
82
- pytest=Poetry().run(
83
- Pytest.on(self.target).run(
84
- with_coverage=True,
85
- last_failed=True,
86
- )
87
- )
88
- )
68
+ return self._install(when=self.in_ci).attach(self.test_unit())
69
+
70
+ def test_unit(self) -> TaskResult:
71
+ return CodexTest(self.target).ci(on=self.in_ci).unit()
72
+
73
+ def test_integration(self) -> TaskResult:
74
+ return CodexTest(self.target).integration()
89
75
 
90
76
  def test_behaviour(self) -> TaskResult:
91
- return ComboResult().attach(
92
- behave=Poetry().run(
93
- Program("behave").append(self.target / "tests" / "features")
94
- )
95
- )
77
+ return CodexTest(self.target).behaviour()
96
78
 
97
79
  def build(self, tag: str) -> TaskResult:
98
80
  return (
@@ -121,6 +103,56 @@ class Codex:
121
103
  )
122
104
 
123
105
 
106
+ @dataclass(frozen=True)
107
+ class CodexTest:
108
+ target: Path
109
+
110
+ in_ci: bool = False
111
+
112
+ def ci(self, on: bool = False) -> CodexTest:
113
+ return CodexTest(self.target, in_ci=on)
114
+
115
+ def unit(self) -> TaskResult:
116
+ return ComboResult().attach(
117
+ pytest=Poetry().run(
118
+ Pytest.on(self.target).run(
119
+ with_coverage=self._when_not_in_ci(),
120
+ last_failed=self._when_not_in_ci(),
121
+ )
122
+ )
123
+ )
124
+
125
+ def _when_not_in_ci(self) -> bool | None:
126
+ return None if self.in_ci else True
127
+
128
+ def integration(self) -> TaskResult:
129
+ return (
130
+ ComboResult()
131
+ .attach(
132
+ setup=(
133
+ ComboResult()
134
+ .attach(tools=Pip().install("poetry", "poetry-plugin-export"))
135
+ .attach(export=Poetry().export(self.target))
136
+ )
137
+ )
138
+ .attach(
139
+ pytest=Poetry().run(
140
+ Pytest.on(self.target / "tests" / "integration").run()
141
+ )
142
+ )
143
+ .attach(
144
+ teardown=Program("rm").append(self.target / "requirements.txt").run()
145
+ )
146
+ )
147
+
148
+ def behaviour(self) -> TaskResult:
149
+ return ComboResult().attach(
150
+ behave=Poetry().run(
151
+ Program("behave").append(self.target / "tests" / "features")
152
+ )
153
+ )
154
+
155
+
124
156
  @dataclass(frozen=True)
125
157
  class Pytest:
126
158
  target: Path | None = None
@@ -37,10 +37,19 @@ class ComboResult:
37
37
 
38
38
  def attach(self, *args: TaskResult, **kwargs: TaskResult) -> ComboResult:
39
39
  for name, result in kwargs.items():
40
- self.results.append(result.named(name))
40
+ self._attach_one(result.named(name))
41
41
 
42
42
  for result in args:
43
- self.results.append(result)
43
+ self._attach_one(result)
44
+
45
+ return self
46
+
47
+ def _attach_one(self, result: TaskResult) -> ComboResult:
48
+ match result:
49
+ case ComboResult():
50
+ self.results.extend(result.results)
51
+ case _:
52
+ self.results.append(result)
44
53
 
45
54
  return self
46
55
 
@@ -0,0 +1,7 @@
1
+ from codex.typer.root import cli as root_cli
2
+ from codex.typer.testing import cli as testing_cli
3
+
4
+ __all__ = [
5
+ "root_cli",
6
+ "testing_cli",
7
+ ]
@@ -1,255 +1,192 @@
1
- from __future__ import annotations
2
-
3
- from pathlib import Path
4
-
5
- import typer
6
-
7
- from codex.reporters import DefaultReporter
8
- from codex.service import Codex, Git
9
-
10
- cli = typer.Typer(no_args_is_help=True)
11
-
12
-
13
- @cli.command(
14
- name="sync",
15
- help="Inject standards into pyproject TOML file.",
16
- )
17
- def _(
18
- path: str = typer.Option(
19
- ".",
20
- "--path",
21
- "-p",
22
- help="Target directory.",
23
- ),
24
- dry_run: bool = typer.Option(
25
- False,
26
- "--dry-run",
27
- help="Show changes without applying them.",
28
- ),
29
- ) -> None:
30
- (
31
- Codex(target=Path(path))
32
- .sync(dry_run=dry_run)
33
- .report(using=DefaultReporter())
34
- .exit(using=typer.Exit)
35
- )
36
-
37
-
38
- @cli.command(
39
- name="install",
40
- help="Install project tools and dependencies.",
41
- )
42
- def _(
43
- path: str = typer.Option(
44
- ".",
45
- "--path",
46
- "-p",
47
- help="Target directory.",
48
- ),
49
- ) -> None:
50
- (
51
- Codex(target=Path(path))
52
- .install()
53
- .report(using=DefaultReporter())
54
- .exit(using=typer.Exit)
55
- )
56
-
57
-
58
- @cli.command(
59
- name="lock",
60
- help="Lock project dependencies.",
61
- )
62
- def _() -> None:
63
- (
64
- Codex(target=Path("."))
65
- .lock()
66
- .report(using=DefaultReporter())
67
- .exit(using=typer.Exit)
68
- )
69
-
70
-
71
- @cli.command(
72
- name="update",
73
- help="Update project dependencies.",
74
- )
75
- def _() -> None:
76
- (
77
- Codex(target=Path("."))
78
- .update()
79
- .report(using=DefaultReporter())
80
- .exit(using=typer.Exit)
81
- )
82
-
83
-
84
- @cli.command(
85
- name="build",
86
- help="Build a Docker image.",
87
- )
88
- def _(
89
- tag: str = typer.Option(
90
- ...,
91
- "--tag",
92
- "-t",
93
- help="Target tag, e.g. my-project:latest",
94
- ),
95
- path: str = typer.Option(
96
- ".",
97
- "--path",
98
- "-p",
99
- help="Target directory.",
100
- ),
101
- ) -> None:
102
- (
103
- Codex(target=Path(path))
104
- .build(tag=tag)
105
- .report(using=DefaultReporter())
106
- .exit(using=typer.Exit)
107
- )
108
-
109
-
110
- @cli.command(
111
- name="lint",
112
- help="Run linting (Ruff) and type checking (MyPy).",
113
- )
114
- def _(
115
- path: str = typer.Option(
116
- ".",
117
- "--path",
118
- "-p",
119
- help="Target directory.",
120
- ),
121
- ci: bool = typer.Option(
122
- False,
123
- "--ci",
124
- help="Run in CI mode.",
125
- ),
126
- silent: bool = typer.Option(
127
- False,
128
- "--silent",
129
- "-s",
130
- help="Suppress output.",
131
- ),
132
- ) -> None:
133
- (
134
- Codex(target=Path(path))
135
- .ci(on=ci)
136
- .lint()
137
- .silenced(when=silent)
138
- .report(using=DefaultReporter())
139
- .exit(using=typer.Exit)
140
- )
141
-
142
-
143
- @cli.command(
144
- name="fix",
145
- help="Automatically fix Ruff linting errors.",
146
- )
147
- def _(
148
- path: str = typer.Option(
149
- ".",
150
- "--path",
151
- "-p",
152
- help="Target directory.",
153
- ),
154
- silent: bool = typer.Option(
155
- False,
156
- "--silent",
157
- "-s",
158
- help="Suppress output.",
159
- ),
160
- unsafe: bool = typer.Option(
161
- False,
162
- "--unsafe",
163
- help="Run unsafe Ruff fixes.",
164
- ),
165
- ) -> None:
166
- (
167
- Codex(target=Path(path))
168
- .fix(unsafe=unsafe)
169
- .silenced(when=silent)
170
- .report(using=DefaultReporter())
171
- .exit(using=typer.Exit)
172
- )
173
-
174
-
175
- @cli.command(
176
- name="amend",
177
- help="Amend the last git commit without changing the message.",
178
- )
179
- def _() -> None:
180
- Git().amend().report(using=DefaultReporter()).exit(using=typer.Exit)
181
-
182
-
183
- test_cli = typer.Typer()
184
- cli.add_typer(test_cli, name="test", short_help="Run tests.")
185
-
186
-
187
- @test_cli.callback(invoke_without_command=True)
188
- def _(ctx: typer.Context) -> None:
189
- if ctx.invoked_subcommand is not None:
190
- return
191
-
192
- run_unit_tests(path=".", ci=False)
193
-
194
-
195
- @test_cli.command(
196
- name="unit",
197
- help="Run programmer tests.",
198
- )
199
- def run_unit_tests(
200
- path: str = typer.Option(
201
- ".",
202
- "--path",
203
- "-p",
204
- help="Target directory.",
205
- ),
206
- ci: bool = typer.Option(
207
- False,
208
- "--ci",
209
- help="Run in CI mode.",
210
- ),
211
- ) -> None:
212
- (
213
- Codex(target=Path(path))
214
- .ci(on=ci)
215
- .test()
216
- .report(using=DefaultReporter())
217
- .exit(using=typer.Exit)
218
- )
219
-
220
-
221
- @test_cli.command(
222
- name="integration",
223
- help="Run integration tests.",
224
- )
225
- def _(
226
- ci: bool = typer.Option(
227
- False,
228
- "--ci",
229
- help="Run in CI mode.",
230
- ),
231
- ) -> None:
232
- (
233
- Codex(target=Path("./tests/integration"))
234
- .ci(on=ci)
235
- .test()
236
- .report(using=DefaultReporter())
237
- .exit(using=typer.Exit)
238
- )
239
-
240
-
241
- @test_cli.command(
242
- name="behaviour",
243
- help="Run behaviour tests.",
244
- )
245
- def _() -> None:
246
- (
247
- Codex(target=Path("."))
248
- .test_behaviour()
249
- .report(using=DefaultReporter())
250
- .exit(using=typer.Exit)
251
- )
252
-
253
-
254
- if __name__ == "__main__":
255
- cli()
1
+ from pathlib import Path
2
+
3
+ import typer
4
+
5
+ from codex.reporters import DefaultReporter
6
+ from codex.service import Codex, Git
7
+
8
+ cli = typer.Typer(no_args_is_help=True)
9
+
10
+
11
+ @cli.command(
12
+ name="sync",
13
+ help="Inject standards into pyproject TOML file.",
14
+ )
15
+ def _(
16
+ path: str = typer.Option(
17
+ ".",
18
+ "--path",
19
+ "-p",
20
+ help="Target directory.",
21
+ ),
22
+ dry_run: bool = typer.Option(
23
+ False,
24
+ "--dry-run",
25
+ help="Show changes without applying them.",
26
+ ),
27
+ ) -> None:
28
+ (
29
+ Codex(target=Path(path))
30
+ .sync(dry_run=dry_run)
31
+ .report(using=DefaultReporter())
32
+ .exit(using=typer.Exit)
33
+ )
34
+
35
+
36
+ @cli.command(
37
+ name="install",
38
+ help="Install project tools and dependencies.",
39
+ )
40
+ def _(
41
+ path: str = typer.Option(
42
+ ".",
43
+ "--path",
44
+ "-p",
45
+ help="Target directory.",
46
+ ),
47
+ ) -> None:
48
+ (
49
+ Codex(target=Path(path))
50
+ .install()
51
+ .report(using=DefaultReporter())
52
+ .exit(using=typer.Exit)
53
+ )
54
+
55
+
56
+ @cli.command(
57
+ name="lock",
58
+ help="Lock project dependencies.",
59
+ )
60
+ def _(
61
+ path: str = typer.Option(
62
+ ".",
63
+ "--path",
64
+ "-p",
65
+ help="Target directory.",
66
+ ),
67
+ ) -> None:
68
+ (
69
+ Codex(target=Path(path))
70
+ .lock()
71
+ .report(using=DefaultReporter())
72
+ .exit(using=typer.Exit)
73
+ )
74
+
75
+
76
+ @cli.command(
77
+ name="update",
78
+ help="Update project dependencies.",
79
+ )
80
+ def _(
81
+ path: str = typer.Option(
82
+ ".",
83
+ "--path",
84
+ "-p",
85
+ help="Target directory.",
86
+ ),
87
+ ) -> None:
88
+ (
89
+ Codex(target=Path(path))
90
+ .update()
91
+ .report(using=DefaultReporter())
92
+ .exit(using=typer.Exit)
93
+ )
94
+
95
+
96
+ @cli.command(
97
+ name="build",
98
+ help="Build a Docker image.",
99
+ )
100
+ def _(
101
+ tag: str = typer.Option(
102
+ ...,
103
+ "--tag",
104
+ "-t",
105
+ help="Target tag, e.g. my-project:latest",
106
+ ),
107
+ path: str = typer.Option(
108
+ ".",
109
+ "--path",
110
+ "-p",
111
+ help="Target directory.",
112
+ ),
113
+ ) -> None:
114
+ (
115
+ Codex(target=Path(path))
116
+ .build(tag=tag)
117
+ .report(using=DefaultReporter())
118
+ .exit(using=typer.Exit)
119
+ )
120
+
121
+
122
+ @cli.command(
123
+ name="lint",
124
+ help="Run linting (Ruff) and type checking (MyPy).",
125
+ )
126
+ def _(
127
+ path: str = typer.Option(
128
+ ".",
129
+ "--path",
130
+ "-p",
131
+ help="Target directory.",
132
+ ),
133
+ ci: bool = typer.Option(
134
+ False,
135
+ "--ci",
136
+ help="Run in CI mode.",
137
+ ),
138
+ silent: bool = typer.Option(
139
+ False,
140
+ "--silent",
141
+ "-s",
142
+ help="Suppress output.",
143
+ ),
144
+ ) -> None:
145
+ (
146
+ Codex(target=Path(path))
147
+ .ci(on=ci)
148
+ .lint()
149
+ .silenced(when=silent)
150
+ .report(using=DefaultReporter())
151
+ .exit(using=typer.Exit)
152
+ )
153
+
154
+
155
+ @cli.command(
156
+ name="fix",
157
+ help="Automatically fix Ruff linting errors.",
158
+ )
159
+ def _(
160
+ path: str = typer.Option(
161
+ ".",
162
+ "--path",
163
+ "-p",
164
+ help="Target directory.",
165
+ ),
166
+ silent: bool = typer.Option(
167
+ False,
168
+ "--silent",
169
+ "-s",
170
+ help="Suppress output.",
171
+ ),
172
+ unsafe: bool = typer.Option(
173
+ False,
174
+ "--unsafe",
175
+ help="Run unsafe Ruff fixes.",
176
+ ),
177
+ ) -> None:
178
+ (
179
+ Codex(target=Path(path))
180
+ .fix(unsafe=unsafe)
181
+ .silenced(when=silent)
182
+ .report(using=DefaultReporter())
183
+ .exit(using=typer.Exit)
184
+ )
185
+
186
+
187
+ @cli.command(
188
+ name="amend",
189
+ help="Amend the last git commit without changing the message.",
190
+ )
191
+ def _() -> None:
192
+ Git().amend().report(using=DefaultReporter()).exit(using=typer.Exit)
@@ -0,0 +1,94 @@
1
+ from pathlib import Path
2
+
3
+ import typer
4
+
5
+ from codex.reporters import DefaultReporter
6
+ from codex.service import Codex
7
+
8
+ cli = typer.Typer()
9
+
10
+
11
+ @cli.command(
12
+ name="unit",
13
+ help="Run programmer tests.",
14
+ )
15
+ def run_unit_tests(
16
+ path: str = typer.Option(
17
+ ".",
18
+ "--path",
19
+ "-p",
20
+ help="Target directory.",
21
+ ),
22
+ ci: bool = typer.Option(
23
+ False,
24
+ "--ci",
25
+ help="Run in CI mode.",
26
+ ),
27
+ ) -> None:
28
+ (
29
+ Codex(target=Path(path))
30
+ .ci(on=ci)
31
+ .test()
32
+ .report(using=DefaultReporter())
33
+ .exit(using=typer.Exit)
34
+ )
35
+
36
+
37
+ @cli.command(
38
+ name="integration",
39
+ help="Run integration tests.",
40
+ )
41
+ def _(
42
+ path: str = typer.Option(
43
+ ".",
44
+ "--path",
45
+ "-p",
46
+ help="Target directory.",
47
+ ),
48
+ ci: bool = typer.Option(
49
+ False,
50
+ "--ci",
51
+ help="Run in CI mode.",
52
+ ),
53
+ ) -> None:
54
+ (
55
+ Codex(target=Path(path))
56
+ .ci(on=ci)
57
+ .test_integration()
58
+ .report(using=DefaultReporter())
59
+ .exit(using=typer.Exit)
60
+ )
61
+
62
+
63
+ @cli.command(
64
+ name="behaviour",
65
+ help="Run behaviour tests.",
66
+ )
67
+ def _(
68
+ path: str = typer.Option(
69
+ ".",
70
+ "--path",
71
+ "-p",
72
+ help="Target directory.",
73
+ ),
74
+ ci: bool = typer.Option(
75
+ False,
76
+ "--ci",
77
+ help="Run in CI mode.",
78
+ ),
79
+ ) -> None:
80
+ (
81
+ Codex(target=Path(path))
82
+ .ci(on=ci)
83
+ .test_behaviour()
84
+ .report(using=DefaultReporter())
85
+ .exit(using=typer.Exit)
86
+ )
87
+
88
+
89
+ @cli.callback(invoke_without_command=True)
90
+ def _(ctx: typer.Context) -> None:
91
+ if ctx.invoked_subcommand is not None:
92
+ return
93
+
94
+ run_unit_tests(path=".", ci=False)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "apexcodexpy"
3
- version = "0.2.1"
3
+ version = "0.2.3"
4
4
  description = "The Non-Destructive Configuration Steward for Python Projects."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -10,7 +10,7 @@ dynamic = ["dependencies"]
10
10
  requires-python = ">=3.11"
11
11
 
12
12
  [project.scripts]
13
- codex = "codex.cli:cli"
13
+ codex = "codex.runner:cli"
14
14
 
15
15
  [tool.poetry]
16
16
  packages = [
File without changes
File without changes
File without changes