Skip to content

Commit 13459b7

Browse files
Enhance GlobalOverrides: add dist_name and env_reader property
- Add dist_name parameter to GlobalOverrides.from_env() for distribution-specific overrides - Add env_reader property that provides pre-configured EnvReader instance - Store EnvReader created during initialization to reuse throughout context - __enter__ returns self enabling clean 'with ... as overrides:' pattern - Add comprehensive tests for env_reader property with and without dist_name Benefits: - Convenient access to custom environment variables via overrides.env_reader - Automatic configuration with correct tool prefix and dist_name - Single EnvReader instance per context (efficient and consistent) - Enables dist-specific TOML reading: overrides.env_reader.read_toml() Tests: 44/44 passing
1 parent f5d1473 commit 13459b7

File tree

2 files changed

+86
-3
lines changed

2 files changed

+86
-3
lines changed

vcs-versioning/src/vcs_versioning/overrides.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,16 @@ class GlobalOverrides:
212212
hg_command: Command to use for Mercurial operations
213213
source_date_epoch: Unix timestamp for reproducible builds (None if not set)
214214
tool: Tool prefix used to read these overrides
215+
dist_name: Optional distribution name for dist-specific env var lookups
215216
216217
Usage:
217-
with GlobalOverrides.from_env("HATCH_VCS"):
218+
with GlobalOverrides.from_env("HATCH_VCS", dist_name="my-package") as overrides:
218219
# All modules now have access to these overrides
219220
# Logging is automatically configured based on HATCH_VCS_DEBUG
221+
222+
# Read custom environment variables
223+
custom_val = overrides.env_reader.read("MY_CUSTOM_VAR")
224+
220225
version = get_version(...)
221226
"""
222227

@@ -225,12 +230,15 @@ class GlobalOverrides:
225230
hg_command: str
226231
source_date_epoch: int | None
227232
tool: str
233+
dist_name: str | None = None
234+
_env_reader: EnvReader | None = None # Cached reader, set by from_env
228235

229236
@classmethod
230237
def from_env(
231238
cls,
232239
tool: str,
233240
env: Mapping[str, str] = os.environ,
241+
dist_name: str | None = None,
234242
) -> GlobalOverrides:
235243
"""Read all global overrides from environment variables.
236244
@@ -239,13 +247,16 @@ def from_env(
239247
Args:
240248
tool: Tool prefix (e.g., "HATCH_VCS", "SETUPTOOLS_SCM")
241249
env: Environment dict to read from (defaults to os.environ)
250+
dist_name: Optional distribution name for dist-specific env var lookups
242251
243252
Returns:
244253
GlobalOverrides instance ready to use as context manager
245254
"""
246255

247-
# Use EnvReader to read all environment variables with fallback
248-
reader = EnvReader(tools_names=(tool, "VCS_VERSIONING"), env=env)
256+
# Create EnvReader for reading environment variables with fallback
257+
reader = EnvReader(
258+
tools_names=(tool, "VCS_VERSIONING"), env=env, dist_name=dist_name
259+
)
249260

250261
# Read debug flag - support multiple formats
251262
debug_val = reader.read("DEBUG")
@@ -306,6 +317,8 @@ def from_env(
306317
hg_command=hg_command,
307318
source_date_epoch=source_date_epoch,
308319
tool=tool,
320+
dist_name=dist_name,
321+
_env_reader=reader,
309322
)
310323

311324
def __enter__(self) -> GlobalOverrides:
@@ -351,6 +364,31 @@ def source_epoch_or_utc_now(self) -> datetime:
351364
else:
352365
return datetime.now(timezone.utc)
353366

367+
@property
368+
def env_reader(self) -> EnvReader:
369+
"""Get the EnvReader configured for this tool and distribution.
370+
371+
Returns the EnvReader that was created during initialization, configured
372+
with this GlobalOverrides' tool prefix, VCS_VERSIONING as fallback, and
373+
the optional dist_name for distribution-specific lookups.
374+
375+
Returns:
376+
EnvReader instance ready to read custom environment variables
377+
378+
Example:
379+
>>> with GlobalOverrides.from_env("HATCH_VCS", dist_name="my-package") as overrides:
380+
... custom_val = overrides.env_reader.read("MY_CUSTOM_VAR")
381+
... config = overrides.env_reader.read_toml("CONFIG", schema=MySchema)
382+
"""
383+
if self._env_reader is None:
384+
# Fallback for instances not created via from_env
385+
return EnvReader(
386+
tools_names=(self.tool, "VCS_VERSIONING"),
387+
env=os.environ,
388+
dist_name=self.dist_name,
389+
)
390+
return self._env_reader
391+
354392
@classmethod
355393
def from_active(cls, **changes: Any) -> GlobalOverrides:
356394
"""Create a new GlobalOverrides instance based on the currently active one.

vcs-versioning/testing_vcs/test_overrides_api.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,51 @@ def test_export_integration_with_subprocess_pattern() -> None:
291291
# subprocess.run(["cmd"], env=subprocess_env)
292292

293293

294+
def test_env_reader_property() -> None:
295+
"""Test that GlobalOverrides provides a configured EnvReader."""
296+
env = {
297+
"TOOL_CUSTOM_VAR": "value1",
298+
"VCS_VERSIONING_FALLBACK_VAR": "value2",
299+
"TOOL_VAR_FOR_MY_PKG": "dist_specific",
300+
}
301+
302+
# Without dist_name
303+
with GlobalOverrides.from_env("TOOL", env=env) as overrides:
304+
reader = overrides.env_reader
305+
assert reader.read("CUSTOM_VAR") == "value1"
306+
assert reader.read("FALLBACK_VAR") == "value2" # Uses VCS_VERSIONING fallback
307+
assert reader.read("NONEXISTENT") is None
308+
309+
# With dist_name
310+
with GlobalOverrides.from_env("TOOL", env=env, dist_name="my-pkg") as overrides:
311+
reader = overrides.env_reader
312+
assert reader.read("VAR") == "dist_specific" # Dist-specific takes precedence
313+
314+
315+
def test_env_reader_property_with_dist_name() -> None:
316+
"""Test EnvReader property with distribution-specific variables."""
317+
env = {
318+
"TOOL_CONFIG_FOR_MY_PACKAGE": '{local_scheme = "no-local"}',
319+
"TOOL_CONFIG": '{version_scheme = "guess-next-dev"}',
320+
}
321+
322+
from typing import TypedDict
323+
324+
class TestSchema(TypedDict, total=False):
325+
local_scheme: str
326+
version_scheme: str
327+
328+
with GlobalOverrides.from_env("TOOL", env=env, dist_name="my-package") as overrides:
329+
# Should read dist-specific TOML
330+
config = overrides.env_reader.read_toml("CONFIG", schema=TestSchema)
331+
assert config == {"local_scheme": "no-local"}
332+
333+
# Without dist_name, gets generic
334+
with GlobalOverrides.from_env("TOOL", env=env) as overrides:
335+
config = overrides.env_reader.read_toml("CONFIG", schema=TestSchema)
336+
assert config == {"version_scheme": "guess-next-dev"}
337+
338+
294339
class TestEnvReader:
295340
"""Tests for the EnvReader class."""
296341

0 commit comments

Comments
 (0)