Skip to content

Commit 0556d15

Browse files
authored
Don't import modules into packages and fix tests (#68)
- Fix wrong documentation reference - Use a dict to map repo types to owners - Split too long line - Return proper type in cookiecutter local extensions - Install the local development version in integration tests - Don't import modules into packages - Import default nox sessions by default - Fix passing of nox config - Add a `nox.configure()` overload that takes a `RepositoryType` Fixes #46.
2 parents ff43702 + 88588ad commit 0556d15

File tree

9 files changed

+143
-64
lines changed

9 files changed

+143
-64
lines changed

cookiecutter/hooks/post_gen_project.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,8 @@ def print_todos() -> None:
318318
print()
319319
note(
320320
"Make sure to (create and) configure your GitHub repository too: "
321-
"https://github.com/frequenz-floss/frequenz-repo-config-python/wiki/Configuring-a-new-GitHub-repository"
321+
"https://github.com/frequenz-floss/frequenz-repo-config-python/"
322+
"wiki/Configuring-a-new-GitHub-repository"
322323
)
323324

324325

cookiecutter/local_extensions.py

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def _get_from_json(key: str) -> str:
3737
The string from the cookiecutter.json file.
3838
"""
3939
with open("../cookiecutter.json", encoding="utf8") as cookiecutter_json_file:
40-
return _json.load(cookiecutter_json_file)[key]
40+
return str(_json.load(cookiecutter_json_file)[key])
4141

4242

4343
# Ignoring because cookiecutter simple_filter decorator is not typed.
@@ -170,22 +170,16 @@ def default_codeowners(cookiecutter: dict[str, str]) -> str:
170170
if github_org != "frequenz-floss":
171171
return f"TODO(cookiecutter): Add codeowners (like @{github_org}/some-team)"
172172

173-
match repo_type:
174-
case "actor":
175-
return (
176-
"TODO(cookiecutter): Add codeowners (like @{github_org}/some-team)"
177-
"# Temporary, should probably change"
178-
)
179-
case "api":
180-
return "@freqenz-floss/api-team"
181-
case "lib":
182-
return "@freqenz-floss/python-sdk-team"
183-
case "app":
184-
return (
185-
"@freqenz-floss/python-sdk-team @frequenz-floss/datasci-team "
186-
"# Temporary, should probably change"
187-
)
188-
case "model":
189-
return "@freqenz-floss/datasci-team"
190-
case _:
191-
assert False, f"Unhandled repository type {repo_type!r}"
173+
type_to_team = {
174+
"actor": "TODO(cookiecutter): Add codeowners (like @{github_org}/some-team)"
175+
"# Temporary, should probably change",
176+
"api": "@frequenz-floss/api-team",
177+
"lib": "@frequenz-floss/python-sdk-team",
178+
"app": "@frequenz-floss/python-sdk-team @frequenz-floss/datasci-team "
179+
"# Temporary, should probably change",
180+
"model": "@frequenz-floss/datasci-team",
181+
}
182+
183+
assert repo_type in type_to_team, f"Unhandled repository type {repo_type!r}"
184+
185+
return type_to_team[repo_type]

cookiecutter/{{cookiecutter.github_repo_name}}/noxfile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33

44
"""Configuration file for nox."""
55

6-
from frequenz.repo.config import nox
6+
from frequenz.repo.config import RepositoryType, nox
77

8-
nox.configure(nox.default.{{cookiecutter.type}}_config)
8+
nox.configure(RepositoryType.{{cookiecutter.type | upper}})

noxfile.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
"""Configuration file for nox."""
55

66
from frequenz.repo.config import nox
7+
from frequenz.repo.config.nox import default
78

8-
config = nox.default.lib_config.copy()
9+
config = default.lib_config.copy()
910
config.extra_paths.extend(
1011
[
1112
"cookiecutter/hooks",
1213
"cookiecutter/local_extensions.py",
1314
]
1415
)
15-
nox.configure(nox.default.lib_config)
16+
nox.configure(config)

src/frequenz/repo/config/__init__.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
The tools are provided to configure the main types of repositories most commonly used at
77
Frequenz, defined in
8-
[`freq.repo.config.RepositoryType`][freq.repo.config.RepositoryType].
8+
[`frequenz.repo.config.RepositoryType`][].
99
1010
- actor: SDK actors
1111
- api: gRPC APIs
@@ -26,26 +26,28 @@
2626
package and use the [`frequenz.repo.config.nox.configure`][] function,
2727
which will configure all nox sessions.
2828
29-
You should call `configure()` using one of the default configurations provided
30-
in the [`frequenz.repo.config.nox.default`][] module. For example:
29+
To use the default options, you should call `configure()` using one of the [repository
30+
types][frequenz.repo.config.RepositoryType]. For example:
3131
3232
```python
33-
from frequenz.repo.config import nox
33+
from frequenz.repo.config import RepositoryType, nox
3434
35-
nox.configure(nox.default.lib_config)
35+
nox.configure(RepositoryType.LIB)
3636
```
3737
38-
Again, make sure to pick the correct default configuration based on the type of your
38+
Again, make sure to pick the correct project typedefault configuration based on the type of your
3939
project (`actor_config`, `api_config`, `app_config`, `lib_config`, `model_config`).
4040
41-
If you need to modify the configuration, you can copy one of the default
42-
configurations by using the
43-
[`copy()`][frequenz.repo.config.nox.config.Config.copy] method:
41+
If you need to use some custom configuration, you can start from the default settings in
42+
the [`frequenz.repo.config.nox.default`][] module,
43+
[copying][frequenz.repo.config.nox.config.Config.copy] it and changing whatever you
44+
need to customize. For example:
4445
4546
```python
4647
from frequenz.repo.config import nox
48+
from frequenz.repo.config.nox import default
4749
48-
config = nox.default.lib_config.copy()
50+
config = default.lib_config.copy()
4951
config.opts.black.append("--diff")
5052
nox.configure(config)
5153
```
@@ -330,12 +332,8 @@
330332
defaults.
331333
"""
332334

