Skip to content

Commit 83b3ed8

Browse files
worksbyfridaypre-commit-ci[bot]claude
authored
Fix env name with dot losing description in TOML config (#3722)
## Description Fixes #3590 Environment names containing dots (e.g. `"py3.11"`) in `pyproject.toml` had their descriptions silently ignored. `tox list` showed `[no description]` instead of the configured description. ### Reproducer ```toml [tool.tox.env."py3.11"] description = "tox test" ``` ```console $ tox list py3.11 -> [no description] ``` ### Root cause Three interrelated issues in `toml_pyproject.py`: 1. **`sections()` split the env name on dots**: `from_key("py3.11")` treats `.` as the section separator, creating `Section(prefix="py3", name="11")` instead of preserving `"py3.11"` as the name. 2. **`keys` property split ALL dots**: The full key `"tool.tox.env.py3.11"` was split into `["env", "py3", "11"]`. `get_loader()` then tried to traverse `dict["py3"]["11"]` instead of `dict["py3.11"]`, returning `None` (config not found). 3. **`envs()` yielded full key**: When `sections()` is fixed to use `test_env()`, the full key becomes `"tool.tox.env.py3.11"` instead of just `"py3.11"`, causing a phantom duplicate environment. ### Fix - **`keys` property**: Build from `prefix` and `name` components directly instead of splitting the joined key on `SEP`. This preserves dots within the env name while still splitting structural path separators. - **`sections()`**: Use `test_env(env_name)` which correctly sets `prefix="tool.tox.env"` and `name="py3.11"` as an atomic unit. - **`envs()`**: Yield `section.name` instead of `section.key` to return just the env name. - **`get_base_sections()`**: Use `test_env()` for consistency. ### After fix ```console $ tox list py3.11 -> tox test ``` --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0ee48ce commit 83b3ed8

2 files changed

Lines changed: 24 additions & 8 deletions

File tree

docs/changelog/3590.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix env names containing dots (e.g. ``py3.11``) losing their description in TOML configuration - by :user:`Fridayai700`.

src/tox/config/source/toml_pyproject.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,26 @@ def run_env_base(cls) -> str:
5555

5656
@property
5757
def keys(self) -> Iterable[str]:
58-
key = self.key
59-
keys = key.split(self.SEP) if self.key else []
60-
if self.PREFIX and len(keys) >= len(self.PREFIX) and tuple(keys[: len(self.PREFIX)]) == self.PREFIX:
61-
keys = keys[len(self.PREFIX) :]
62-
return keys
58+
# Build keys from prefix and name components directly, rather than
59+
# splitting the joined key on SEP. This preserves dots that are part
60+
# of the name (e.g. environment name "py3.11") instead of treating
61+
# them as path separators.
62+
prefix = self._prefix
63+
name = self._name
64+
if prefix is None and not name:
65+
return []
66+
prefix_parts: list[str] = prefix.split(self.SEP) if prefix else []
67+
# Strip the global PREFIX (e.g. ("tool", "tox")) from the front
68+
if (
69+
self.PREFIX
70+
and len(prefix_parts) >= len(self.PREFIX)
71+
and tuple(prefix_parts[: len(self.PREFIX)]) == self.PREFIX
72+
):
73+
prefix_parts = prefix_parts[len(self.PREFIX) :]
74+
result = prefix_parts
75+
if name:
76+
result.append(name)
77+
return result
6378

6479

6580
class TomlPyProjectSection(TomlSection):
@@ -113,17 +128,17 @@ def get_loader(self, section: Section, override_map: OverrideMap) -> Loader[Any]
113128

114129
def envs(self, core_conf: CoreConfigSet) -> Iterator[str]:
115130
yield from core_conf["env_list"]
116-
yield from [i.key for i in self.sections()]
131+
yield from [i.name for i in self.sections()]
117132

118133
def sections(self) -> Iterator[Section]:
119134
for env_name in self._our_content.get(self._Section.ENV, {}):
120135
if not isinstance(env_name, str):
121136
msg = f"Environment key must be string, got {env_name!r}"
122137
raise HandledError(msg)
123-
yield self._Section.from_key(env_name)
138+
yield self._Section.test_env(env_name)
124139

125140
def get_base_sections(self, base: list[str], in_section: Section) -> Iterator[Section]: # noqa: ARG002
126-
yield from [self._Section.from_key(b) for b in base]
141+
yield from [self._Section.test_env(b) for b in base]
127142

128143
def get_tox_env_section(self, item: str) -> tuple[Section, list[str], list[str]]:
129144
return self._Section.test_env(item), [self._Section.run_env_base()], [self._Section.package_env_base()]

0 commit comments

Comments
 (0)