artefacts-cli 0.6.18__py3-none-any.whl → 0.7.0__py3-none-any.whl

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.
artefacts/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ from pathlib import Path
2
+
3
+
4
+ ARTEFACTS_DEFAULT_OUTPUT_DIR = Path("artefacts")
artefacts/cli/app.py CHANGED
@@ -20,7 +20,7 @@ from gitignore_parser import parse_gitignore
20
20
  from artefacts.cli import init_job, generate_scenarios, AuthenticationError, __version__
21
21
  from artefacts.cli import app_containers as containers
22
22
  from artefacts.cli.constants import DEPRECATED_FRAMEWORKS, SUPPORTED_FRAMEWORKS
23
- from artefacts.cli.utils import read_config, config_validation
23
+ from artefacts.cli.utils import add_output_from_default, config_validation, read_config
24
24
 
25
25
  HOME = os.path.expanduser("~")
26
26
  CONFIG_DIR = f"{HOME}/.artefacts"
@@ -247,10 +247,10 @@ def hello(project_name):
247
247
  help="[Experimental] Run the job using the image name passed here. Only used when running with --in-container set.",
248
248
  )
249
249
  @click.option(
250
- "--rebuild-container",
250
+ "--no-rebuild",
251
251
  is_flag=True,
252
252
  default=False,
253
- help="[Experimental] Rebuild the container image before running. This flag guarantees that the run uses the latest code available when building the image, and usually takes more time before the run can start (time to compile and generate the image).",
253
+ help="[Experimental] Override the default behaviour to always rebuild the container image (as we assume incremental testing).",
254
254
  )
