Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

## [1.5.2]

### Added

- `isolated` added
- `local_modules` and `shared_modules` added

## [1.5.1]

### Fixed
Expand Down
11 changes: 11 additions & 0 deletions docs/source/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,17 @@ Example:
Top-Level Configuration Keys
----------------------------

isolated
~~~~~~~~

The ``isolated`` key controls how this configuration module is registered when imported.

- ``true`` *(default)* → The module is added as a **local module** for the importing parser only.
Other parsers that import this module will have it in their **local_modules**.

- ``false`` → The module is added to **shared_modules** if not already present.
Shared modules are globally accessible and can be reused by multiple parsers.

local
~~~~~

Expand Down
15 changes: 14 additions & 1 deletion docs/source/parser.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ Initialization

ConfigParser(
config_path: str | Path,
kwargs: dict | None = None
kwargs: dict | None = None,
*,
isolated: bool = True,
)

Parameters:
Expand All @@ -40,6 +42,17 @@ Parameters:
Optional runtime keyword arguments.
These values take precedence during resolution.

- ``isolated`` *(default: True)*
Controls how this parser is registered in Kaizo's module system.

- If ``true`` *(default)*
The module is added as a **local module** for any parser that imports it.
This means it is only accessible to the parser that imported it.

- If ``false``
The module is added to **shared_modules** if it isn't already present.
Shared modules are globally accessible to all parsers, allowing cross-file references and preventing duplication.

.. note::

Runtime ``kwargs`` override values found in configuration files
Expand Down
73 changes: 52 additions & 21 deletions kaizo/parser.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
from pathlib import Path
from types import ModuleType
from typing import Any
from typing import Any, Self

import yaml

Expand All @@ -24,10 +24,18 @@ class ConfigParser:
local: ModuleType | None
storage: dict[str, Storage]
kwargs: DictEntry[str]
modules: dict[str, "ConfigParser"] | None
local_modules: dict[str, Self] | None
shared_modules: dict[str, Self] = {}
plugins: dict[str, FnWithKwargs[Plugin]] | None
isolated: bool

def __init__(self, config_path: str | Path, kwargs: dict[str] | None = None) -> None:
def __init__(
self,
config_path: str | Path,
kwargs: dict[str] | None = None,
*,
isolated: bool = True,
) -> None:
root, _ = os.path.split(config_path)

root = Path(root)
Expand All @@ -38,6 +46,8 @@ def __init__(self, config_path: str | Path, kwargs: dict[str] | None = None) ->
with Path.open(config_path) as file:
self.config = yaml.safe_load(file)

self.isolated = self.config.pop("isolated", isolated)

if "local" in self.config:
local_path = Path(self.config.pop("local"))

Expand All @@ -55,9 +65,23 @@ def __init__(self, config_path: str | Path, kwargs: dict[str] | None = None) ->
msg = f"import module should be a dict, got {type(modules)}"
raise TypeError(msg)

self.modules = self._import_modules(root, modules, kwargs)
imported_modules = self._import_modules(
root,
modules,
kwargs,
isolated=isolated,
)

self.local_modules = {}

for key, value in imported_modules.items():
if value.isolated:
self.local_modules[key] = value
elif key not in ConfigParser.shared_modules:
ConfigParser.shared_modules[key] = value

else:
self.modules = None
self.local_modules = None

if "plugins" in self.config:
plugins = self.config.pop("plugins")
Expand All @@ -75,7 +99,9 @@ def _import_modules(
root: Path,
modules: dict[str, str],
kwargs: dict[str] | None = None,
) -> dict[str, "ConfigParser"]:
*,
isolated: bool = True,
) -> dict[str, Self]:
module_dict = {}

for module_name, module_path_str in modules.items():
Expand All @@ -84,7 +110,7 @@ def _import_modules(
if not module_path.is_absolute():
module_path = root / module_path

parser = ConfigParser(module_path, kwargs)
parser = ConfigParser(module_path, kwargs, isolated=isolated)
parser.parse()

module_dict[module_name] = parser
Expand Down Expand Up @@ -154,9 +180,24 @@ def _load_symbol_from_module(self, module_path: str, symbol_name: str) -> Any:

return ModuleLoader.load_object(module_path, symbol_name)

def _resolve_parser(self, key: str) -> Self:
if self.local_modules is None:
msg = "import module is not given"
raise ValueError(msg)

module = self.local_modules.get(key)

if module is None:
module = ConfigParser.shared_modules.get(key)

if module is None:
msg = f"keyword not found, got {key}"
raise ValueError(msg)

return module

def _resolve_from_storage(
self,
storage: dict[str, Storage],
*,
key: str,
entry_key: str | None,
Expand All @@ -172,7 +213,7 @@ def _resolve_from_storage(
if not storage_key:
storage_key = key

storage_i = storage.get(storage_key)
storage_i = self.storage.get(storage_key)

if storage_i is None:
return None
Expand All @@ -190,25 +231,15 @@ def _resolve_string(self, key: str, entry: str) -> Entry:
return self.kwargs[entry_sub_key]

parsed_entry = self._resolve_from_storage(
self.storage,
key=key,
entry_key=entry_key,
entry_sub_key=entry_sub_key,
)

else:
if self.modules is None:
msg = "import module is not given"
raise ValueError(msg)
parser = self._resolve_parser(entry_module)

module = self.modules.get(entry_module)

if module is None:
msg = f"keyword not found, got {entry_module}"
raise ValueError(msg)

parsed_entry = self._resolve_from_storage(
module.storage,
parsed_entry = parser._resolve_from_storage(
key=key,
entry_key=entry_key,
entry_sub_key=entry_sub_key,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "kaizo"
version = "1.5.1"
version = "1.5.2"
description = "declarative YAML-based configuration parser"
authors = [{ name = "Mohammad Ghazanfari", email = "mgh.5225@gmail.com" }]
readme = "README.md"
Expand Down
Loading