(self)
| 353 | |
| 354 | @property |
| 355 | def environment_variables(self) -> dict[str, str]: |
| 356 | if self._resolving_env_vars: |
| 357 | # Re-entrant call: set_env resolution triggered a substitution (e.g. {env_site_packages_dir}) |
| 358 | # that requires the virtualenv session, which needs environment_variables to be built first. |
| 359 | # Return pass_env + PATH without set_env to break the cycle. |
| 360 | result = self._load_pass_env(self.conf["pass_env"]) |
| 361 | result["PATH"] = self._make_path() |
| 362 | return result |
| 363 | |
| 364 | pass_env: list[str] = self.conf["pass_env"] |
| 365 | self._resolving_env_vars = True |
| 366 | try: |
| 367 | set_env: SetEnv = self.conf["set_env"] |
| 368 | finally: |
| 369 | self._resolving_env_vars = False |
| 370 | if self._env_vars_pass_env == pass_env and not set_env.changed and self._env_vars is not None: |
| 371 | return self._env_vars |
| 372 | |
| 373 | result = self._load_pass_env(pass_env) |
| 374 | if disallow := self.conf["disallow_pass_env"]: |
| 375 | disallow_patterns = [re.compile(fnmatch.translate(e), re.IGNORECASE) for e in disallow] |
| 376 | result = {k: v for k, v in result.items() if not any(p.match(k) for p in disallow_patterns)} |
| 377 | # load/paths_env might trigger a load of the environment variables, set result here, returns current state |
| 378 | self._env_vars, self._env_vars_pass_env, set_env.changed = result, pass_env.copy(), False |
| 379 | # set PATH here in case setting and environment variable requires access to the environment variable PATH |
| 380 | result["PATH"] = self._make_path() |
| 381 | self._resolving_env_vars = True |
| 382 | try: |
| 383 | for key in set_env: |
| 384 | result[key] = set_env.load(key) |
| 385 | finally: |
| 386 | self._resolving_env_vars = False |
| 387 | # if set_env modified PATH, re-prepend virtual-env paths (deduped) so they always come first |
| 388 | if self._paths and "PATH" in set_env: |
| 389 | result["PATH"] = self._make_path(result["PATH"]) |
| 390 | result["TOX_ENV_NAME"] = self.name |
| 391 | result["TOX_WORK_DIR"] = str(self.core["work_dir"]) |
| 392 | result["TOX_ENV_DIR"] = str(self.conf["env_dir"]) |
| 393 | if (ci := os.environ.get("CI")) is not None: |
| 394 | result["__TOX_ENVIRONMENT_VARIABLE_ORIGINAL_CI"] = ci |
| 395 | return result |
| 396 | |
| 397 | @staticmethod |
| 398 | def _load_pass_env(pass_env: list[str]) -> dict[str, str]: |
nothing calls this directly
no test coverage detected