Skip to content

Conversation

@jackdewinter
Copy link
Owner

@jackdewinter jackdewinter commented Jan 24, 2026

Summary by Sourcery

Allow TOML configurations to use quoted keys containing periods and ensure TOML section headers are honored when loading configuration files, while updating tooling, tests, and documentation for the new behavior.

New Features:

  • Add optional section_header_if_toml support in MultisourceConfigurationLoaderOptions to control which TOML section is loaded from configuration files.
  • Introduce reusable patch utilities for builtins.open to simplify testing file I/O behavior.

Bug Fixes:

  • Fix TOML loading to accept keys containing periods when quoted, aligning with TOML semantics and avoiding improper parsing errors.
  • Ensure TOML configuration files loaded via an explicit config flag honor the same section header behavior as implicitly loaded pyproject.toml files.
  • Allow clean.sh to skip dependency upgrade checks via a new --no-upgrades flag.

Enhancements:

  • Extend ApplicationProperties.load_from_dict to optionally allow periods in keys and preserve them as quoted segments in flattened property names.
  • Add targeted tests covering TOML keys with quoted and unquoted separators, unsupported value types, and TOML loading through the multisource configuration loader.
  • Update changelog and version metadata to 0.9.1 documenting the TOML-related fixes and recent feature history.

Documentation:

  • Expand the changelog with a 0.9.1 entry describing TOML parsing fixes and configuration loading behavior changes.

Tests:

  • Add new tests for TOML loader behavior with complex keys and for multisource configuration loading from pyproject.toml and explicit config files.
  • Introduce patch helpers for mocking open in tests to validate TOML loading without touching the real filesystem.

@sourcery-ai
Copy link

sourcery-ai bot commented Jan 24, 2026

Reviewer's Guide

Adds TOML key-handling improvements (allowing quoted period-containing keys), wires TOML section headers into the multisource configuration loader, introduces a reusable builtins.open patching utility for tests, extends TOML-related test coverage, updates the clean script with a no-upgrades flag, bumps the library version to 0.9.1, and documents changes in the changelog.

Sequence diagram for TOML configuration loading with section headers and period-containing keys

sequenceDiagram
    actor Client
    participant Loader as MultisourceConfigurationLoader
    participant Options as MultisourceConfigurationLoaderOptions
    participant Props as ApplicationProperties
    participant TomlLoader as ApplicationPropertiesTomlLoader

    Client->>Loader: _load_config(file_name, options, Props, handle_error_fn)
    Loader->>Loader: determine config_file_type == TOML
    Loader->>Loader: __load_as_toml(file_name, options, Props, handle_error_fn)

    Loader->>TomlLoader: load_and_set(Props, file_name, section_header=options.section_header_if_toml, handle_error_fn, clear_property_map=False, check_for_file_presence=True, strict_mode=True)

    TomlLoader->>TomlLoader: parse TOML file
    TomlLoader->>TomlLoader: extract configuration_map
    alt configuration_map is not empty
        TomlLoader->>Props: load_from_dict(configuration_map, clear_map=clear_property_map, allow_periods_in_keys=True)
        Props->>Props: clear() if clear_map
        Props->>Props: __scan_map(config_map, current_prefix="", allow_periods_in_keys=True)
    end

    TomlLoader-->>Loader: (did_apply_map, did_have_one_error)
    Loader-->>Client: (did_apply_map, did_have_one_error)
Loading

Class diagram for updated configuration loading and TOML key handling

