artefacts-cli 0.6.16__py3-none-any.whl → 0.6.17__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/cli/__init__.py CHANGED
@@ -15,7 +15,7 @@ logging.basicConfig(level=logging.INFO)
15
15
 
16
16
 
17
17
  try:
18
- __version__ = version("package-name")
18
+ __version__ = version("artefacts-cli")
19
19
  except PackageNotFoundError:
20
20
  try:
21
21
  # Package is not installed, most likely dev/test mode
artefacts/cli/app.py CHANGED
@@ -231,11 +231,64 @@ def hello(project_name):
231
231
  is_eager=True, # Necessary for callbacks to see it.
232
232
  help="Skip configuration validation, so that unsupported settings can be tried out, e.g. non-ROS settings or simulators like SAPIEN.",
233
233
  )
234
+ @click.option(
235
+ "--in-container",
236
+ is_flag=True,
237
+ default=False,
238
+ help='[Experimental] Run the job inside a package container. The container image is build if it does not exist yet, with default name as "artefacts" (please use --with-image to override the image name). This option overrides (for now) --dryrun, --nosim, --noisolation and --description.',
239
+ )
240
+ @click.option(
241
+ "--with-image",
242
+ default="artefacts",
243
+ help="[Experimental] Run the job using the image name passed here. Only used when running with --in-container set.",
244
+ )
245
+ @click.option(
246
+ "--rebuild-container",
247
+ is_flag=True,
248
+ default=False,
249
+ 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).",
250
+ )
251
+ @click.option(
252
+ "--with-gui",
253
+ is_flag=True,
254
+ default=False,
255
+ help="Show any GUI if any is created by the test runs. By default, UI elements are run but hidden---only test logs are returned. Please note GUI often assume X11 (e.g. ROS), typically with Qt, so this may not work without a appropriate environment.",
256
+ )
234
257
  @click.argument("jobname")
258
+ @click.pass_context
235
259
  def run(
236
- config, jobname, dryrun, nosim, noisolation, description="", skip_validation=False
260
+ ctx: click.Context,
261
+ config,
262
+ jobname,
263
+ dryrun,
264
+ nosim,
265
+ noisolation,
266
+ description="",
267
+ skip_validation=False,
268
+ in_container: bool = False,
269
+ with_image: str = "artefacts",
270
+ rebuild_container: bool = False,
271
+ with_gui: bool = False,
237
272
  ):
238
- """Run JOBNAME locally"""
273
+ """
274
+ Run JOBNAME locally
275
+
276
+ * Directly in the shell by default.
277
+ * Inside a packaged container when using the --in-container option.
278
+ """
279
+ if in_container:
280
+ if rebuild_container or not ctx.invoke(containers.check, name=with_image):
281
+ ctx.invoke(
282
+ containers.build, path=".", dockerfile="Dockerfile", name=with_image
283
+ )
284
+ return ctx.invoke(
285
+ containers.run,
286
+ image=with_image,
287
+ jobname=jobname,
288
+ config=config,
289
+ with_gui=with_gui,
290
+ )
291
+
239
292
  warpconfig = read_config(config)
240
293
 
241
294
  project_id = warpconfig["project"]
@@ -573,7 +626,7 @@ artefacts.add_command(config)
573
626
  artefacts.add_command(hello)
574
627
  artefacts.add_command(run)
575
628
  artefacts.add_command(run_remote)
576
- artefacts.add_command(containers.package)
629
+ artefacts.add_command(containers.containers)
577
630
 
578
631
 
579
632
  if __name__ == "__main__":
@@ -10,12 +10,12 @@ from artefacts.cli.containers.utils import ContainerMgr
10
10
  @click.group()
11
11
  @click.option("--debug/--no-debug", default=False)
12
12
  @click.pass_context
13
- def package(ctx: click.Context, debug: bool):
13
+ def containers(ctx: click.Context, debug: bool):
14
14
  ctx.ensure_object(dict)
15
15
  ctx.obj["debug"] = debug
16
16
 
17
17
 
