Split out of #16 (items 5 and 6, same root cause: detect-and-fall-through where detect-and-raise would catch user error).
Reproduction (verified 2026-09-26, config2py 0.1.54)
>>> from config2py import extract_exports, ConfigReader
>>> extract_exports("path/to/.env") # file does not exist
{}
>>> r = ConfigReader("no/such/file.ini") # file does not exist
>>> dict(r), r.source_kind
({'DEFAULT': <Section: DEFAULT>}, 'filepath')
Note on item 5: the typo'd-path case goes through the isinstance(source, str) / no-newline branch of ConfigReader.__init__ (self.read(source), which silently skips missing files), not the final else branch quoted in #16. Both deserve a fix.
Why this was not changed unattended
Raising where we currently return empty is a behaviour change for existing callers (for instance code that probes optional config files with ConfigReader(path) and expects an empty result). The docstrings now state the current behaviour (cloud-sweep PR).
Proposed plan
ConfigReader: when a no-newline str/Path source does not exist, raise FileNotFoundError, unless a new keyword-only missing_ok=False flag is set to True. In the final else branch raise TypeError(f"Unsupported source: {type(source).__name__}").
extract_exports: if the argument has no newline, does not start with export , and is not an existing file, raise FileNotFoundError. A single export A="1" line keeps working.
- Tests for each case, then the dependents gate (
py2store re-exports config2py.s_configparser).
Split out of #16 (items 5 and 6, same root cause: detect-and-fall-through where detect-and-raise would catch user error).
Reproduction (verified 2026-09-26, config2py 0.1.54)
Note on item 5: the typo'd-path case goes through the
isinstance(source, str)/ no-newline branch ofConfigReader.__init__(self.read(source), which silently skips missing files), not the finalelsebranch quoted in #16. Both deserve a fix.Why this was not changed unattended
Raising where we currently return empty is a behaviour change for existing callers (for instance code that probes optional config files with
ConfigReader(path)and expects an empty result). The docstrings now state the current behaviour (cloud-sweep PR).Proposed plan
ConfigReader: when a no-newlinestr/Pathsource does not exist, raiseFileNotFoundError, unless a new keyword-onlymissing_ok=Falseflag is set toTrue. In the finalelsebranch raiseTypeError(f"Unsupported source: {type(source).__name__}").extract_exports: if the argument has no newline, does not start withexport, and is not an existing file, raiseFileNotFoundError. A singleexport A="1"line keeps working.py2storere-exportsconfig2py.s_configparser).