Skip to content

Commit 8b5d656

Browse files
committed
Add detail_context and PulpMasterContext
[noissue]
1 parent 98edb51 commit 8b5d656

File tree

8 files changed

+117
-73
lines changed

8 files changed

+117
-73
lines changed

CHANGES/pulp-glue/+cast.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added `detail_context` to master-detail contexts.

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ tests/cli.toml:
3434
@echo "In order to configure the tests to talk to your test server, you might need to edit $@ ."
3535

3636
test: | tests/cli.toml
37-
pytest -v tests
37+
pytest -v tests pulp-glue/tests
3838

3939
servedocs:
4040
mkdocs serve -w docs_theme -w pulp-glue/pulp_glue -w pulpcore/cli/common/generic.py

pulp-glue/pulp_glue/common/context.py

Lines changed: 37 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,36 @@ def needs_capability(self, capability: str) -> None:
10671067
)
10681068

10691069

1070-
class PulpRemoteContext(PulpEntityContext):
1070+
class PulpMasterContext(PulpEntityContext):
1071+
TYPE_REGISTRY: t.ClassVar[t.Dict[str, t.Type[t.Self]]]
1072+
1073+
def __init_subclass__(cls, **kwargs: t.Any) -> None:
1074+
super().__init_subclass__(**kwargs)
1075+
if not hasattr(cls, "RESOURCE_TYPE"):
1076+
cls.TYPE_REGISTRY = {}
1077+
elif hasattr(cls, "PLUGIN"):
1078+
cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls
1079+
1080+
def detail_context(self, pulp_href: str) -> t.Self:
1081+
"""
1082+
Provide a detail context for a matching href.
1083+
"""
1084+
m = re.search(self.HREF_PATTERN, pulp_href)
1085+
if m is None:
1086+
raise PulpException(f"'{pulp_href}' is not an href for {self.ENTITY}.")
1087+
plugin = m.group("plugin")
1088+
resource_type = m.group("resource_type")
1089+
try:
1090+
detail_class = self.TYPE_REGISTRY[f"{plugin}:{resource_type}"]
1091+
except KeyError:
1092+
raise PulpException(
1093+
f"{self.ENTITY} with plugin '{plugin}' and"
1094+
f"resource type '{resource_type}' is unknown."
1095+
)
1096+
return detail_class(self.pulp_ctx, pulp_href=pulp_href)
1097+
1098+
1099+
class PulpRemoteContext(PulpMasterContext):
10711100
"""
10721101
Base class for remote contexts.
10731102
"""
@@ -1093,27 +1122,15 @@ class PulpRemoteContext(PulpEntityContext):
10931122
"sock_read_timeout",
10941123
"rate_limit",
10951124
}
1096-
TYPE_REGISTRY: t.Dict[str, t.Type["PulpRemoteContext"]] = {}
1097-
1098-
def __init_subclass__(cls, **kwargs: t.Any) -> None:
1099-
super().__init_subclass__(**kwargs)
1100-
if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"):
1101-
cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls
11021125

11031126

1104-
class PulpPublicationContext(PulpEntityContext):
1127+
class PulpPublicationContext(PulpMasterContext):
11051128
"""Base class for publication contexts."""
11061129

11071130
ENTITY = _("publication")
11081131
ENTITIES = _("publications")
11091132
ID_PREFIX = "publications"
11101133
HREF_PATTERN = r"publications/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
1111-
TYPE_REGISTRY: t.Dict[str, t.Type["PulpPublicationContext"]] = {}
1112-
1113-
def __init_subclass__(cls, **kwargs: t.Any) -> None:
1114-
super().__init_subclass__(**kwargs)
1115-
if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"):
1116-
cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls
11171134

11181135
def list(self, limit: int, offset: int, parameters: t.Dict[str, t.Any]) -> t.List[t.Any]:
11191136
if parameters.get("repository") is not None:
@@ -1123,20 +1140,14 @@ def list(self, limit: int, offset: int, parameters: t.Dict[str, t.Any]) -> t.Lis
11231140
return super().list(limit, offset, parameters)
11241141

11251142

1126-
class PulpDistributionContext(PulpEntityContext):
1143+
class PulpDistributionContext(PulpMasterContext):
11271144
"""Base class for distribution contexts."""
11281145

11291146
ENTITY = _("distribution")
11301147
ENTITIES = _("distributions")
11311148
ID_PREFIX = "distributions"
11321149
HREF_PATTERN = r"distributions/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
11331150
NULLABLES = {"content_guard", "publication", "remote", "repository", "repository_version"}
1134-
TYPE_REGISTRY: t.Dict[str, t.Type["PulpDistributionContext"]] = {}
1135-
1136-
def __init_subclass__(cls, **kwargs: t.Any) -> None:
1137-
super().__init_subclass__(**kwargs)
1138-
if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"):
1139-
cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls
11401151

11411152

11421153
class PulpRepositoryVersionContext(PulpEntityContext):
@@ -1198,7 +1209,7 @@ def repair(self, href: t.Optional[str] = None) -> t.Any:
11981209
return self.call("repair", parameters={self.HREF: href or self.pulp_href}, body={})
11991210

12001211

1201-
class PulpRepositoryContext(PulpEntityContext):
1212+
class PulpRepositoryContext(PulpMasterContext):
12021213
"""Base class for repository contexts."""
12031214

12041215
ENTITY = _("repository")
@@ -1207,12 +1218,6 @@ class PulpRepositoryContext(PulpEntityContext):
12071218
ID_PREFIX = "repositories"
12081219
VERSION_CONTEXT: t.ClassVar[t.Type[PulpRepositoryVersionContext]] = PulpRepositoryVersionContext
12091220
NULLABLES = {"description", "retain_repo_versions"}
1210-
TYPE_REGISTRY: t.Dict[str, t.Type["PulpRepositoryContext"]] = {}
1211-
1212-
def __init_subclass__(cls, **kwargs: t.Any) -> None:
1213-
super().__init_subclass__(**kwargs)
1214-
if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"):
1215-
cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls
12161221

12171222
def get_version_context(
12181223
self,
@@ -1324,18 +1329,13 @@ def reclaim(
13241329
return self.call("reclaim_space_reclaim", body=body)
13251330

13261331

1327-
class PulpContentContext(PulpEntityContext):
1332+
class PulpContentContext(PulpMasterContext):
13281333
"""Base class for content contexts."""
13291334

13301335
ENTITY = _("content")
13311336
ENTITIES = _("content")
1337+
HREF_PATTERN = r"content/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
13321338
ID_PREFIX = "content"
1333-
TYPE_REGISTRY: t.Dict[str, t.Type["PulpContentContext"]] = {}
1334-
1335-
def __init_subclass__(cls, **kwargs: t.Any) -> None:
1336-
super().__init_subclass__(**kwargs)
1337-
if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"):
1338-
cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls
13391339

13401340
def upload(
13411341
self,
@@ -1376,38 +1376,26 @@ def upload(
13761376
return self.create(body=body)
13771377

13781378

1379-
class PulpACSContext(PulpEntityContext):
1379+
class PulpACSContext(PulpMasterContext):
13801380
"""Base class for ACS contexts."""
13811381

13821382
ENTITY = _("ACS")
13831383
ENTITIES = _("ACSes")
13841384
HREF_PATTERN = r"acs/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
13851385
ID_PREFIX = "acs"
1386-
TYPE_REGISTRY: t.Dict[str, t.Type["PulpACSContext"]] = {}
1387-
1388-
def __init_subclass__(cls, **kwargs: t.Any) -> None:
1389-
super().__init_subclass__(**kwargs)
1390-
if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"):
1391-
cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls
13921386

13931387
def refresh(self, href: t.Optional[str] = None) -> t.Any:
13941388
return self.call("refresh", parameters={self.HREF: href or self.pulp_href})
13951389

13961390

1397-
class PulpContentGuardContext(PulpEntityContext):
1391+
class PulpContentGuardContext(PulpMasterContext):
13981392
"""Base class for content guard contexts."""
13991393

14001394
ENTITY = "content guard"
14011395
ENTITIES = "content guards"
14021396
ID_PREFIX = "contentguards"
14031397
HREF_PATTERN = r"contentguards/(?P<plugin>[\w\-_]+)/(?P<resource_type>[\w\-_]+)/"
14041398
NULLABLES = {"description"}
1405-
TYPE_REGISTRY: t.Dict[str, t.Type["PulpContentGuardContext"]] = {}
1406-
1407-
def __init_subclass__(cls, **kwargs: t.Any) -> None:
1408-
super().__init_subclass__(**kwargs)
1409-
if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"):
1410-
cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls
14111399

14121400

14131401
EntityFieldDefinition = t.Union[None, str, PulpEntityContext]

pulp-glue/tests/conftest.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import typing as t
2+
3+
import pytest
4+
5+
from pulp_glue.common.context import PulpContext
6+
from pulp_glue.common.openapi import BasicAuthProvider
7+
8+
9+
class PulpTestContext(PulpContext):
10+
# TODO check if we can just make the base class ignore echo.
11+
def echo(*args, **kwargs) -> None:
12+
return
13+
14+
15+
@pytest.fixture
16+
def pulp_ctx(pulp_cli_settings: t.Dict[str, t.Dict[str, t.Any]]) -> PulpContext:
17+
settings = pulp_cli_settings["cli"]
18+
return PulpTestContext(
19+
api_kwargs={
20+
"base_url": settings["base_url"],
21+
"auth_provider": BasicAuthProvider(settings.get("username"), settings.get("password")),
22+
},
23+
api_root=settings.get("api_root", "pulp/"),
24+
background_tasks=False,
25+
timeout=settings.get("timeout", 120),
26+
)

tests/test_api_quirks.py renamed to pulp-glue/tests/test_api_quirks.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,18 @@
1-
import typing as t
21
from copy import deepcopy
32

43
import pytest
4+
55
from pulp_glue.common.context import _REGISTERED_API_QUIRKS, PulpContext
66

7+
pytestmark = pytest.mark.glue
8+
79

8-
@pytest.mark.glue
9-
def test_api_quirks_idempotent(
10-
pulp_cli_settings: t.Tuple[t.Any, t.Dict[str, t.Dict[str, t.Any]]]
11-
) -> None:
10+
def test_api_quirks_idempotent(pulp_ctx: PulpContext) -> None:
1211
"""
1312
Test, that the applied api quirks can be applied twice without failing.
1413
1514
This can let us hope they will not fail once the api is fixed upstream.
1615
"""
17-
settings = pulp_cli_settings[1]["cli"]
18-
pulp_ctx = PulpContext(
19-
api_kwargs={"base_url": settings["base_url"]},
20-
api_root=settings.get("api_root", "pulp/"),
21-
background_tasks=False,
22-
timeout=settings.get("timeout", 120),
23-
)
24-
2516
assert {
2617
"patch_content_in_query_filters",
2718
"patch_field_select_filters",
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import random
2+
import string
3+
import typing as t
4+
5+
import pytest
6+
7+
from pulp_glue.common.context import PulpContext, PulpRepositoryContext
8+
from pulp_glue.file.context import PulpFileRepositoryContext
9+
10+
pytestmark = pytest.mark.glue
11+
12+
13+
@pytest.fixture
14+
def file_repository(pulp_ctx: PulpContext) -> t.Dict[str, t.Any]:
15+
name = "".join(random.choices(string.ascii_letters, k=8))
16+
file_repository_ctx = PulpFileRepositoryContext(pulp_ctx)
17+
yield file_repository_ctx.create(body={"name": name})
18+
file_repository_ctx.delete()
19+
20+
21+
def test_detail_context(pulp_ctx: PulpContext, file_repository: t.Dict[str, t.Any]) -> None:
22+
master_ctx = PulpRepositoryContext(pulp_ctx)
23+
detail_ctx = master_ctx.detail_context(pulp_href=file_repository["pulp_href"])
24+
assert isinstance(detail_ctx, PulpFileRepositoryContext)
25+
assert detail_ctx.entity["name"] == file_repository["name"]

pulpcore/cli/common/context.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import warnings
2+
13
from pulp_glue.common.context import EntityDefinition # noqa: F401
24
from pulp_glue.common.context import (
35
EntityFieldDefinition,
@@ -15,6 +17,10 @@
1517
registered_repository_contexts,
1618
)
1719

20+
warnings.warn(
21+
DeprecationWarning("This module is deprecated. Import from pulp_glue.common.context instead.")
22+
)
23+
1824
__all__ = [
1925
"EntityDefinition",
2026
"EntityFieldDefinition",

pytest_pulp_cli/__init__.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def pulp_cli_vars() -> t.Dict[str, str]:
8282

8383

8484
@pytest.fixture(scope="session")
85-
def pulp_cli_settings(tmp_path_factory: pytest.TempPathFactory) -> t.Tuple[pathlib.Path, t.Any]:
85+
def pulp_cli_settings() -> t.Dict[str, t.Dict[str, t.Any]]:
8686
"""
8787
This fixture will setup the config file once per session only.
8888
It is most likely not useful to be included standalone.
@@ -92,11 +92,18 @@ def pulp_cli_settings(tmp_path_factory: pytest.TempPathFactory) -> t.Tuple[pathl
9292
if os.environ.get("PULP_API_ROOT"):
9393
for key in settings:
9494
settings[key]["api_root"] = os.environ["PULP_API_ROOT"]
95+
return settings
96+
97+
98+
@pytest.fixture(scope="session")
99+
def pulp_cli_settings_path(
100+
tmp_path_factory: pytest.TempPathFactory, pulp_cli_settings: t.Dict[str, t.Dict[str, t.Any]]
101+
) -> pathlib.Path:
95102
settings_path = tmp_path_factory.mktemp("config", numbered=False)
96103
(settings_path / "pulp").mkdir(parents=True)
97104
with open(settings_path / "pulp" / "cli.toml", "w") as settings_file:
98-
toml.dump(settings, settings_file)
99-
return settings_path, settings
105+
toml.dump(pulp_cli_settings, settings_file)
106+
return settings_path
100107

101108

102109
@pytest.fixture(scope="session")
@@ -122,11 +129,12 @@ def pulp_cli_gnupghome(tmp_path_factory: pytest.TempPathFactory) -> pathlib.Path
122129

123130
@pytest.fixture
124131
def pulp_cli_env(
125-
pulp_cli_settings: t.Tuple[pathlib.Path, t.Dict[str, t.Any]],
132+
pulp_cli_settings: t.Dict[str, t.Dict[str, t.Any]],
133+
pulp_cli_settings_path: pathlib.Path,
126134
pulp_cli_vars: t.Dict[str, str],
127135
pulp_cli_gnupghome: pathlib.Path,
128136
monkeypatch: pytest.MonkeyPatch,
129-
) -> t.Dict[str, t.Any]:
137+
) -> None:
130138
"""
131139
This fixture will set up the environment for cli commands by:
132140
@@ -135,16 +143,15 @@ def pulp_cli_env(
135143
* pointing XDG_CONFIG_HOME accordingly
136144
* supplying other useful environment vars
137145
"""
138-
settings_path, settings = pulp_cli_settings
139-
monkeypatch.setenv("XDG_CONFIG_HOME", str(settings_path))
140-
monkeypatch.setenv("PULP_BASE_URL", settings["cli"]["base_url"])
141-
monkeypatch.setenv("VERIFY_SSL", str(settings["cli"].get("verify_ssl", True)).lower())
146+
monkeypatch.setenv("XDG_CONFIG_HOME", str(pulp_cli_settings_path))
147+
monkeypatch.setenv("PULP_BASE_URL", pulp_cli_settings["cli"]["base_url"])
148+
monkeypatch.setenv("VERIFY_SSL", str(pulp_cli_settings["cli"].get("verify_ssl", True)).lower())
142149
monkeypatch.setenv("GNUPGHOME", str(pulp_cli_gnupghome))
143150

144151
for key, value in pulp_cli_vars.items():
145152
monkeypatch.setenv(key, value)
146153

147-
return settings
154+
return None
148155

149156

150157
if "PULP_LOGGING" in os.environ:

0 commit comments

Comments
 (0)