classDiagram
    class ApplicationProperties {
        - Dict[Any, Any] __flat_property_map
        - str __assignment_operator
        - str __separator
        + clear() void
        + load_from_dict(config_map: Dict[Any, Any], clear_map: bool, allow_periods_in_keys: bool) void
        + verify_full_part_form(property_key: str) str
        + property_names_under(key_name: str) List[str]
        - __scan_map(config_map: Dict[Any, Any], current_prefix: str, allow_periods_in_keys: bool) void
    }

    class ApplicationPropertiesTomlLoader {
        + load_and_set(properties_object: ApplicationProperties, file_name: str, section_header: Optional[str], handle_error_fn: Callable[[str, Optional[Exception]], None], clear_property_map: bool, check_for_file_presence: bool, strict_mode: bool) Tuple[bool, bool]
    }

    class MultisourceConfigurationLoaderOptions {
        + bool allow_json5
        + Optional[str] section_header_if_toml
    }

    class MultisourceConfigurationLoader {
        - __load_as_toml(file_name: str, options: MultisourceConfigurationLoaderOptions, application_properties: ApplicationProperties, handle_error_fn: Callable[[str, Optional[Exception]], None]) Tuple[bool, bool]
        - _load_config(file_name: str, options: MultisourceConfigurationLoaderOptions, application_properties: ApplicationProperties, handle_error_fn: Callable[[str, Optional[Exception]], None]) Tuple[bool, bool]
    }

    ApplicationPropertiesTomlLoader --> ApplicationProperties : uses
    MultisourceConfigurationLoader --> ApplicationPropertiesTomlLoader : calls
    MultisourceConfigurationLoader --> MultisourceConfigurationLoaderOptions : reads
    MultisourceConfigurationLoaderOptions --> ApplicationPropertiesTomlLoader : passes section_header
    ApplicationPropertiesTomlLoader --> ApplicationProperties : load_from_dict(allow_periods_in_keys=True)
Loading

File-Level Changes

Change Details Files
Allow periods in configuration keys when loading from TOML while still validating keys from other sources.
  • Extend ApplicationProperties.load_from_dict with an allow_periods_in_keys flag to control separator validation during map scanning.
  • Update __scan_map to accept allow_periods_in_keys, relax the period check when allowed, and wrap keys containing the separator in single quotes so they become part of the flattened key.
  • Call load_from_dict from the TOML loader with allow_periods_in_keys set to True so TOML keys with quoted periods are preserved.
application_properties/application_properties.py
application_properties/application_properties_toml_loader.py
Support specifying a TOML section header when loading configuration through MultisourceConfigurationLoader, aligning explicit and implicit TOML loading behavior.
  • Add section_header_if_toml option to MultisourceConfigurationLoaderOptions with documentation.
  • Change __load_as_toml to accept options and pass options.section_header_if_toml into ApplicationPropertiesTomlLoader.load_and_set.
  • Update _load_config to forward options into __load_as_toml, enabling section header use for auto-detected TOML files.
  • Clarify docstring for add_specified_configuration_file to mention the TOML section header option.
application_properties/multisource_configuration_loader.py
Introduce a reusable patching helper for builtins.open and use it to test TOML loading from implicit and explicit configuration files.
  • Create PatchBase to encapsulate common patch setup/teardown and side-effect wiring for unittest.mock.patch.
  • Implement PatchBuiltinOpen to mock builtins.open for text, binary content, or exceptions, and add context managers for binary content and exception-based patching.
  • Use path_builtin_open_with_binary_content in a new test that verifies implicit pyproject.toml loading via MultisourceConfigurationLoader.
  • Add tests covering quoted-period TOML keys, invalid unquoted keys with periods and slashes, unsupported value types for such keys, and explicit TOML configuration loading through MultisourceConfigurationLoaderOptions.
test/patches/patch_base.py
test/patches/patch_builtin_open.py
test/test_application_properties_toml_loader.py
Improve test clarity and extend coverage around TOML loader behavior.
  • Insert "# Assert" comments before assertion blocks in multiple TOML loader tests to make test structure clearer.
  • Add new TOML tests for quoted separator keys, invalid unquoted separator keys with slashes, unsupported list values for such keys, and multisource loader integration with pyproject.toml and explicit configuration files.
test/test_application_properties_toml_loader.py
Add a no-upgrades flag to the clean script and wire it into the project dependency check step.
  • Introduce NO_UPGRADE_MODE variable in command-line parsing and default initialization.
  • Add -nu/--no-upgrades option handling to set NO_UPGRADE_MODE.
  • Short-circuit look_for_upgrades when NO_UPGRADE_MODE is set, logging that upgrade checks are being skipped.
