@@ -526,20 +526,38 @@ def get_launch_cmd(
526526 self ,
527527 container_runtime : OciRuntimeBase ,
528528 extra_run_args : Optional [List [str ]] = None ,
529+ in_background : bool = True ,
530+ interactive_tty : bool = True ,
531+ remove : bool = False ,
529532 ) -> List [str ]:
530533 """Returns the command to launch this container image.
531534
532535 Args:
536+ container_runtime: The container runtime to be used to launch this
537+ container
538+
533539 extra_run_args: optional list of arguments that are added to the
534540 launch command directly after the ``run -d``.
535541
542+ in_background: flag whether to launch the container with ``-d``
543+ (i.e. in the background). Defaults to ``True``.
544+
545+ interactive: flag whether to launch the container with ``--it``
546+ (i.e. in interactive mode and attach a pseudo TTY). Defaults to
547+ ``True``.
548+
549+ remove: flag whether to launch the container with the ``--rm`` flag
550+ (i.e. it will be auto-removed on after stopping)
551+
536552 Returns:
537553 The command to launch the container image described by this class
538554 instance as a list of strings that can be fed directly to
539555 :py:class:`subprocess.Popen` as the ``args`` parameter.
540556 """
541557 cmd = (
542- [container_runtime .runner_binary , "run" , "-d" ]
558+ [container_runtime .runner_binary , "run" ]
559+ + (["-d" ] if in_background else [])
560+ + (["--rm" ] if remove else [])
543561 + (extra_run_args or [])
544562 + self .extra_launch_args
545563 + (
@@ -558,7 +576,9 @@ def get_launch_cmd(
558576 )
559577
560578 id_or_url = self .container_id or self .url
561- container_launch = ("-it" , id_or_url )
579+ container_launch : Tuple [str , ...] = (
580+ ("-it" , id_or_url ) if interactive_tty else (id_or_url ,)
581+ )
562582 bash_launch_end = (
563583 * _CONTAINER_STOPSIGNAL ,
564584 * container_launch ,
@@ -994,7 +1014,29 @@ def prepare_container(
9941014
9951015
9961016@dataclass (frozen = True )
997- class ContainerData :
1017+ class ContainerImageData :
1018+ #: the container data class that has been used in this test
1019+ container : Union [Container , DerivedContainer , MultiStageContainer ]
1020+
1021+ _container_runtime : OciRuntimeBase
1022+
1023+ @property
1024+ def run_command_list (self ) -> List [str ]:
1025+ return self .container .get_launch_cmd (
1026+ self ._container_runtime ,
1027+ in_background = False ,
1028+ remove = True ,
1029+ # -it breaks testinfra.host.check_output() with docker
1030+ interactive_tty = self ._container_runtime .runner_binary == "podman" ,
1031+ )
1032+
1033+ @property
1034+ def run_command (self ) -> str :
1035+ return " " .join (self .run_command_list )
1036+
1037+
1038+ @dataclass (frozen = True )
1039+ class ContainerData (ContainerImageData ):
9981040 """Class returned by the ``*container*`` fixtures to the test function. It
9991041 contains information about the launched container and the testinfra
10001042 :py:attr:`connection` to the running container.
@@ -1008,13 +1050,9 @@ class ContainerData:
10081050 container_id : str
10091051 #: the testinfra connection to the running container
10101052 connection : Any
1011- #: the container data class that has been used in this test
1012- container : Union [Container , DerivedContainer , MultiStageContainer ]
10131053 #: any ports that are exposed by this container
10141054 forwarded_ports : List [PortForwarding ]
10151055
1016- _container_runtime : OciRuntimeBase
1017-
10181056 @property
10191057 def inspect (self ) -> ContainerInspect :
10201058 """Inspect the launched container and return the result of
@@ -1205,11 +1243,7 @@ def from_pytestconfig(
12051243 def __enter__ (self ) -> "ContainerLauncher" :
12061244 return self
12071245
1208- def launch_container (self ) -> None :
1209- """This function performs the actual heavy lifting of launching the
1210- container, creating all the volumes, port bindings, etc.pp.
1211-
1212- """
1246+ def prepare_container (self ) -> None :
12131247 # Lock guarding the container preparation, so that only one process
12141248 # tries to pull/build it at the same time.
12151249 # If this container is a singleton, then we use it as a lock until
@@ -1251,6 +1285,13 @@ def release_lock() -> None:
12511285 get_volume_creator (cont_vol , self .container_runtime )
12521286 )
12531287
1288+ def launch_container (self ) -> None :
1289+ """This function performs the actual heavy lifting of launching the
1290+ container, creating all the volumes, port bindings, etc.pp.
1291+
1292+ """
1293+ self .prepare_container ()
1294+
12541295 forwarded_ports = self .container .forwarded_ports
12551296
12561297 extra_run_args = self .extra_run_args
@@ -1290,6 +1331,13 @@ def release_lock() -> None:
12901331
12911332 self ._wait_for_container_to_become_healthy ()
12921333
1334+ @property
1335+ def container_image_data (self ) -> ContainerImageData :
1336+ # FIXME: check if container is prepared
1337+ return ContainerImageData (
1338+ container = self .container , _container_runtime = self .container_runtime
1339+ )
1340+
12931341 @property
12941342 def container_data (self ) -> ContainerData :
12951343 """The :py:class:`ContainerData` instance corresponding to the running
0 commit comments