def test_toml_serializer() -> None: original_values: Dict = { "GLOBAL": { "truthy": True, "falsy": False, "int": 0, "float": 0.0, "word": "hello there", "listy": ["a", "b", "c"], "map": { "a": 0, "b": 1 }, }, "some-subsystem": { "o": "" }, } assert TomlSerializer(original_values).normalize() == { "GLOBAL": { **original_values["GLOBAL"], "map": "{'a': 0, 'b': 1}" }, "some-subsystem": { "o": "" }, }
def test_toml_serializer_list_add_remove() -> None: original_values = {"GLOBAL": {"backend_packages.add": ["added"]}} assert TomlSerializer( original_values).normalize() == { # type: ignore[arg-type] "GLOBAL": { "backend_packages": "+['added']" } }
def test_toml_serializer_add_remove() -> None: original_values: Dict = { "GLOBAL": { "backend_packages.add": ["added"], }, } assert TomlSerializer(original_values).normalize() == { "GLOBAL": { "backend_packages": "+['added']", }, }
def test_toml_serializer() -> None: original_values: Dict = { "GLOBAL": { "truthy": True, "falsy": False, "int": 0, "float": 0.0, "word": "hello there", "listy": ["a", "b", "c"], "map": {"a": 0, "b": 1}, }, "cache.java": {"o": ""}, "inception.nested.nested-again.one-more": {"o": ""}, } assert TomlSerializer(original_values).normalize() == { "GLOBAL": {**original_values["GLOBAL"], "map": "{'a': 0, 'b': 1}"}, "cache": {"java": {"o": ""}}, "inception": {"nested": {"nested-again": {"one-more": {"o": ""}}}}, }
def run_pants_with_workdir_without_waiting( command: Command, *, workdir: str, hermetic: bool = True, use_pantsd: bool = True, config: Mapping | None = None, extra_env: Mapping[str, str] | None = None, print_stacktrace: bool = True, **kwargs: Any, ) -> PantsJoinHandle: args = [ "--no-pantsrc", f"--pants-workdir={workdir}", f"--print-stacktrace={print_stacktrace}", ] pantsd_in_command = "--no-pantsd" in command or "--pantsd" in command pantsd_in_config = config and "GLOBAL" in config and "pantsd" in config[ "GLOBAL"] if not pantsd_in_command and not pantsd_in_config: args.append("--pantsd" if use_pantsd else "--no-pantsd") if hermetic: args.append("--pants-config-files=[]") if config: toml_file_name = os.path.join(workdir, "pants.toml") with safe_open(toml_file_name, mode="w") as fp: fp.write(TomlSerializer(config).serialize()) args.append(f"--pants-config-files={toml_file_name}") pants_script = [sys.executable, "-m", "pants"] # Permit usage of shell=True and string-based commands to allow e.g. `./pants | head`. pants_command: Command if kwargs.get("shell") is True: assert not isinstance( command, list), "must pass command as a string when using shell=True" pants_command = " ".join([*pants_script, " ".join(args), command]) else: pants_command = [*pants_script, *args, *command] # Only allow-listed entries will be included in the environment if hermetic=True. Note that # the env will already be fairly hermetic thanks to the v2 engine; this provides an # additional layer of hermiticity. if hermetic: # With an empty environment, we would generally get the true underlying system default # encoding, which is unlikely to be what we want (it's generally ASCII, still). So we # explicitly set an encoding here. env = {"LC_ALL": "en_US.UTF-8"} # Apply our allowlist. for h in ( "HOME", "PATH", # Needed to find Python interpreters and other binaries. "PANTS_PROFILE", "RUN_PANTS_FROM_PEX", ): value = os.getenv(h) if value is not None: env[h] = value hermetic_env = os.getenv("HERMETIC_ENV") if hermetic_env: for h in hermetic_env.strip(",").split(","): value = os.getenv(h) if value is not None: env[h] = value else: env = os.environ.copy() if extra_env: env.update(extra_env) env.update(PYTHONPATH=os.pathsep.join(sys.path)) # Pants command that was called from the test shouldn't have a parent. if "PANTS_PARENT_BUILD_ID" in env: del env["PANTS_PARENT_BUILD_ID"] return PantsJoinHandle( command=pants_command, process=subprocess.Popen( pants_command, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs, ), workdir=workdir, )
def run_pants_with_workdir_without_waiting( self, command, workdir, config=None, extra_env=None, build_root=None, print_exception_stacktrace=True, **kwargs, ) -> PantsJoinHandle: args = [ "--no-pantsrc", f"--pants-workdir={workdir}", f"--print-exception-stacktrace={print_exception_stacktrace}", ] if self.hermetic(): args.extend( [ "--pants-config-files=[]", # Turn off cache globally. A hermetic integration test shouldn't rely on cache, # or we have no idea if it's actually testing anything. "--no-cache-read", "--no-cache-write", # Turn cache on just for tool bootstrapping, for performance. "--cache-bootstrap-read", "--cache-bootstrap-write", ] ) if self.use_pantsd_env_var(): args.append("--pantsd") if config: toml_file_name = os.path.join(workdir, "pants.toml") with safe_open(toml_file_name, mode="w") as fp: fp.write(TomlSerializer(config).serialize()) args.append("--pants-config-files=" + toml_file_name) pants_script = [sys.executable, "-m", "pants"] # Permit usage of shell=True and string-based commands to allow e.g. `./pants | head`. if kwargs.get("shell") is True: assert not isinstance( command, list ), "must pass command as a string when using shell=True" pants_command = " ".join([*pants_script, " ".join(args), command]) else: pants_command = pants_script + args + command # Only whitelisted entries will be included in the environment if hermetic=True. if self.hermetic(): env = dict() # With an empty environment, we would generally get the true underlying system default # encoding, which is unlikely to be what we want (it's generally ASCII, still). So we # explicitly set an encoding here. env["LC_ALL"] = "en_US.UTF-8" for h in self.hermetic_env_whitelist(): value = os.getenv(h) if value is not None: env[h] = value hermetic_env = os.getenv("HERMETIC_ENV") if hermetic_env: for h in hermetic_env.strip(",").split(","): value = os.getenv(h) if value is not None: env[h] = value else: env = os.environ.copy() if extra_env: env.update(extra_env) env.update(PYTHONPATH=os.pathsep.join(sys.path)) # Pants command that was called from the test shouldn't have a parent. if "PANTS_PARENT_BUILD_ID" in env: del env["PANTS_PARENT_BUILD_ID"] # Don't overwrite the profile of this process in the called process. # Instead, write the profile into a sibling file. if env.get("PANTS_PROFILE"): prof = f"{env['PANTS_PROFILE']}.{self._get_profile_disambiguator()}" env["PANTS_PROFILE"] = prof # Make a note the subprocess command, so the user can correctly interpret the profile files. with open(f"{prof}.cmd", "w") as fp: fp.write(" ".join(pants_command)) return PantsJoinHandle( command=pants_command, process=subprocess.Popen( pants_command, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs, ), workdir=workdir, )