18
- @package.command()
18
+ @containers.command()
19
19
  @click.option(
20
20
  "--path",
21
21
  default=".",
@@ -29,13 +29,13 @@ def package(ctx: click.Context, debug: bool):
29
29
  @click.option(
30
30
  "--name",
31
31
  required=False,
32
- help="Name for the generated package",
32
+ help="Name for the generated container",
33
33
  )
34
34
  @click.pass_context
35
35
  def build(ctx: click.Context, path: str, dockerfile: str, name: str):
36
36
  if not os.path.exists(os.path.join(path, dockerfile)):
37
37
  raise click.ClickException(
38
- f"No {dockerfile} found here. I cannot build the package."
38
+ f"No {dockerfile} found here. I cannot build the container."
39
39
  )
40
40
  if name is None:
41
41
  name = "artefacts"
@@ -44,7 +44,21 @@ def build(ctx: click.Context, path: str, dockerfile: str, name: str):
44
44
  print(f"Package complete in image: {image}")
45
45
 
46
46
 
47
- @package.command()
47
+ @containers.command()
48
+ @click.argument("name")
49
+ @click.pass_context
50
+ def check(ctx: click.Context, name: str):
51
+ if name is None:
52
+ name = "artefacts"
53
+ handler = ContainerMgr()
54
+ result = handler.check(name)
55
+ if ctx.parent is None:
56
+ # Print only if the command is called directly.
57
+ print(f"Package {name} exists and ready to use.")
58
+ return result
59
+
60
+
61
+ @containers.command()
48
62
  @click.argument("image")
49
63
  @click.argument("jobname")
50
64
  @click.option(
@@ -53,8 +67,14 @@ def build(ctx: click.Context, path: str, dockerfile: str, name: str):
53
67
  default="artefacts.yaml",
54
68
  help="Artefacts config file.",
55
69
  )
70
+ @click.option(
71
+ "--with-gui",
72
+ "with_gui",
73
+ default=False,
74
+ help="Show any GUI if any is created by the test runs. By default, UI elements are run but hidden---only test logs are returned. Please note GUI often assume an X11 environment, typically with Qt, so this may not work without a appropriate environment.",
75
+ )
56
76
  @click.pass_context
57
- def run(ctx: click.Context, image: str, jobname: str, config: str):
77
+ def run(ctx: click.Context, image: str, jobname: str, config: str, with_gui: bool):
58
78
  try:
59
79
  artefacts_config = read_config(config)
60
80
  except FileNotFoundError:
@@ -67,6 +87,7 @@ def run(ctx: click.Context, image: str, jobname: str, config: str):
67
87
  jobname=jobname,
68
88
  # Hidden setting primarily useful to Artefacts developers
69
89
  api_url=os.environ.get("ARTEFACTS_API_URL", DEFAULT_API_URL),
90
+ with_gui=with_gui,
70
91
  )
71
92
  container, logs = handler.run(**params)
72
93
  if container:
@@ -15,6 +15,12 @@ class CMgr:
15
15
  """
16
16
  raise NotImplemented()
17
17
 
18
+ def check(self, image: str) -> bool:
19
+ """
20
+ Checks whether a target image exists locally.
21
+ """
22
+ raise NotImplemented()
23
+
18
24
  def run(
19
25
  self,
20
26
  image: str,
@@ -22,6 +28,7 @@ class CMgr:
22
28
  jobname: str = None,
23
29
  artefacts_dir: str = Path("~/.artefacts").expanduser(),
24
30
  api_url: str = DEFAULT_API_URL,
31
+ with_gui: bool = False,
25
32
  ) -> Tuple[Any, Generator]:
26
33
  """
27
34
  Returns a container (Any type as depends on the framework)