333-
from . import mkdocs, nox, setuptools
334335
from ._core import RepositoryType
335336

336337
__all__ = [
337338
"RepositoryType",
338-
"mkdocs",
339-
"nox",
340-
"setuptools",
341339
]

src/frequenz/repo/config/nox/__init__.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,30 @@
66
The main entry point is the [`configure()`][configure] function, which will
77
configure all nox sessions according to some configuration.
88
9-
You should call `configure()` using one of the default configurations provided
10-
in the [`default`][] module. For example:
9+
To use the default options, you should call `configure()` using one of the [repository
10+
types][frequenz.repo.config.RepositoryType]. For example:
1111
1212
```python
13-
from frequenz.repo import config
13+
from frequenz.repo.config import RepositoryType, nox
1414
15-
config.nox.configure(config.nox.default.lib_config)
15+
nox.configure(RepositoryType.LIB)
1616
```
1717
18-
If you need to modify the configuration, you can copy one of the default
19-
configurations by using the
20-
[`copy()`][frequenz.repo.config.nox.config.Config.copy] method:
18+
Again, make sure to pick the correct project typedefault configuration based on the type of your
19+
project (`actor_config`, `api_config`, `app_config`, `lib_config`, `model_config`).
20+
21+
If you need to use some custom configuration, you can start from the default settings in
22+
the [`frequenz.repo.config.nox.default`][] module,
23+
[copying][frequenz.repo.config.nox.config.Config.copy] it and changing whatever you
24+
need to customize. For example:
2125
2226
```python
23-
from frequenz.repo import config
27+
from frequenz.repo.config import nox
28+
from frequenz.repo.config.nox import default
2429
25-
conf = config.nox.default.lib_config.copy()
26-
conf.opts.black.append("--diff")
27-
config.nox.configure(conf)
30+
config = default.lib_config.copy()
31+
config.opts.black.append("--diff")
32+
nox.configure(config)
2833
```
2934
3035
If you need further customization or to define new sessions, you can use the
@@ -41,13 +46,8 @@
4146
- [`util`][]: General purpose utility functions.
4247
"""
4348

44-
from . import config, default, session, util
4549
from .config import configure
4650

4751
__all__ = [
48-
"config",
4952
"configure",
50-
"default",
51-
"session",
52-
"util",
5353
]

src/frequenz/repo/config/nox/config.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414

1515
import dataclasses as _dataclasses
1616
import itertools as _itertools
17-
from typing import Self
17+
from typing import Self, assert_never, overload
1818

1919
import nox as _nox
2020

21+
from .._core import RepositoryType
2122
from . import util as _util
2223

2324

@@ -177,12 +178,73 @@ def get() -> Config:
177178
return _config
178179

179180

180-
def configure(conf: Config, /) -> None:
181+
@overload
182+
def configure(conf: Config, /, *, import_default_sessions: bool = True) -> None:
181183
"""Configure nox using the provided configuration.
182184
183185
Args:
184186
conf: The configuration to use to configure nox.
187+
import_default_sessions: Whether to import the default sessions or not.
188+
This is only necessary if you want to avoid using the default provided
189+
sessions and use your own.
190+
"""
191+
192+
193+
@overload
194+
def configure(
195+
repo_type: RepositoryType, /, *, import_default_sessions: bool = True
196+
) -> None:
197+
"""Configure nox using the provided repository type.
198+
199+
Args:
200+
repo_type: The repository type to use to configure nox. This will use the
201+
default configuration in [`frequenz.repo.config.nox.default`][] for that
202+
type of repository.
203+
import_default_sessions: Whether to import the default sessions or not.
204+
This is only necessary if you want to avoid using the default provided
205+
sessions and use your own.
206+
"""
207+
208+
209+
def configure(
210+
conf: Config | RepositoryType, /, *, import_default_sessions: bool = True
211+
) -> None:
212+
"""Configure nox using the provided configuration or repository type.
213+
214+
Args:
215+
conf: The configuration to use to configure nox, or the repository type to use
216+
to configure nox. The later will use the default configuration in
217+
[`frequenz.repo.config.nox.default`][] for that type of repository.
218+
import_default_sessions: Whether to import the default sessions or not.
219+
This is only necessary if you want to avoid using the default provided
220+
sessions and use your own.
185221
"""
186222
global _config # pylint: disable=global-statement
187-
_config = conf
223+
224+
# We need to make sure sessions are imported, otherwise they won't be visible to nox.
225+
if import_default_sessions:
226+
# pylint: disable=import-outside-toplevel,cyclic-import
227+
from . import session as _
228+
229+
match conf:
230+
case Config():
231+
_config = conf
232+
case RepositoryType() as repo_type:
233+
# pylint: disable=import-outside-toplevel,cyclic-import
234+
from . import default
235+
236+
match repo_type:
237+
case RepositoryType.ACTOR:
238+
_config = default.actor_config
239+
case RepositoryType.API:
240+
_config = default.api_config
241+
case RepositoryType.APP:
242+
_config = default.app_config
243+
case RepositoryType.LIB:
244+
_config = default.lib_config
245+
case RepositoryType.MODEL:
246+
_config = default.model_config
247+
case _ as unhandled:
248+
assert_never(unhandled)
249+
188250
_nox.options.sessions = _config.sessions

src/frequenz/repo/config/setuptools/__init__.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,3 @@
22
# Copyright © 2023 Frequenz Energy-as-a-Service GmbH
33

44
"""Setuptools utilities."""
5-
6-
from . import grpc_tools
7-
8-
__all__ = [
9-
"grpc_tools",
10-
]

tests/integration/test_cookiecutter_generation.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""Generation tests for cookiecutter."""
55