clean.sh
Document the new behavior and bump the project version.
  • Add changelog entries for versions 0.9.1 through earlier historical versions, including notes about TOML parsing fixes and pyproject config behavior.
  • Update version from 0.9.0 to 0.9.1 to reflect the new release.
newdocs/src/changelog.md
application_properties/version.py
publish/coverage.json
publish/pylint_suppression.json
publish/test-results.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • In ApplicationProperties.__scan_map, the logic that always wraps keys containing the separator in quotes might be surprising when allow_periods_in_keys is False (the earlier validation already rejects such keys); consider only quoting keys when allow_periods_in_keys is True or refactoring to keep the behavior clearer.
  • The validation error message in __scan_map still states that keys cannot contain a '.' character, even though TOML loading now allows quoted periods via allow_periods_in_keys; it would be clearer to align the message with the new behavior or make it context-specific.
  • In PatchBuiltinOpen.register_exception_for_file, exception_map only stores a single (mode, exception) tuple per file, so registering multiple exceptions for the same path will silently overwrite previous entries; if multiple mode/exception pairs per file are needed, consider using a nested map keyed by mode.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `ApplicationProperties.__scan_map`, the logic that always wraps keys containing the separator in quotes might be surprising when `allow_periods_in_keys` is False (the earlier validation already rejects such keys); consider only quoting keys when `allow_periods_in_keys` is True or refactoring to keep the behavior clearer.
- The validation error message in `__scan_map` still states that keys cannot contain a '.' character, even though TOML loading now allows quoted periods via `allow_periods_in_keys`; it would be clearer to align the message with the new behavior or make it context-specific.
- In `PatchBuiltinOpen.register_exception_for_file`, `exception_map` only stores a single `(mode, exception)` tuple per file, so registering multiple exceptions for the same path will silently overwrite previous entries; if multiple mode/exception pairs per file are needed, consider using a nested map keyed by mode.

## Individual Comments

### Comment 1
<location> `test/patches/patch_builtin_open.py:58-1` </location>
<code_context>
+            f"register_text_content[{exact_file_name}]=[{file_contents}]]"
+        )
+
+    def register_binary_content_for_file(
+        self, exact_file_name: str, file_contents: bytes
+    ) -> None:
+        """
+        Register text content to return when the specified file is opened for reading as
+        a text file.
</code_context>

<issue_to_address>
**nitpick:** Docstring for `register_binary_content_for_file` is misleading (mentions text instead of binary).

Since this helper accepts `bytes` and is used with "rb" mode, the docstring should describe registering binary content for binary reads, not text. Please update the wording accordingly to avoid confusion and potential misuse.
</issue_to_address>

### Comment 2
<location> `newdocs/src/changelog.md:90-91` </location>
<code_context>
+    - added ability to translate from string to other forms
+    - controlled by flag, and only occurs on pure strings, not any strings with
+      any typing
+        - i.e. only manual set and "config" files are untyped, so only those are
+          affected
+- [Issue 145](https://github.com/jackdewinter/application_properties/issues/145)
</code_context>

<issue_to_address>
**issue (typo):** Replace `manual set` with `manually set` for correct grammar.

Update the phrase to: `only manually set and "config" files are untyped` for correct grammar and clarity.

```suggestion
        - i.e. only manually set and "config" files are untyped, so only those are
          affected
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@@ -0,0 +1,157 @@
"""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: Docstring for register_binary_content_for_file is misleading (mentions text instead of binary).

Since this helper accepts bytes and is used with "rb" mode, the docstring should describe registering binary content for binary reads, not text. Please update the wording accordingly to avoid confusion and potential misuse.

Comment on lines +90 to +91
- i.e. only manual set and "config" files are untyped, so only those are
affected
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (typo): Replace manual set with manually set for correct grammar.

Update the phrase to: only manually set and "config" files are untyped for correct grammar and clarity.

Suggested change
- i.e. only manual set and "config" files are untyped, so only those are
affected
- i.e. only manually set and "config" files are untyped, so only those are
affected

@jackdewinter jackdewinter deleted the issue-192 branch January 24, 2026 17:24
@jackdewinter jackdewinter restored the issue-192 branch January 24, 2026 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants