diracx-cli 0.0.1a17__tar.gz → 0.0.1a19__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 (28) hide show
  1. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/PKG-INFO +2 -2
  2. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/pyproject.toml +11 -1
  3. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx/cli/__init__.py +20 -4
  4. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx/cli/internal/__init__.py +5 -8
  5. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx/cli/internal/legacy.py +8 -9
  6. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx/cli/jobs.py +11 -2
  7. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx_cli.egg-info/PKG-INFO +2 -2
  8. diracx_cli-0.0.1a19/src/diracx_cli.egg-info/entry_points.txt +9 -0
  9. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/tests/legacy/cs_sync/integration_test.cfg +0 -2
  10. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/tests/legacy/cs_sync/integration_test.yaml +0 -2
  11. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/tests/test_jobs.py +2 -6
  12. diracx_cli-0.0.1a17/src/diracx_cli.egg-info/entry_points.txt +0 -2
  13. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/README.md +0 -0
  14. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/setup.cfg +0 -0
  15. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx/cli/__main__.py +0 -0
  16. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx/cli/config.py +0 -0
  17. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx/cli/py.typed +0 -0
  18. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx/cli/utils.py +0 -0
  19. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx_cli.egg-info/SOURCES.txt +0 -0
  20. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx_cli.egg-info/dependency_links.txt +0 -0
  21. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx_cli.egg-info/requires.txt +0 -0
  22. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/src/diracx_cli.egg-info/top_level.txt +0 -0
  23. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/tests/legacy/cs_sync/integration_test_buggy.cfg +0 -0
  24. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/tests/legacy/cs_sync/integration_test_secret.cfg +0 -0
  25. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/tests/legacy/cs_sync/test_cssync.py +0 -0
  26. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/tests/legacy/test_legacy.py +0 -0
  27. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/tests/test_internal.py +0 -0
  28. {diracx_cli-0.0.1a17 → diracx_cli-0.0.1a19}/tests/test_login.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: diracx-cli
3
- Version: 0.0.1a17
3
+ Version: 0.0.1a19
4
4
  Summary: TODO
5
5
  License: GPL-3.0-only
6
6
  Classifier: Intended Audience :: Science/Research
@@ -8,7 +8,7 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Topic :: Scientific/Engineering
10
10
  Classifier: Topic :: System :: Distributed Computing
11
- Requires-Python: >=3.10
11
+ Requires-Python: >=3.11
12
12
  Description-Content-Type: text/markdown
13
13
  Requires-Dist: diraccfg
14
14
  Requires-Dist: diracx-api
@@ -2,7 +2,7 @@
2
2
  name = "diracx-cli"
3
3
  description = "TODO"
4
4
  readme = "README.md"
5
- requires-python = ">=3.10"
5
+ requires-python = ">=3.11"
6
6
  keywords = []
7
7
  license = {text = "GPL-3.0-only"}
8
8
  classifiers = [
@@ -36,6 +36,15 @@ types = [
36
36
  [project.scripts]
37
37
  dirac = "diracx.cli:app"
38
38
 
39
+ [project.entry-points."diracx.cli"]
40
+ jobs = "diracx.cli.jobs:app"
41
+ config = "diracx.cli.config:app"
42
+
43
+ [project.entry-points."diracx.cli.hidden"]
44
+ internal = "diracx.cli.internal:app"
45
+
46
+
47
+
39
48
  [tool.setuptools.packages.find]
40
49
  where = ["src"]
41
50
 
@@ -58,3 +67,4 @@ asyncio_mode = "auto"
58
67
  markers = [
59
68
  "enabled_dependencies: List of dependencies which should be available to the FastAPI test client",
60
69
  ]
70
+ asyncio_default_fixture_loop_scope = "session"
@@ -8,10 +8,10 @@ import typer
8
8
 
9
9
  from diracx.client.aio import DiracClient
10
10
  from diracx.client.models import DeviceFlowErrorResponse
11
+ from diracx.core.extensions import select_from_extension
11
12
  from diracx.core.preferences import get_diracx_preferences
12
13
  from diracx.core.utils import write_credentials
13
14
 
14
- from . import config, internal, jobs
15
15
  from .utils import AsyncTyper
16
16
 
17
17
  app = AsyncTyper()
@@ -115,9 +115,25 @@ def callback(output_format: Optional[str] = None):
115
115
  os.environ["DIRACX_OUTPUT_FORMAT"] = output_format
116
116
 
117
117
 
118
- app.add_typer(jobs.app, name="jobs")
119
- app.add_typer(config.app, name="config")
120
- app.add_typer(internal.app, name="internal", hidden=True)
118
+ # Load all the sub commands
119
+
120
+ cli_names = set(
121
+ [entry_point.name for entry_point in select_from_extension(group="diracx.cli")]
122
+ )
123
+ for cli_name in cli_names:
124
+ entry_point = select_from_extension(group="diracx.cli", name=cli_name)[0]
125
+ app.add_typer(entry_point.load(), name=entry_point.name)
126
+
127
+
128
+ cli_hidden_names = set(
129
+ [
130
+ entry_point.name
131
+ for entry_point in select_from_extension(group="diracx.cli.hidden")
132
+ ]
133
+ )
134
+ for cli_name in cli_hidden_names:
135
+ entry_point = select_from_extension(group="diracx.cli.hidden", name=cli_name)[0]
136
+ app.add_typer(entry_point.load(), name=entry_point.name, hidden=True)
121
137
 
122
138
 
123
139
  if __name__ == "__main__":
@@ -26,7 +26,7 @@ app.add_typer(legacy.app, name="legacy")
26
26
 
27
27
  @app.command()
28
28
  def generate_cs(config_repo: str):
29
- """Generate a minimal DiracX configuration repository"""
29
+ """Generate a minimal DiracX configuration repository."""
30
30
  # TODO: The use of TypeAdapter should be moved in to typer itself
31
31
  config_repo = TypeAdapter(ConfigSourceUrl).validate_python(config_repo)
32
32
  if config_repo.scheme != "git+file" or config_repo.path is None:
@@ -58,8 +58,7 @@ def add_vo(
58
58
  idp_url: Annotated[str, typer.Option()],
59
59
  idp_client_id: Annotated[str, typer.Option()],
60
60
  ):
61
- """Add a registry entry (vo) to an existing configuration repository"""
62
-
61
+ """Add a registry entry (vo) to an existing configuration repository."""
63
62
  # TODO: The use of TypeAdapter should be moved in to typer itself
64
63
  config_repo = TypeAdapter(ConfigSourceUrl).validate_python(config_repo)
65
64
  if config_repo.scheme != "git+file" or config_repo.path is None:
@@ -102,8 +101,7 @@ def add_group(
102
101
  group: Annotated[str, typer.Option()],
103
102
  properties: list[str] = ["NormalUser"],
104
103
  ):
105
- """Add a group to an existing vo in the configuration repository"""
106
-
104
+ """Add a group to an existing vo in the configuration repository."""
107
105
  # TODO: The use of TypeAdapter should be moved in to typer itself
108
106
  config_repo = TypeAdapter(ConfigSourceUrl).validate_python(config_repo)
109
107
  if config_repo.scheme != "git+file" or config_repo.path is None:
@@ -139,8 +137,7 @@ def add_user(
139
137
  sub: Annotated[str, typer.Option()],
140
138
  preferred_username: Annotated[str, typer.Option()],
141
139
  ):
142
- """Add a user to an existing vo and group"""
143
-
140
+ """Add a user to an existing vo and group."""
144
141
  # TODO: The use of TypeAdapter should be moved in to typer itself
145
142
  config_repo = TypeAdapter(ConfigSourceUrl).validate_python(config_repo)
146
143
  if config_repo.scheme != "git+file" or config_repo.path is None:
@@ -184,7 +181,7 @@ def add_user(
184
181
 
185
182
 
186
183
  def update_config_and_commit(repo_path: Path, config: Config, message: str):
187
- """Update the yaml file in the repo and commit it"""
184
+ """Update the yaml file in the repo and commit it."""
188
185
  repo = git.Repo(repo_path)
189
186
  yaml_path = repo_path / "default.yml"
190
187
  typer.echo(f"Writing back configuration to {yaml_path}", err=True)
@@ -53,7 +53,7 @@ class ConversionConfig(BaseModel):
53
53
 
54
54
  @app.command()
55
55
  def cs_sync(old_file: Path, new_file: Path):
56
- """Load the old CS and convert it to the new YAML format"""
56
+ """Load the old CS and convert it to the new YAML format."""
57
57
  if not os.environ.get("DIRAC_COMPAT_ENABLE_CS_CONVERSION"):
58
58
  raise RuntimeError(
59
59
  "DIRAC_COMPAT_ENABLE_CS_CONVERSION must be set for the conversion to be possible"
@@ -86,8 +86,7 @@ def cs_sync(old_file: Path, new_file: Path):
86
86
 
87
87
 
88
88
  def _apply_fixes(raw):
89
- """Modify raw in place to make any layout changes between the old and new structure"""
90
-
89
+ """Modify raw in place to make any layout changes between the old and new structure."""
91
90
  conv_config = ConversionConfig.model_validate(raw["DiracX"]["CsSync"])
92
91
 
93
92
  raw.pop("DiracX", None)
@@ -184,15 +183,15 @@ def generate_helm_values(
184
183
  ),
185
184
  output_file: Path = Option(help="Where to dump the yam file"),
186
185
  ):
187
- """Generate an initial values.yaml to run a DiracX installation
188
- compatible with a DIRAC instance. The file is not complete, and needs
189
- manual editing"""
186
+ """Generate an initial values.yaml to run a DiracX installation.
190
187
 
188
+ The file generated is not complete, and needs manual editing.
189
+ """
191
190
  helm_values = {
192
191
  "developer": {"enabled": False},
193
- "init-cs": {"enabled": True},
194
- "init-secrets": {"enabled": True},
195
- "init-sql": {"enabled": False, "env": {}},
192
+ "initCs": {"enabled": True},
193
+ "initSecrets": {"enabled": True},
194
+ "initSql": {"enabled": False, "env": {}},
196
195
  "cert-manager": {"enabled": False},
197
196
  "cert-manager-issuer": {"enabled": False},
198
197
  "minio": {"enabled": False},
@@ -20,6 +20,12 @@ from .utils import AsyncTyper
20
20
  app = AsyncTyper()
21
21
 
22
22
 
23
+ available_operators = (
24
+ f"Scalar operators: {', '.join([op.value for op in ScalarSearchOperator])}. "
25
+ f"Vector operators: {', '.join([op.value for op in VectorSearchOperator])}."
26
+ )
27
+
28
+
23
29
  def parse_condition(value: str) -> SearchSpec:
24
30
  parameter, operator, rest = value.split(" ", 2)
25
31
  if operator in set(ScalarSearchOperator):
@@ -51,15 +57,18 @@ async def search(
51
57
  "Owner",
52
58
  "LastUpdateTime",
53
59
  ],
54
- condition: Annotated[list[SearchSpec], Option(parser=parse_condition)] = [],
60
+ condition: Annotated[
61
+ list[str], Option(help=f'Example: "JobID eq 1000". {available_operators}')
62
+ ] = [],
55
63
  all: bool = False,
56
64
  page: int = 1,
57
65
  per_page: int = 10,
58
66
  ):
67
+ search_specs = [parse_condition(cond) for cond in condition]
59
68
  async with DiracClient() as api:
60
69
  jobs, content_range = await api.jobs.search(
61
70
  parameters=None if all else parameter,
62
- search=condition if condition else None,
71
+ search=search_specs if search_specs else None,
63
72
  page=page,
64
73
  per_page=per_page,
65
74
  cls=lambda _, jobs, headers: (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: diracx-cli
3
- Version: 0.0.1a17
3
+ Version: 0.0.1a19
4
4
  Summary: TODO
5
5
  License: GPL-3.0-only
6
6
  Classifier: Intended Audience :: Science/Research
@@ -8,7 +8,7 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Topic :: Scientific/Engineering
10
10
  Classifier: Topic :: System :: Distributed Computing
11
- Requires-Python: >=3.10
11
+ Requires-Python: >=3.11
12
12
  Description-Content-Type: text/markdown
13
13
  Requires-Dist: diraccfg
14
14
  Requires-Dist: diracx-api
@@ -0,0 +1,9 @@
1
+ [console_scripts]
2
+ dirac = diracx.cli:app
3
+
4
+ [diracx.cli]
5
+ config = diracx.cli.config:app
6
+ jobs = diracx.cli.jobs:app
7
+
8
+ [diracx.cli.hidden]
9
+ internal = diracx.cli.internal:app
@@ -1216,8 +1216,6 @@ Systems
1216
1216
  {
1217
1217
  Default = Operator
1218
1218
  getJobPilotOutput = authenticated
1219
- getSiteMask = authenticated
1220
- getSiteMaskStatus = authenticated
1221
1219
  ping = authenticated
1222
1220
  allowSite = SiteManager
1223
1221
  allowSite += Operator
@@ -858,8 +858,6 @@ Systems:
858
858
  allowSite: SiteManager, Operator
859
859
  banSite: SiteManager, Operator
860
860
  getJobPilotOutput: authenticated
861
- getSiteMask: authenticated
862
- getSiteMaskStatus: authenticated
863
861
  ping: authenticated
864
862
  Protocol: https
865
863
  URLs:
@@ -8,7 +8,6 @@ import pytest
8
8
  from pytest import raises
9
9
 
10
10
  from diracx import cli
11
- from diracx.core.models import ScalarSearchSpec
12
11
  from diracx.core.preferences import get_diracx_preferences
13
12
 
14
13
  TEST_JDL = """
@@ -41,7 +40,6 @@ async def jdl_file():
41
40
 
42
41
  async def test_submit(with_cli_login, jdl_file, capfd):
43
42
  """Test submitting a job using a JDL file."""
44
-
45
43
  with open(jdl_file, "r") as temp_file:
46
44
  await cli.jobs.submit([temp_file])
47
45
 
@@ -52,7 +50,6 @@ async def test_submit(with_cli_login, jdl_file, capfd):
52
50
 
53
51
  async def test_search(with_cli_login, jdl_file, capfd):
54
52
  """Test searching for jobs."""
55
-
56
53
  # Submit 20 jobs
57
54
  with open(jdl_file, "r") as temp_file:
58
55
  await cli.jobs.submit([temp_file] * 20)
@@ -82,8 +79,7 @@ async def test_search(with_cli_login, jdl_file, capfd):
82
79
  assert "JobGroup" in cap.out
83
80
 
84
81
  # Search for a job that doesn't exist
85
- condition = ScalarSearchSpec(parameter="Status", operator="eq", value="nonexistent")
86
- await cli.jobs.search(condition=[condition])
82
+ await cli.jobs.search(condition=["Status eq nonexistent"])
87
83
  cap = capfd.readouterr()
88
84
  assert cap.err == ""
89
85
  assert "[]" == cap.out.strip()
@@ -116,7 +112,7 @@ async def test_search(with_cli_login, jdl_file, capfd):
116
112
  assert "Showing all jobs" in cap.out
117
113
 
118
114
  # Search for a job that doesn't exist
119
- await cli.jobs.search(condition=[condition])
115
+ await cli.jobs.search(condition=["Status eq nonexistent"])
120
116
  cap = capfd.readouterr()
121
117
  assert cap.err == ""
122
118
  assert "No jobs found" in cap.out
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- dirac = diracx.cli:app
File without changes
File without changes