@@ -45,7 +52,7 @@ class CMgr:
45
52
  """
46
53
  if not path:
47
54
  raise Exception(
48
- "`path` must be a string, a Path object, or exclusded from the kwargs"
55
+ "`path` must be a string, a Path object, or excluded from the kwargs"
49
56
  )
50
57
  if os.environ.get("ARTEFACTS_KEY", None):
51
58
  return True
@@ -2,6 +2,7 @@ from collections.abc import Generator
2
2
  import json
3
3
  import os
4
4
  from pathlib import Path
5
+ import platform
5
6
  from typing import Any, Tuple
6
7
  from uuid import uuid4
7
8
 
@@ -39,6 +40,12 @@ class DockerManager(CMgr):
39
40
  img_id = self.client.inspect_image(kwargs["tag"])["Id"]
40
41
  return img_id, iter(logs)
41
42
 
43
+ def check(
44
+ self,
45
+ image: str,
46
+ ) -> bool:
47
+ return len(self.client.images(name=image)) > 0
48
+
42
49
  def run(
43
50
  self,
44
51
  image: str,
@@ -46,6 +53,7 @@ class DockerManager(CMgr):
46
53
  jobname: str = None,
47
54
  artefacts_dir: str = Path("~/.artefacts").expanduser(),
48
55
  api_url: str = DEFAULT_API_URL,
56
+ with_gui: bool = False,
49
57
  ) -> Tuple[Any, Generator]:
50
58
  if not self._valid_artefacts_api_key(project, artefacts_dir):
51
59
  return None, iter(
@@ -60,6 +68,15 @@ class DockerManager(CMgr):
60
68
  "ARTEFACTS_API_URL": api_url,
61
69
  }
62
70
 
71
+ if platform.system() in ["Darwin", "Windows"]:
72
+ # Assume we run in Docker Desktop
73
+ env["DISPLAY"] = "host.docker.internal:0"
74
+ else:
75
+ env["DISPLAY"] = os.environ.get("DISPLAY", ":0")
76
+
77
+ if not with_gui:
78
+ env["QT_QPA_PLATFORM"] = "offscreen"
79
+
63
80
  container = self.client.create_container(
64
81
  image,
65
82
  environment=env,
@@ -72,6 +89,7 @@ class DockerManager(CMgr):
72
89
  "mode": "ro",
73
90
  },
74
91
  },
92
+ network_mode="host",
75
93
  ),
76
94
  )
77
95
  self.client.start(container=container.get("Id"))
@@ -50,5 +50,8 @@ class ContainerMgr:
50
50
  def build(self, **kwargs) -> Tuple[str, Generator]:
51
51
  return self.mgr.build(**kwargs)
52
52
 
53
+ def check(self, image: str) -> bool:
54
+ return self.mgr.check(image)
55
+
53
56
  def run(self, **kwargs) -> Tuple[Any, Generator]:
54
57
  return self.mgr.run(**kwargs)
artefacts/cli/version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.6.16'
16
- __version_tuple__ = version_tuple = (0, 6, 16)
15
+ __version__ = version = '0.6.17'
16
+ __version_tuple__ = version_tuple = (0, 6, 17)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: artefacts_cli
3
- Version: 0.6.16
3
+ Version: 0.6.17
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
@@ -18,6 +18,7 @@ Requires-Dist: mcap-ros2-support
18
18
  Requires-Dist: PyYAML>=6.0
19
19
  Requires-Dist: requests>=2.27.1
20
20
  Requires-Dist: setuptools-scm
21
+ Requires-Dist: setuptools>=74
21
22
  Provides-Extra: dev
22
23
  Requires-Dist: awscli; extra == "dev"
23
24
  Requires-Dist: build; extra == "dev"
@@ -0,0 +1,21 @@
1
+ artefacts/cli/__init__.py,sha256=--1soc8cqq1JWhz4DuRUvJWgSeDCPGqm8mEmdqtclsI,11644
2
+ artefacts/cli/app.py,sha256=cxVVHD89_eVCHm5fqPq3ANuy6jTPfw3se-FST_7wILY,22093
3
+ artefacts/cli/app_containers.py,sha256=tHdGkxtzjexLhgcx5YXy_OOJsPcBi1jmwKZN01OAcmU,3044
4
+ artefacts/cli/bagparser.py,sha256=FE_QaztC9pg4hQzTjGSdyve6mzZbHJbyqa3wqvZSbxE,3702
5
+ artefacts/cli/constants.py,sha256=bvsVDwqkAc49IZN7j6k6IL6EG87bECHd_VINtKJqbv8,320
6
+ artefacts/cli/other.py,sha256=7NvzlspvG0zF7sryR-QznwdLupXLln1BKWxHB9VuEcc,1160
7
+ artefacts/cli/parameters.py,sha256=MDhrM7ur95wKTLDteqz2f-sLdCPcepi5wk0XjeLo6TU,788
8
+ artefacts/cli/ros1.py,sha256=RbtirCGarD9a0ikfuGK-pdpWYSXfqJhEt4rpA0uFsyU,9625
9
+ artefacts/cli/ros2.py,sha256=YaCi3HRuCdvCTjM0Ftnm-SLgMOy1OneIr0aU7KVTiAM,4476
10
+ artefacts/cli/utils.py,sha256=6yQJRzv-xaLbtcA73Tty9C9QZeV06n5pjXMYl3xsLPE,3156
11
+ artefacts/cli/utils_ros.py,sha256=pYbhAU9fK2VbnWm3nSLBwUMVBzsZuCn10SFZmVW3-Zo,2090
12
+ artefacts/cli/version.py,sha256=q7Xb4Wt4eH2VCIhiAa6149XDeUKQFfphqlwqiTFiurk,413
13
+ artefacts/cli/containers/__init__.py,sha256=y6NVB0efBfRQBlHb71xhRu1hEh7t2bkKNs2vtsLJaO8,2239
14
+ artefacts/cli/containers/docker.py,sha256=A9jqs0WU-g8umJzPpEACi0_DU5N8rglR-V3dmwxDuBA,3507
15
+ artefacts/cli/containers/utils.py,sha256=6Bw6s1ceEnTbWSdE5_1CReNW6RB29VeHsq-BAwcJ_fY,1895
16
+ artefacts/wrappers/artefacts_ros1_meta.launch,sha256=9tN7_0xLH8jW27KYFerhF3NuWDx2dED3ks_qoGVZAPw,1412
17
+ artefacts_cli-0.6.17.dist-info/METADATA,sha256=aiDZPGqyOGAS_pS3XnjIk4IAStv_vS3fUOW3qPyEH-s,3051
18
+ artefacts_cli-0.6.17.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
19
+ artefacts_cli-0.6.17.dist-info/entry_points.txt,sha256=nlTXRzilNjccbi53FgaRWCQPkG-pv61HRkaCkrKjlec,58
20
+ artefacts_cli-0.6.17.dist-info/top_level.txt,sha256=FdaMV1C9m36MWa-2Stm5xVODv7hss_nRYNwR83j_7ow,10
21
+ artefacts_cli-0.6.17.dist-info/RECORD,,
@@ -1,21 +0,0 @@
1
- artefacts/cli/__init__.py,sha256=9rTAfBoS9ALJxKSqaUo32ThbDshbvNN4-EmoyUsPhRI,11643
2
- artefacts/cli/app.py,sha256=597uPtK4A_wujvqhk5h4KkrXV_XVkDLpymedd2lZB5k,20140
3
- artefacts/cli/app_containers.py,sha256=7OAtc4n9YeK8ZYUKvteOMbZr7lYjx_YMa6tu8Pnu9Yc,2280
4
- artefacts/cli/bagparser.py,sha256=FE_QaztC9pg4hQzTjGSdyve6mzZbHJbyqa3wqvZSbxE,3702
5
- artefacts/cli/constants.py,sha256=bvsVDwqkAc49IZN7j6k6IL6EG87bECHd_VINtKJqbv8,320
6
- artefacts/cli/other.py,sha256=7NvzlspvG0zF7sryR-QznwdLupXLln1BKWxHB9VuEcc,1160
7
- artefacts/cli/parameters.py,sha256=MDhrM7ur95wKTLDteqz2f-sLdCPcepi5wk0XjeLo6TU,788
8
- artefacts/cli/ros1.py,sha256=RbtirCGarD9a0ikfuGK-pdpWYSXfqJhEt4rpA0uFsyU,9625
9
- artefacts/cli/ros2.py,sha256=YaCi3HRuCdvCTjM0Ftnm-SLgMOy1OneIr0aU7KVTiAM,4476
10
- artefacts/cli/utils.py,sha256=6yQJRzv-xaLbtcA73Tty9C9QZeV06n5pjXMYl3xsLPE,3156
11
- artefacts/cli/utils_ros.py,sha256=pYbhAU9fK2VbnWm3nSLBwUMVBzsZuCn10SFZmVW3-Zo,2090
12
- artefacts/cli/version.py,sha256=zbqzBVUYJbK8o4vMJuNyIN5tBM9QXVZa7XiEM2PNdR8,413
13
- artefacts/cli/containers/__init__.py,sha256=S3DXLsb0csUdfjOZIngTfhMHrmYAaWBeu5EctLEEXbM,2057
14
- artefacts/cli/containers/docker.py,sha256=RtUOMbtWHQumTtDRa0ALjJ29tSaa7Pp497Ah1aJ7nZ4,2964
15
- artefacts/cli/containers/utils.py,sha256=5yUoREHM9AxnTkDNCY-DFUPSR5OWtu1rNxIVs6n5zZo,1816
16
- artefacts/wrappers/artefacts_ros1_meta.launch,sha256=9tN7_0xLH8jW27KYFerhF3NuWDx2dED3ks_qoGVZAPw,1412
17
- artefacts_cli-0.6.16.dist-info/METADATA,sha256=OLy7Jmo_RMo9CiktBZSKiZRN1HVILJkuhz-W24YB0RA,3021
18
- artefacts_cli-0.6.16.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
19
- artefacts_cli-0.6.16.dist-info/entry_points.txt,sha256=nlTXRzilNjccbi53FgaRWCQPkG-pv61HRkaCkrKjlec,58
20
- artefacts_cli-0.6.16.dist-info/top_level.txt,sha256=FdaMV1C9m36MWa-2Stm5xVODv7hss_nRYNwR83j_7ow,10
21
- artefacts_cli-0.6.16.dist-info/RECORD,,