255
255
  @click.option(
256
256
  "--with-gui",
@@ -272,7 +272,7 @@ def run(
272
272
  skip_validation=False,
273
273
  in_container: bool = False,
274
274
  with_image: str = "artefacts",
275
- rebuild_container: bool = False,
275
+ no_rebuild: bool = False,
276
276
  with_gui: bool = False,
277
277
  ):
278
278
  """
@@ -282,10 +282,18 @@ def run(
282
282
  * Inside a packaged container when using the --in-container option.
283
283
  """
284
284
  if in_container:
285
- if rebuild_container or not ctx.invoke(containers.check, name=with_image):
285
+ image_exist = ctx.invoke(containers.check, name=with_image)
286
+ if not no_rebuild or not image_exist:
287
+ if image_exist:
288
+ announce = "Rebuilding container image to prepare the run..."
289
+ else:
290
+ announce = "Building container image to prepare the run..."
291
+ click.echo(announce)
286
292
  ctx.invoke(
287
293
  containers.build, path=".", dockerfile="Dockerfile", name=with_image
288
294
  )
295
+ click.echo("Build complete.\n")
296
+ click.echo("Starting the container run...")
289
297
  return ctx.invoke(
290
298
  containers.run,
291
299
  image=with_image,
@@ -419,6 +427,9 @@ def run(
419
427
  if type(run.params.get("metrics", [])) is str:
420
428
  run.log_metrics()
421
429
 
430
+ # Add for upload any default output generated by the run
431
+ add_output_from_default(run)
432
+
422
433
  run.stop()
423
434
  warpjob.log_tests_result(job_success)
424
435
  click.echo("Done")
@@ -85,9 +85,10 @@ def run(ctx: click.Context, image: str, jobname: str, config: str, with_gui: boo
85
85
  image=image,
86
86
  project=project,
87
87
  jobname=jobname,
88
- # Hidden setting primarily useful to Artefacts developers
89
- api_url=os.environ.get("ARTEFACTS_API_URL", DEFAULT_API_URL),
90
88
  with_gui=with_gui,
89
+ # Hidden settings primarily useful to Artefacts developers
90
+ api_url=os.environ.get("ARTEFACTS_API_URL", DEFAULT_API_URL),
91
+ api_key=os.environ.get("ARTEFACTS_KEY", None),
91
92
  )
92
93
  container, logs = handler.run(**params)
93
94
  if container:
@@ -2,7 +2,7 @@ from collections.abc import Generator
2
2
  import configparser
3
3
  import os
4
4
  from pathlib import Path
5
- from typing import Any, Tuple, Union
5
+ from typing import Any, Optional, Tuple, Union
6
6
 
7
7
  from artefacts.cli.constants import DEFAULT_API_URL
8
8
 
@@ -36,17 +36,17 @@ class CMgr:
36
36
  """
37
37
  raise NotImplementedError()
38
38
 
39
- def _valid_artefacts_api_key(
39
+ def _get_artefacts_api_key(
40
40
  self, project: str, path: Union[str, Path] = Path("~/.artefacts").expanduser()
41
- ) -> bool:
41
+ ) -> Optional[str]:
42
42
  """
43
- Check if a valid API key is available to embed in containers.
43
+ Get any valid API key to embed in containers.
44
44
 
45
- 1. Check overrides with the ARTEFACTS_KEY environment variable.
46
- 2. If `path` is not given, check the default .artefacts folder for the config file.
47
- 3. If `path` is given, check the file directly is a file, or check for a `config` file if a folder.
45
+ 1. Checks first from the ARTEFACTS_KEY environment variable.
46
+ 2. If `path` is not given, check from the default configuraiton file in the .artefacts folder.
47
+ 3. If `path` is given, check the file directly if a file, or check for a `config` file if a folder.
48
48
 
49
- When a config file is found, we check here if the API key for the `project` is available.
49
+ When a config file is found, we get the API key for the `project`.
50
50
 
51
51
  `path` set to None is an error, and aborts execution.
52
52
  """
@@ -55,7 +55,7 @@ class CMgr:
55
55
  "`path` must be a string, a Path object, or excluded from the kwargs"
56
56
  )
57
57
  if os.environ.get("ARTEFACTS_KEY", None):
58
- return True
58
+ return os.environ["ARTEFACTS_KEY"]
59
59
  path = Path(path) # Ensure we have a Path object
60
60
  config = configparser.ConfigParser()
61
61
  if path.is_dir():
@@ -63,6 +63,6 @@ class CMgr:
63
63
  else:
64
64
  config.read(path)
65
65
  try:
66
- return config[project].get("apikey") is not None
66
+ return config[project].get("apikey")
67
67
  except KeyError:
68
- return False
68
+ return None
@@ -53,21 +53,35 @@ class DockerManager(CMgr):
53
53
  jobname: str = None,
54
54
  artefacts_dir: str = Path("~/.artefacts").expanduser(),
55
55
  api_url: str = DEFAULT_API_URL,
56
+ api_key: str = None,
56
57
  with_gui: bool = False,
57
58
  ) -> Tuple[Any, Generator]:
58
- if not self._valid_artefacts_api_key(project, artefacts_dir):
59
+ """
60
+ Run an application as an Artefacts-enabled container in a Docker engine
61
+
62
+ The arguments are considered straightforward, except the different
63
+ priorities between `artefacts_dir` and `api_key`:
64
+ * `api_key` has the highest priority. When specified, `artefacts_dir`
65
+ is ignored. The container will rely on the key as an environment
66
+ variable (ARTEFACTS_KEY).
67
+ * Whenever `api_key` is not provided, the container gets `artefacts_dir`
68
+ mounted as volume. The directory must contain a valid configuration
69
+ with the project's key.
70
+ """
71
+ env = {
72
+ "JOB_ID": str(uuid4()),
73
+ "ARTEFACTS_JOB_NAME": jobname,
74
+ "ARTEFACTS_API_URL": api_url,
75
+ }
76
+
77
+ env["ARTEFACTS_KEY"] = self._get_artefacts_api_key(project, artefacts_dir)
78
+ if env["ARTEFACTS_KEY"] is None:
59
79
  return None, iter(
60
80
  [
61
- "Missing API key for the project. Does `~/.artefacts/config` exist and contain your key?"
81
+ f"Missing API key for the project. Does `{artefacts_dir}/config` exist and contain your key? Alternatively ARTEFACTS_KEY can be set with the key."
62
82
  ]
63
83
  )
64
84
  try:
65
- env = {
66
- "JOB_ID": str(uuid4()),
67
- "ARTEFACTS_JOB_NAME": jobname,
68
- "ARTEFACTS_API_URL": api_url,
69
- }
70
-
71
85
  if platform.system() in ["Darwin", "Windows"]:
72
86
  # Assume we run in Docker Desktop
73
87
  env["DISPLAY"] = "host.docker.internal:0"
@@ -77,24 +91,21 @@ class DockerManager(CMgr):
77
91
  if not with_gui:
78
92
  env["QT_QPA_PLATFORM"] = "offscreen"
79
93
 
80
- container = self.client.create_container(
81
- image,
94
+ container_conf = dict(
95
+ image=image,
82
96
  environment=env,
83
97
  detach=False,
84
- volumes=["/root/.artefacts"],
85
98
  host_config=self.client.create_host_config(
86
- binds={
87
- artefacts_dir: {
88
- "bind": "/root/.artefacts",
89
- "mode": "ro",
90
- },
91
- },
92
99
  network_mode="host",
93
100
  ),
94
101
  )
102
+
103
+ container = self.client.create_container(**container_conf)
95
104
  self.client.start(container=container.get("Id"))
105
+
96
106
  for entry in self.client.logs(container=container.get("Id"), stream=True):
97
107
  print(entry.decode("utf-8").strip())
108
+
98
109
  return container, iter([])
99
110
  except docker.errors.ImageNotFound:
100
111
  return None, iter(
artefacts/cli/utils.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import os
2
+ from pathlib import Path
2
3
  import subprocess
3
4
  import sys
4
5
  from typing import Union
@@ -6,6 +7,8 @@ from typing import Union
6
7
  import click
7
8
 
8
9
  import artefacts_copava as copava
10
+ from artefacts import ARTEFACTS_DEFAULT_OUTPUT_DIR
11
+ from artefacts.cli import WarpRun
9
12
 
10
13
 
11
14
  def run_and_save_logs(
@@ -97,3 +100,17 @@ def pretty_print_config_error(
97
100
  # Must not happen, so broad definition, but we want to know fast.
98
101
  raise Exception(f"Unacceptable data type for config error formatting: {errors}")
99
102
  return output
103
+
104
+
105
+ def add_output_from_default(run: WarpRun) -> None:
106
+ """
107
+ Add every file found under ARTEFACTS_DEFAULT_OUTPUT_DIR to the set of files
108
+ uploaded to Artefacts for the run argument.
109
+
110
+ The default folder is created either directly, or more generally by Artefacts
111
+ toolkit libraries.
112
+ """
113
+ if ARTEFACTS_DEFAULT_OUTPUT_DIR.exists() and ARTEFACTS_DEFAULT_OUTPUT_DIR.is_dir():
114
+ for root, dirs, files in os.walk(ARTEFACTS_DEFAULT_OUTPUT_DIR):
115
+ for file in files:
116
+ run.log_artifacts(Path(root) / Path(file))
artefacts/cli/version.py CHANGED
@@ -1,8 +1,13 @@
1
- # file generated by setuptools_scm
1
+ # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
3
6
  TYPE_CHECKING = False
4
7
  if TYPE_CHECKING:
5
- from typing import Tuple, Union
8
+ from typing import Tuple
9
+ from typing import Union
10
+
6
11
  VERSION_TUPLE = Tuple[Union[int, str], ...]
7
12
  else:
8
13
  VERSION_TUPLE = object
@@ -12,5 +17,5 @@ __version__: str
12
17
  __version_tuple__: VERSION_TUPLE
13
18
  version_tuple: VERSION_TUPLE
14
19
 
15
- __version__ = version = '0.6.18'
16
- __version_tuple__ = version_tuple = (0, 6, 18)
20
+ __version__ = version = '0.7.0'
21
+ __version_tuple__ = version_tuple = (0, 7, 0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: artefacts_cli
3
- Version: 0.6.18
3
+ Version: 0.7.0
4
4
  Author-email: FD <fabian@artefacts.com>, AGC <alejandro@artefacts.com>, TN <tomo@artefacts.com>, EP <eric@artefacts.com>
5
5
  Project-URL: Homepage, https://github.com/art-e-fact/artefacts-client
6
6
  Project-URL: Bug Tracker, https://github.com/art-e-fact/artefacts-client/issues
@@ -0,0 +1,24 @@
1
+ artefacts/__init__.py,sha256=VLmogtpRQeJjQjAORV8ClSJ5qF-57Hxx3apvgy9H1zk,76
2
+ artefacts/cli/__init__.py,sha256=pt8OK66hMeQUxT9iLcvzYIIjFGrPS63ecWo8hS0T2qQ,11980
3
+ artefacts/cli/app.py,sha256=tEknMMi7WhAPnq8NlGgLuLqqoCDWssZqs1lB3eNlVg4,22571
4
+ artefacts/cli/app_containers.py,sha256=dsyzN8UzGNwxkhV8BsFK7Sz9EOL6Se3YpeiUgzC2qic,3099
5
+ artefacts/cli/bagparser.py,sha256=FE_QaztC9pg4hQzTjGSdyve6mzZbHJbyqa3wqvZSbxE,3702
6
+ artefacts/cli/constants.py,sha256=bvsVDwqkAc49IZN7j6k6IL6EG87bECHd_VINtKJqbv8,320
7
+ artefacts/cli/errors.py,sha256=BiCRo3IwVjtEotaFtmwsGTZiX-TRE69KqLrEQItLsag,34
8
+ artefacts/cli/logger.py,sha256=MP8WDImHA3BKVsn55BMWtGP5-aCmXl5ViVPtIo3jKk4,242
9
+ artefacts/cli/other.py,sha256=7NvzlspvG0zF7sryR-QznwdLupXLln1BKWxHB9VuEcc,1160
10
+ artefacts/cli/parameters.py,sha256=msf2aG-tmw0ahxwrPpB2W6KqdMj5A-nw9DPG9flkHTg,788
11
+ artefacts/cli/ros1.py,sha256=rKepZckAuy5O_qraF2CW5GiTmTZHar7LRD4pvESy6T0,9622
12
+ artefacts/cli/ros2.py,sha256=9Ax_WQIOV_cohKz3H1eo1LnWiahiaqxO8r99doMmhEc,4466
13
+ artefacts/cli/utils.py,sha256=GJM2QdF_ewzPWr8NzO5BbrhyZdSSk9DNX12Nbwc4bnI,3814
14
+ artefacts/cli/utils_ros.py,sha256=3EFoMrzBdlhLc-wAL3mmS5sSw_pACkurYhssKHqYJsI,2089
15
+ artefacts/cli/version.py,sha256=itvIHlqPKoO_13qf_yPD2pmcp0U4z1s19vvBGZM927Q,511
16
+ artefacts/cli/containers/__init__.py,sha256=K0efkJXNCqXH-qYBqhCE_8zVUCHbVmeuKH-y_fE8s4M,2254
17
+ artefacts/cli/containers/docker.py,sha256=fsGTzpj7Sj7ykCBxzaYlIt_so1yfWJ2j6ktxsWjvdvY,4073
18
+ artefacts/cli/containers/utils.py,sha256=bILX0uvazUJq7hoqKk4ztRzI_ZerYs04XQdKdx1ltjk,2002
19
+ artefacts/wrappers/artefacts_ros1_meta.launch,sha256=9tN7_0xLH8jW27KYFerhF3NuWDx2dED3ks_qoGVZAPw,1412
20
+ artefacts_cli-0.7.0.dist-info/METADATA,sha256=bYCIMBdVBOLHHW38dmsUqXj-hoFczntRhszgykDm_eM,3034
21
+ artefacts_cli-0.7.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
22
+ artefacts_cli-0.7.0.dist-info/entry_points.txt,sha256=nlTXRzilNjccbi53FgaRWCQPkG-pv61HRkaCkrKjlec,58
23
+ artefacts_cli-0.7.0.dist-info/top_level.txt,sha256=FdaMV1C9m36MWa-2Stm5xVODv7hss_nRYNwR83j_7ow,10
24
+ artefacts_cli-0.7.0.dist-info/RECORD,,
@@ -1,23 +0,0 @@
1
- artefacts/cli/__init__.py,sha256=pt8OK66hMeQUxT9iLcvzYIIjFGrPS63ecWo8hS0T2qQ,11980
2
- artefacts/cli/app.py,sha256=fHqq4N_JdSO8jgN4uc0puLSSJk_NU5srbztveipbqLw,22221
3
- artefacts/cli/app_containers.py,sha256=dLQqcrRF-3NSpcmijGK6Q51CinumAXnJ1KLNSEKUIPQ,3043
4
- artefacts/cli/bagparser.py,sha256=FE_QaztC9pg4hQzTjGSdyve6mzZbHJbyqa3wqvZSbxE,3702
5
- artefacts/cli/constants.py,sha256=bvsVDwqkAc49IZN7j6k6IL6EG87bECHd_VINtKJqbv8,320
6
- artefacts/cli/errors.py,sha256=BiCRo3IwVjtEotaFtmwsGTZiX-TRE69KqLrEQItLsag,34
7
- artefacts/cli/logger.py,sha256=MP8WDImHA3BKVsn55BMWtGP5-aCmXl5ViVPtIo3jKk4,242
8
- artefacts/cli/other.py,sha256=7NvzlspvG0zF7sryR-QznwdLupXLln1BKWxHB9VuEcc,1160
9
- artefacts/cli/parameters.py,sha256=msf2aG-tmw0ahxwrPpB2W6KqdMj5A-nw9DPG9flkHTg,788
10
- artefacts/cli/ros1.py,sha256=rKepZckAuy5O_qraF2CW5GiTmTZHar7LRD4pvESy6T0,9622
11
- artefacts/cli/ros2.py,sha256=9Ax_WQIOV_cohKz3H1eo1LnWiahiaqxO8r99doMmhEc,4466
12
- artefacts/cli/utils.py,sha256=bqADil7Aqvg-ci0244e-yf8G9KvIkYeWGNc_jMn6qv0,3151
13
- artefacts/cli/utils_ros.py,sha256=3EFoMrzBdlhLc-wAL3mmS5sSw_pACkurYhssKHqYJsI,2089
14
- artefacts/cli/version.py,sha256=hdhRgZhTA3pieFZY1w6wT4BsoNOPCUB21i3j8v6cYbA,413
15
- artefacts/cli/containers/__init__.py,sha256=ga52A5dJUl3EzmrRAQ-ucsLVExPhL61cfcT4rnTgtzc,2258
16
- artefacts/cli/containers/docker.py,sha256=ndidmuMUc8LvgGGF7MwUTCaSUzp9dSS56DE847krmJ8,3535
17
- artefacts/cli/containers/utils.py,sha256=bILX0uvazUJq7hoqKk4ztRzI_ZerYs04XQdKdx1ltjk,2002
18
- artefacts/wrappers/artefacts_ros1_meta.launch,sha256=9tN7_0xLH8jW27KYFerhF3NuWDx2dED3ks_qoGVZAPw,1412
19
- artefacts_cli-0.6.18.dist-info/METADATA,sha256=r0BO8lNkG3yljvWpgU3R11x3WfpR3fGVdNIcK_Xu2-s,3035
20
- artefacts_cli-0.6.18.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
21
- artefacts_cli-0.6.18.dist-info/entry_points.txt,sha256=nlTXRzilNjccbi53FgaRWCQPkG-pv61HRkaCkrKjlec,58
22
- artefacts_cli-0.6.18.dist-info/top_level.txt,sha256=FdaMV1C9m36MWa-2Stm5xVODv7hss_nRYNwR83j_7ow,10
23
- artefacts_cli-0.6.18.dist-info/RECORD,,