66
import pathlib
7+
import re
78
import subprocess
89

910
import pytest
@@ -31,6 +32,10 @@ def test_generation(tmp_path: pathlib.Path, repo_type: str) -> None:
3132
repo_path = subdirs[0]
3233
_run(repo_path, "python3", "-m", "venv", ".venv")
3334

35+
_update_pyproject_repo_config_dep(
36+
repo_config_path=cwd, repo_type=repo_type, repo_path=repo_path
37+
)
38+
3439
cmd = ". .venv/bin/activate; pip install .[dev-noxfile]; nox"
3540
print()
3641
print(f"Running in shell [{cwd}]: {cmd}")
@@ -43,3 +48,27 @@ def _run(cwd: pathlib.Path, *cmd: str) -> subprocess.CompletedProcess[bytes]:
4348
print(f"Running [{cwd}]: {' '.join(cmd)}")
4449
print()
4550
return subprocess.run(cmd, cwd=cwd, check=True)
51+
52+
53+
def _update_pyproject_repo_config_dep(
54+
*, repo_config_path: pathlib.Path, repo_type: str, repo_path: pathlib.Path
55+
) -> None:
56+
"""Update the repo config dependency in the generated pyproject.toml.
57+
58+
This is necessary to make sure we are testing the local version of
59+
`frequenz-repo-config`, otherwise tests will fail because they will be running with
60+
an older (released) version of `frequenz-repo-config`.
61+
62+
Args:
63+
repo_config_path: Path to the local `frequenz-repo-config` repo.
64+
repo_type: Type of the repo to generate.
65+
repo_path: Path to the generated repo.
66+
"""
67+
repo_config_dep = f"frequenz-repo-config[{repo_type}] @ file://{repo_config_path}"
68+
repo_config_dep_re = re.compile(rf"""frequenz-repo-config\[{repo_type}\][^"]+""")
69+
70+
with open(repo_path / "pyproject.toml", encoding="utf8") as pyproject_file:
71+
pyproject_content = pyproject_file.read()
72+
73+
with open(repo_path / "pyproject.toml", "w", encoding="utf8") as pyproject_file:
74+
pyproject_file.write(repo_config_dep_re.sub(repo_config_dep, pyproject_content))

0 commit comments

Comments
 (0)