config2py.util#
Utility functions for config2py.
Module Attributes
|
Declarative description of where a given folder kind lives on a platform. |
Functions
|
True if |
|
Function that just returns True. |
|
Return the |
|
Ask the user for input, optionally masking, validating and transforming the input. |
|
Create directories up to a specified limit. |
|
Copy a bundled seed file to target if it does not already exist. |
|
Reads the contents of a config file, extracting Unix-style environment variable declarations of the form |
|
Retrieve or create the app directory specific to the given app name and folder kind. |
|
Returns the root directory for a specific folder kind. |
|
Retrieve or create the configs directory specific to the given app name. |
|
Retrieve or create the configs directory specific to the given app name. |
|
Function that just returns its argument. |
|
Function that returns True if x is not empty. |
|
Determines if the Python interpreter is running in REPL. |
|
True if |
|
Parse assignments from python source code. |
|
|
|
Open |
Get the system default folder for |
Classes
|
Per-user data directory facade for a Python application. |
Class to wrap environment variables, hiding values from |
|
|
Declarative description of where a given folder kind lives on a platform. |
- class config2py.util.AppData(app_name, *, package_name=None, seed_data_dir='_seed_data')[source]#
Bases:
objectPer-user data directory facade for a Python application.
Binds an application name (and optional Python package name) once and provides convenient access to:
resources — editable reference data seeded from the package on first access (
~/.local/share/<app>/resources/).config — user preference files, also seeded on first access (
~/.config/<app>/).artifact directories — runtime-generated data organised by kind (
~/.local/share/<app>/artifacts/<kind>/).
Seed files are read via
importlib.resourcesfrom<package_name>._seed_data.{resources,config}/.- Parameters:
app_name (
str) – The application name used for the directory under the XDG root (e.g."my_app"→~/.local/share/my_app).package_name (
Optional[str]) – The top-level Python package that contains the_seed_datadirectory. Defaults to app_name.seed_data_dir (
str) – Name of the seed-data sub-package inside the Python package (default"_seed_data").
Example
>>> app = AppData("myapp", package_name="myapp") >>> app.app_folder() PosixPath('/Users/.../.local/share/myapp')
- app_folder(*, folder_kind='data')[source]#
Return the app directory for folder_kind, creating it if needed.
- Return type:
- get_artifact_dir(kind)[source]#
Return (and create) an artifact sub-directory for kind.
- Return type:
- config2py.util.DFLT_MASKING_INPUT(text)#
True if
text(typically a prompt naming a config key) looks secret.It errs on the side of masking: a false positive only means the user doesn’t see what they type, while a false negative echoes a secret to the terminal. It is a plain substring match on the whole prompt, so
KEYS_DIRorAUTHORalso match, as would a custom prompt template mentioning “key”. Pass an explicitmask_input(or your own predicate) when that matters.- Return type:
>>> looks_like_secret("Enter a value for OPENAI_API_KEY: ") True >>> looks_like_secret("Enter a value for github_token: ") True >>> looks_like_secret("Enter a value for DATA_DIR: ") False
- class config2py.util.EnvironmentVariables[source]#
Bases:
ChainMapClass to wrap environment variables, hiding values from
repr/printonly.__repr__is overridden to avoid printing secrets to a REPL or log, but values are still reachable through normalMappingoperations –dict(envvar),envvar.items()/.values(),pickle.dumps(envvar), or a structured logger that walks the mapping. Treat this as UI-level redaction, not access control (see i2mint/config2py#16).
- class config2py.util.FolderSpec(env_var, default_path, subpath)#
Bases:
tupleDeclarative description of where a given folder kind lives on a platform.
env_varis the platform-standard environment variable that, when set, names the root folder.default_pathis the root to use when that variable is absent (~is expanded).subpathis a relative path appended to the root; it exists because some platform standards place a folder kind inside another kind’s root rather than under its own variable (e.g. Windows cache lives at%LOCALAPPDATA%\\Temp).- default_path#
Alias for field number 1
- env_var#
Alias for field number 0
- subpath#
Alias for field number 2
- config2py.util.app_folder_standards(os_name='posix')[source]#
Return the
{folder_kind: FolderSpec}table for the givenos.name.This is the single place where config2py branches on the operating system: everything else consumes the returned table. Exposing it as a function (rather than an
ifat import time) keeps the branch testable on any platform – callers can ask for the table of an OS they are not running on.- Parameters:
os_name (
str) – Anos.namevalue;"nt"selects the Windows standards, anything else selects the XDG Base Directory standards.- Return type:
>>> app_folder_standards("nt")["cache"] FolderSpec(env_var='LOCALAPPDATA', default_path='~\\AppData\\Local', subpath='Temp') >>> app_folder_standards("posix")["cache"] FolderSpec(env_var='XDG_CACHE_HOME', default_path='~/.cache', subpath='')
- config2py.util.ask_user_for_input(prompt, default='', *, mask_input=<function looks_like_secret>, masking_toggle_str=None, egress=<function identity>)[source]#
Ask the user for input, optionally masking, validating and transforming the input.
- Parameters:
prompt (
str) – Prompt to display to the userdefault (
str) – Default value to return if the user enters nothingmask_input (
bool|Callable[[str],bool]) – Whether to mask the user’s input: a bool, or aprompt -> boolpredicate. The default,looks_like_secret, masks prompts that mention something secret-looking (API_KEY,TOKEN,PASSWORD, …) and echoes the others. When masking is decided by a predicate and stdin is piped (not a terminal), the response is read from stdin, as it was before this default existed. An explicitTruealways usesgetpass.getpass, which reads the terminal even when stdin is piped.masking_toggle_str (
str) – String to toggle input masking. IfNone, no toggle is available. If notNone(a common choice is the empty string) the user can enter this string to toggle input masking.egress (
Callable) – Function to apply to the user’s response before returning it. This can be used to validate the response, for example.
- Return type:
- Returns:
The user’s response (or the default value if the user entered nothing)
- config2py.util.create_directories(dirpath, max_dirs_to_make=None)[source]#
Create directories up to a specified limit.
- Parameters:
- Returns:
True if the directory was created successfully, False otherwise.
- Return type:
- Raises:
ValueError – If max_dirs_to_make is negative.
Examples
>>> import tempfile, shutil >>> temp_dir = tempfile.mkdtemp() >>> target_dir = os.path.join(temp_dir, 'a', 'b', 'c') >>> create_directories(target_dir, max_dirs_to_make=2) False >>> create_directories(target_dir, max_dirs_to_make=3) True >>> os.path.isdir(target_dir) True >>> shutil.rmtree(temp_dir) # Cleanup
>>> temp_dir = tempfile.mkdtemp() >>> target_dir = os.path.join(temp_dir, 'a', 'b', 'c', 'd') >>> create_directories(target_dir) True >>> os.path.isdir(target_dir) True >>> shutil.rmtree(temp_dir) # Cleanup
- config2py.util.ensure_seeded(target, package_name, seed_subpackage, filename, *, seed_data_dir='_seed_data')[source]#
Copy a bundled seed file to target if it does not already exist.
Reads the seed from
importlib.resources.files( "{package_name}.{seed_data_dir}.{seed_subpackage}") / filenameand writes its bytes to target. If target already exists, this is a no-op (user edits are preserved).- Parameters:
target (
Union[str,Path]) – Destination path for the seeded file.package_name (
str) – Top-level Python package that ships the seed data.seed_subpackage (
str) – Subdirectory inside_seed_data(e.g."resources"or"config").filename (
str) – Name of the seed file.seed_data_dir (
str) – Name of the seed-data directory inside package_name (default"_seed_data").
- Return type:
- Returns:
The resolved target as a
Path.
Example
>>> from config2py import ensure_seeded >>> # ensure_seeded("/tmp/myfile.txt", "mypkg", "resources", "myfile.txt")
- config2py.util.extract_variable_declarations(string, expand=None)[source]#
Reads the contents of a config file, extracting Unix-style environment variable declarations of the form
export {NAME}={value}, returning a dictionary of{NAME: value, ...}pairs.See issue for more info and applications: i2mint/config2py#2
- Parameters:
string (
str) – String to extract variable declarations fromexpand (
dict|bool|None) – An optional dictionary of variable names and values to use to expand variables that are referenced (i.e.$NAMEis a reference toNAMEvariable) in the values of config variables. IfTrue,expandis replaced with an empty dictionary, which means we want to expand variables recursively, but we have no references to seed the expansion with. IfFalse,expandis replaced withNone, indicating that we don’t want to expand any variables.
- Return type:
- Returns:
A dictionary of variable names and values.
>>> config = 'export ENVIRONMENT="dev"\nexport PORT=8080\nexport DEBUG=true' >>> extract_variable_declarations(config) {'ENVIRONMENT': 'dev', 'PORT': '8080', 'DEBUG': 'true'}
>>> config = 'export PATH="$PATH:/usr/local/bin"\nexport EDITOR="nano"' >>> extract_variable_declarations(config) {'PATH': '$PATH:/usr/local/bin', 'EDITOR': 'nano'}
The
expandargument can be used to expand variables in the values of other.Let’s add a reference to the
PATHvariable in theEDITORvariable:>>> config = 'export PATH="$PATH:/usr/local/bin"\nexport EDITOR="nano $PATH"'
If you specify a value for
PATHin theexpandargument, you’ll see it reflected in thePATHvariable (self reference) and theEDITORvariable. (Note if you changed the order ofPATHandEDITORin theconfig, you wouldn’t get the same thing though.)>>> extract_variable_declarations(config, expand={'PATH': '/root'}) {'PATH': '/root:/usr/local/bin', 'EDITOR': 'nano /root:/usr/local/bin'}
If you specify
expand={}, the firstPATHvariable will not be expanded, since PATH is not in the expand dictionary. But the secondPATHvariable, referenced in the definition ofEDITORwill be expanded, since it is in the expand dictionary.>>> extract_variable_declarations(config, expand={}) {'PATH': '$PATH:/usr/local/bin', 'EDITOR': 'nano $PATH:/usr/local/bin'}
- config2py.util.get_app_config_folder(app_name='config2py', *, setup_callback=<function _default_folder_setup>, ensure_exists=False, folder_kind='config')#
Retrieve or create the app directory specific to the given app name and folder kind.
The folder kind determines where the app’s files are stored. Here are concise explanations for each folder kind:
config: User preferences and settings files (e.g., API keys, theme preferences, editor settings). Files users might edit manually or that define how the app behaves.
data: Essential user-created content and application state (e.g., databases, saved games, user documents, session files). Data that should be backed up and persists across updates.
cache: Temporary, regeneratable files (e.g., downloaded images, compiled assets, web cache). Can be safely deleted to free space without losing user work.
state: Application state and logs that persist between sessions but aren’t critical user data (e.g., command history, undo history, recently opened files, log files). Unlike cache, shouldn’t be auto-deleted.
runtime: Temporary runtime files that only exist while the app runs (e.g., PID files, Unix sockets, lock files, named pipes). Typically cleared on logout/reboot.
TL;DR: config = settings, data = user files, cache = disposable, state = logs/history, runtime = process files.
- Parameters:
app_name – Name of the app for which the directory is needed.
setup_callback – A callback function to initialize the directory. Default is _default_folder_setup.
ensure_exists – Whether to ensure the directory exists.
folder_kind – Type of folder (‘config’, ‘data’, ‘cache’, ‘state’, or ‘runtime’). Default is ‘config’ for backward compatibility.
- Returns:
Path to the app directory.
- Return type:
By default, the app will be “config2py” and folder_kind will be “config”. The exact text of the path is platform-specific (
~/.config/config2pyunder the XDG standards,%APPDATA%\config2pyon Windows), so we assert the properties that hold everywhere: it is an absolute path named after the app, sitting directly inside the ‘config’ root directory.>>> folder = get_app_folder() >>> os.path.isabs(folder) True >>> os.path.basename(folder) 'config2py' >>> os.path.dirname(folder) == get_app_rootdir('config') True
You can specify a different app name and folder kind:
>>> get_app_folder('my_app', folder_kind='data') '/Users/.../.local/share/my_app' >>> get_app_folder('my_app', folder_kind='cache') '/Users/.../.cache/my_app'
You can also specify a path relative to the app root directory:
>>> get_app_folder('another/app/subfolder', folder_kind='data') '/Users/.../.local/share/another/app/subfolder'
If ensure_exists is True, the directory will be created and initialized with the setup_callback:
>>> path = get_app_folder('my_app', ensure_exists=True) >>> os.path.exists(path) True
- config2py.util.get_app_data_directory(app_name='config2py', *, setup_callback=<function _default_folder_setup>, ensure_exists=False, folder_kind='config')#
Retrieve or create the app directory specific to the given app name and folder kind.
The folder kind determines where the app’s files are stored. Here are concise explanations for each folder kind:
config: User preferences and settings files (e.g., API keys, theme preferences, editor settings). Files users might edit manually or that define how the app behaves.
data: Essential user-created content and application state (e.g., databases, saved games, user documents, session files). Data that should be backed up and persists across updates.
cache: Temporary, regeneratable files (e.g., downloaded images, compiled assets, web cache). Can be safely deleted to free space without losing user work.
state: Application state and logs that persist between sessions but aren’t critical user data (e.g., command history, undo history, recently opened files, log files). Unlike cache, shouldn’t be auto-deleted.
runtime: Temporary runtime files that only exist while the app runs (e.g., PID files, Unix sockets, lock files, named pipes). Typically cleared on logout/reboot.
TL;DR: config = settings, data = user files, cache = disposable, state = logs/history, runtime = process files.
- Parameters:
app_name – Name of the app for which the directory is needed.
setup_callback – A callback function to initialize the directory. Default is _default_folder_setup.
ensure_exists – Whether to ensure the directory exists.
folder_kind – Type of folder (‘config’, ‘data’, ‘cache’, ‘state’, or ‘runtime’). Default is ‘config’ for backward compatibility.
- Returns:
Path to the app directory.
- Return type:
By default, the app will be “config2py” and folder_kind will be “config”. The exact text of the path is platform-specific (
~/.config/config2pyunder the XDG standards,%APPDATA%\config2pyon Windows), so we assert the properties that hold everywhere: it is an absolute path named after the app, sitting directly inside the ‘config’ root directory.>>> folder = get_app_folder() >>> os.path.isabs(folder) True >>> os.path.basename(folder) 'config2py' >>> os.path.dirname(folder) == get_app_rootdir('config') True
You can specify a different app name and folder kind:
>>> get_app_folder('my_app', folder_kind='data') '/Users/.../.local/share/my_app' >>> get_app_folder('my_app', folder_kind='cache') '/Users/.../.cache/my_app'
You can also specify a path relative to the app root directory:
>>> get_app_folder('another/app/subfolder', folder_kind='data') '/Users/.../.local/share/another/app/subfolder'
If ensure_exists is True, the directory will be created and initialized with the setup_callback:
>>> path = get_app_folder('my_app', ensure_exists=True) >>> os.path.exists(path) True
- config2py.util.get_app_data_folder(app_name='config2py', *, setup_callback=<function _default_folder_setup>, ensure_exists=False, folder_kind='data')#
Retrieve or create the app directory specific to the given app name and folder kind.
The folder kind determines where the app’s files are stored. Here are concise explanations for each folder kind:
config: User preferences and settings files (e.g., API keys, theme preferences, editor settings). Files users might edit manually or that define how the app behaves.
data: Essential user-created content and application state (e.g., databases, saved games, user documents, session files). Data that should be backed up and persists across updates.
cache: Temporary, regeneratable files (e.g., downloaded images, compiled assets, web cache). Can be safely deleted to free space without losing user work.
state: Application state and logs that persist between sessions but aren’t critical user data (e.g., command history, undo history, recently opened files, log files). Unlike cache, shouldn’t be auto-deleted.
runtime: Temporary runtime files that only exist while the app runs (e.g., PID files, Unix sockets, lock files, named pipes). Typically cleared on logout/reboot.
TL;DR: config = settings, data = user files, cache = disposable, state = logs/history, runtime = process files.
- Parameters:
app_name – Name of the app for which the directory is needed.
setup_callback – A callback function to initialize the directory. Default is _default_folder_setup.
ensure_exists – Whether to ensure the directory exists.
folder_kind – Type of folder (‘config’, ‘data’, ‘cache’, ‘state’, or ‘runtime’). Default is ‘config’ for backward compatibility.
- Returns:
Path to the app directory.
- Return type:
By default, the app will be “config2py” and folder_kind will be “config”. The exact text of the path is platform-specific (
~/.config/config2pyunder the XDG standards,%APPDATA%\config2pyon Windows), so we assert the properties that hold everywhere: it is an absolute path named after the app, sitting directly inside the ‘config’ root directory.>>> folder = get_app_folder() >>> os.path.isabs(folder) True >>> os.path.basename(folder) 'config2py' >>> os.path.dirname(folder) == get_app_rootdir('config') True
You can specify a different app name and folder kind:
>>> get_app_folder('my_app', folder_kind='data') '/Users/.../.local/share/my_app' >>> get_app_folder('my_app', folder_kind='cache') '/Users/.../.cache/my_app'
You can also specify a path relative to the app root directory:
>>> get_app_folder('another/app/subfolder', folder_kind='data') '/Users/.../.local/share/another/app/subfolder'
If ensure_exists is True, the directory will be created and initialized with the setup_callback:
>>> path = get_app_folder('my_app', ensure_exists=True) >>> os.path.exists(path) True
- config2py.util.get_app_folder(app_name='config2py', *, setup_callback=<function _default_folder_setup>, ensure_exists=False, folder_kind='config')[source]#
Retrieve or create the app directory specific to the given app name and folder kind.
The folder kind determines where the app’s files are stored. Here are concise explanations for each folder kind:
config: User preferences and settings files (e.g., API keys, theme preferences, editor settings). Files users might edit manually or that define how the app behaves.
data: Essential user-created content and application state (e.g., databases, saved games, user documents, session files). Data that should be backed up and persists across updates.
cache: Temporary, regeneratable files (e.g., downloaded images, compiled assets, web cache). Can be safely deleted to free space without losing user work.
state: Application state and logs that persist between sessions but aren’t critical user data (e.g., command history, undo history, recently opened files, log files). Unlike cache, shouldn’t be auto-deleted.
runtime: Temporary runtime files that only exist while the app runs (e.g., PID files, Unix sockets, lock files, named pipes). Typically cleared on logout/reboot.
TL;DR: config = settings, data = user files, cache = disposable, state = logs/history, runtime = process files.
- Parameters:
app_name (
str) – Name of the app for which the directory is needed.setup_callback (
Callable[[str],None]) – A callback function to initialize the directory. Default is _default_folder_setup.ensure_exists (
bool) – Whether to ensure the directory exists.folder_kind (
Literal['config','data','cache','state','runtime']) – Type of folder (‘config’, ‘data’, ‘cache’, ‘state’, or ‘runtime’). Default is ‘config’ for backward compatibility.
- Returns:
Path to the app directory.
- Return type:
By default, the app will be “config2py” and folder_kind will be “config”. The exact text of the path is platform-specific (
~/.config/config2pyunder the XDG standards,%APPDATA%\config2pyon Windows), so we assert the properties that hold everywhere: it is an absolute path named after the app, sitting directly inside the ‘config’ root directory.>>> folder = get_app_folder() >>> os.path.isabs(folder) True >>> os.path.basename(folder) 'config2py' >>> os.path.dirname(folder) == get_app_rootdir('config') True
You can specify a different app name and folder kind:
>>> get_app_folder('my_app', folder_kind='data') '/Users/.../.local/share/my_app' >>> get_app_folder('my_app', folder_kind='cache') '/Users/.../.cache/my_app'
You can also specify a path relative to the app root directory:
>>> get_app_folder('another/app/subfolder', folder_kind='data') '/Users/.../.local/share/another/app/subfolder'
If ensure_exists is True, the directory will be created and initialized with the setup_callback:
>>> path = get_app_folder('my_app', ensure_exists=True) >>> os.path.exists(path) True
- config2py.util.get_app_rootdir(folder_kind='config', *, ensure_exists=True)[source]#
Returns the root directory for a specific folder kind.
The folder kind determines which standard directory is returned:
‘config’: Configuration files (XDG_CONFIG_HOME, default ~/.config)
‘data’: Application data (XDG_DATA_HOME, default ~/.local/share)
‘cache’: Temporary/cache files (XDG_CACHE_HOME, default ~/.cache)
‘state’: State data/logs (XDG_STATE_HOME, default ~/.local/state)
‘runtime’: Runtime files (XDG_RUNTIME_DIR, default /tmp)
On Windows:
‘config’: %APPDATA%
‘data’: %LOCALAPPDATA%
‘cache’: %LOCALAPPDATA%Temp
‘state’: %LOCALAPPDATA%
‘runtime’: %TEMP%
- Parameters:
folder_kind (
Literal['config','data','cache','state','runtime']) – The kind of folder to get. One of ‘config’, ‘data’, ‘cache’, ‘state’, ‘runtime’. Defaults to ‘config’. Here are concise explanations for each folder kind: config: User preferences and settings files (e.g., API keys, theme preferences, editor settings). Files users might edit manually or that define how the app behaves. data: Essential user-created content and application state (e.g., databases, saved games, user documents, session files). Data that should be backed up and persists across updates. cache: Temporary, regeneratable files (e.g., downloaded images, compiled assets, web cache). Can be safely deleted to free space without losing user work. state: Application state and logs that persist between sessions but aren’t critical user data (e.g., command history, undo history, recently opened files, log files). Unlike cache, shouldn’t be auto-deleted. runtime: Temporary runtime files that only exist while the app runs (e.g., PID files, Unix sockets, lock files, named pipes). Typically cleared on logout/reboot. TL;DR: config = settings, data = user files, cache = disposable, state = logs/history, runtime = process files.ensure_exists (
bool) – Whether to create the directory if it doesn’t exist
- Returns:
The full path of the app root folder for the specified kind.
- Return type:
Note
The default root folder follows XDG Base Directory standards on Unix/Linux/macOS. You can override this by setting environment variables:
CONFIG2PY_CONFIG_DIR, CONFIG2PY_DATA_DIR, CONFIG2PY_CACHE_DIR, etc. (highest priority, overrides everything, and works on every platform – see
config2py_env_varfor the full list of names)The platform’s own standard variable: XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_CACHE_HOME, etc. on Unix/Linux/macOS; APPDATA / LOCALAPPDATA / TEMP on Windows. The XDG variables are a POSIX standard and are not consulted on Windows – use the CONFIG2PY_* variables above for platform-neutral overrides.
If neither is set, uses platform defaults
Examples
>>> get_app_rootdir('config') '/Users/.../.config' >>> get_app_rootdir('data') '/Users/.../.local/share' >>> get_app_rootdir('cache') '/Users/.../.cache'
- config2py.util.get_configs_directory_for_app(app_name='config2py', *, configs_name='configs', app_dir_setup_callback=<function _default_folder_setup>, config_dir_setup_callback=<function _default_folder_setup>)#
Retrieve or create the configs directory specific to the given app name.
- Parameters:
app_name (
str) – Name of the app for which the configs directory is needed.configs_name (
str) – Name of the configs directory.app_dir_setup_callback (
Callable[[str],None]) – A callback function to initialize the app directory. Default is _default_folder_setup.config_dir_setup_callback (
Callable[[str],None]) – A callback function to initialize the configs directory. Default is _default_folder_setup.
- config2py.util.get_configs_folder_for_app(app_name='config2py', *, configs_name='configs', app_dir_setup_callback=<function _default_folder_setup>, config_dir_setup_callback=<function _default_folder_setup>)[source]#
Retrieve or create the configs directory specific to the given app name.
- Parameters:
app_name (
str) – Name of the app for which the configs directory is needed.configs_name (
str) – Name of the configs directory.app_dir_setup_callback (
Callable[[str],None]) – A callback function to initialize the app directory. Default is _default_folder_setup.config_dir_setup_callback (
Callable[[str],None]) – A callback function to initialize the configs directory. Default is _default_folder_setup.
- config2py.util.is_repl()[source]#
Determines if the Python interpreter is running in REPL.
To test: If you put it in a module.py, do a print of it in the module, and do
python module.pyit should print False. If you dopython -i module.py, or call it from a python console or jupyter notebook, it should returnTrue.- Returns:
True if running in a REPL, False otherwise.
- Return type:
is_replreturnsTrueif any function inis_repl.repl_conditions(a set of no-argument callables) returnsTrue. By default that set checks whetherget_ipythonis in globals, or whether__main__has no__file__attribute. Mutateis_repl.repl_conditionsin place (e.g.is_repl.repl_conditions.add(fn)) to change the checks – rebinding the attribute to a new set has no effect, sinceis_replreads the original set.
- config2py.util.looks_like_secret(text)[source]#
True if
text(typically a prompt naming a config key) looks secret.It errs on the side of masking: a false positive only means the user doesn’t see what they type, while a false negative echoes a secret to the terminal. It is a plain substring match on the whole prompt, so
KEYS_DIRorAUTHORalso match, as would a custom prompt template mentioning “key”. Pass an explicitmask_input(or your own predicate) when that matters.- Return type:
>>> looks_like_secret("Enter a value for OPENAI_API_KEY: ") True >>> looks_like_secret("Enter a value for github_token: ") True >>> looks_like_secret("Enter a value for DATA_DIR: ") False
- config2py.util.parse_assignments_from_py_source(source_code, *, name_filt=None, value_filt=<function _value_node_is_instance_of>)[source]#
Parse assignments from python source code.
>>> source_code = '''a = 1 ... b = 'hello' ... c = [1, 2, 3] ... def func(): ... d = 4 ... ''' >>> dict(parse_assignments_from_py_source(source_code)) {'a': 1, 'b': 'hello', 'c': [1, 2, 3], 'd': 4}
- config2py.util.secure_makedirs(dirpath, *, exist_ok=True)[source]#
os.makedirs(dirpath, mode=0o700), re-tightening the mode if it already exists.os.makedirs(..., mode=0o700, exist_ok=True)alone won’t re-tighten an existing directory’s mode, so this follows up with an explicitos.chmod. Intended for directories that may hold config/secret files (see i2mint/config2py#15).
- config2py.util.secure_open(path, mode='w')[source]#
Open
pathfor writing with owner-only (0o600) permissions.Two cases, both handled:
New file: the restrictive mode is applied atomically at creation via
os.open, so there is no window where the file briefly exists with the process’s default umask (commonly world-readable,0o644).Pre-existing file with looser permissions:
os.open’smodeargument is a POSIX no-op in this case (only consulted when a new file is actually created), so an explicitos.fchmodre-tightens it – on the open file descriptor, not the path, so it’s not subject to a TOCTOU swap either.
Intended for files that may hold secrets (see i2mint/config2py#15).
>>> import tempfile, os >>> path = tempfile.mktemp() >>> with secure_open(path, "w") as f: ... _ = f.write("secret") >>> # Unix mode bits aren't meaningful on Windows -- os.stat there reports 0o666 >>> # regardless of what secure_open does, so only assert the mode on POSIX. >>> oct(os.stat(path).st_mode & 0o777) if os.name == "posix" else "0o600" '0o600' >>> os.remove(path)
- config2py.util.system_default_for_app_data_folder(folder_kind='config', *, standards=None)[source]#
Get the system default folder for
folder_kind.The root is the value of the platform’s standard environment variable for that kind, falling back to the spec’s
default_path; the spec’ssubpath(usually empty) is then appended.- Parameters:
folder_kind (
Literal['config','data','cache','state','runtime']) – One of ‘config’, ‘data’, ‘cache’, ‘state’, ‘runtime’.standards (
Optional[dict]) – The{folder_kind: FolderSpec}table to resolve against. Defaults to the running platform’s (APP_FOLDER_STANDARDS); pass another platform’s table to resolve as that platform would.
- Return type: