Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
564bffb
https://github.com/jackdewinter/application_properties/issues/192 - M…
jackdewinter Jul 15, 2023
e668e0e
https://github.com/jackdewinter/application_properties/issues/192 - f…
jackdewinter Jul 15, 2023
0c213c6
https://github.com/jackdewinter/application_properties/issues/195: Ad…
jackdewinter Jul 16, 2023
6782444
updated changelog
jackdewinter Jul 16, 2023
8b62ff8
https://github.com/jackdewinter/application_properties/issues/202 - F…
jackdewinter Jul 22, 2023
0d1ddeb
https://github.com/jackdewinter/application_properties/issues/216
jackdewinter Jan 28, 2024
0e2254c
https://github.com/jackdewinter/application_properties/issues/216
jackdewinter Jan 28, 2024
bc3639c
Merge branch 'main' of https://github.com/jackdewinter/application_pr…
jackdewinter Jan 28, 2024
0af9ff2
package updates
jackdewinter Jan 28, 2024
32604e8
Merge branch 'main' of https://github.com/jackdewinter/application_pr…
jackdewinter Jan 28, 2024
980409a
updating packages
jackdewinter Jan 28, 2024
d73488e
upgrading packages
jackdewinter Jan 28, 2024
7fafd0e
upgrading
jackdewinter Jul 14, 2024
cf6ed42
Merge branch 'main' into issue-192
jackdewinter Jul 14, 2024
b2c9b90
test
jackdewinter Jul 14, 2024
242e4d9
Merge branch 'issue-192' of https://github.com/jackdewinter/applicati…
jackdewinter Jul 14, 2024
2b0e3b7
test
jackdewinter Jul 14, 2024
f140180
test
jackdewinter Jul 14, 2024
1b8d1fa
upgrading
jackdewinter Jul 14, 2024
e1a7af2
upgrading
jackdewinter Jul 14, 2024
adc9aa9
pylint
jackdewinter Jul 14, 2024
cd6b3dd
codeql
jackdewinter Jul 14, 2024
c8489bb
upgrading
jackdewinter Jul 14, 2024
60b4106
Merge branch 'main' of https://github.com/jackdewinter/application_pr…
jackdewinter Jul 14, 2024
0166758
upgrade
jackdewinter Jul 14, 2024
4ed56b3
updates
jackdewinter Jul 14, 2024
b28bba2
Merge branch 'main' into issue-192
jackdewinter Jul 14, 2024
f90a333
upgrade
jackdewinter Jul 14, 2024
5461121
Merge branch 'issue-192' of https://github.com/jackdewinter/applicati…
jackdewinter Jul 14, 2024
993a892
upgrading
jackdewinter May 22, 2025
1bec254
Merge branch 'main' into issue-192
jackdewinter May 22, 2025
7f46dd0
https://github.com/jackdewinter/application_properties/issues/271
jackdewinter Jun 15, 2025
f6d94bd
Merge branch 'issue-192' of https://github.com/jackdewinter/applicati…
jackdewinter Jun 15, 2025
7707d95
Merge branch 'main' of https://github.com/jackdewinter/application_pr…
jackdewinter Jun 15, 2025
73e4a20
https://github.com/jackdewinter/application_properties/issues/271
jackdewinter Jun 15, 2025
1c71d1f
https://github.com/jackdewinter/application_properties/issues/271
jackdewinter Jun 15, 2025
28a4936
upgrade build tools
jackdewinter Jun 16, 2025
b1bd6af
Merge branch 'main' of https://github.com/jackdewinter/application_pr…
jackdewinter Jun 16, 2025
b4fa87c
https://github.com/jackdewinter/application_properties/issues/148
jackdewinter Jun 18, 2025
a316f56
https://github.com/jackdewinter/application_properties/issues/148
jackdewinter Jun 18, 2025
0ce639e
https://github.com/jackdewinter/application_properties/issues/148
jackdewinter Jun 30, 2025
7e9cec6
Merge branch 'main' into issue-192
jackdewinter Jun 30, 2025
214ac90
https://github.com/jackdewinter/application_properties/issues/148
jackdewinter Jun 30, 2025
463d2cb
Merge branch 'issue-192' of https://github.com/jackdewinter/applicati…
jackdewinter Jun 30, 2025
5e6a957
https://github.com/jackdewinter/application_properties/issues/148
jackdewinter Jul 1, 2025
cf764c6
https://github.com/jackdewinter/application_properties/issues/148
jackdewinter Jul 1, 2025
2b4ccb9
xxx
jackdewinter Jul 1, 2025
cabd725
https://github.com/jackdewinter/application_properties/issues/148
jackdewinter Jul 1, 2025
662cfb3
Merge branch 'main' into issue-192
jackdewinter Jul 1, 2025
44fc3e3
upgrading dependencies
jackdewinter Dec 21, 2025
d4b6dac
Merge branch 'issue-192' of https://github.com/jackdewinter/applicati…
jackdewinter Dec 21, 2025
6304921
upgrading dependencies
jackdewinter Dec 21, 2025
0f10a8d
upgrading dependencies
jackdewinter Dec 21, 2025
17cdb3e
Merge branch 'main' into issue-192
jackdewinter Dec 21, 2025
8df30a6
upgrading dependencies
jackdewinter Dec 21, 2025
60f2a13
Merge branch 'issue-192' of https://github.com/jackdewinter/applicati…
jackdewinter Dec 21, 2025
8a0f9ed
upgrading dependencies
jackdewinter Dec 21, 2025
b75f087
Merge branch 'main' into issue-192
jackdewinter Dec 21, 2025
a4622ee
upgrading dependencies
jackdewinter Dec 21, 2025
32852c3
Merge branch 'issue-192' of https://github.com/jackdewinter/applicati…
jackdewinter Dec 21, 2025
04703ab
update cookieslicer config
jackdewinter Jan 12, 2026
b0e62dd
Merge branch 'main' into issue-192
jackdewinter Jan 12, 2026
ab40c6f
https://github.com/jackdewinter/application_properties/issues/269
jackdewinter Jan 24, 2026
fbf76d5
Merge branch 'issue-192' of https://github.com/jackdewinter/applicati…
jackdewinter Jan 24, 2026
eb55a48
Merge branch 'main' into issue-192
jackdewinter Jan 24, 2026
8ef2100
version 0.9.1
jackdewinter Jan 24, 2026
27c69ad
Merge branch 'issue-192' of https://github.com/jackdewinter/applicati…
jackdewinter Jan 24, 2026
f720261
test
jackdewinter Jan 24, 2026
f9ae2f6
test
jackdewinter Jan 24, 2026
3e57188
test
jackdewinter Jan 24, 2026
4bb2224
test
jackdewinter Jan 24, 2026
0ba9197
test
jackdewinter Jan 24, 2026
d7a1aa9
test
jackdewinter Jan 24, 2026
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
28 changes: 23 additions & 5 deletions application_properties/application_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ def clear(self) -> None:
self.__flat_property_map.clear()

def load_from_dict(
self, config_map: Dict[Any, Any], clear_map: bool = True
self,
config_map: Dict[Any, Any],
clear_map: bool = True,
allow_periods_in_keys: bool = False,
) -> None:
"""
Load the properties from a provided dictionary.
Expand All @@ -106,7 +109,7 @@ def load_from_dict(
LOGGER.debug("Loading from dictionary: {%s}", str(config_map))
if clear_map:
self.clear()
self.__scan_map(config_map, "")
self.__scan_map(config_map, "", allow_periods_in_keys)

@staticmethod
def verify_full_part_form(property_key: str) -> str:
Expand Down Expand Up @@ -444,7 +447,13 @@ def property_names_under(self, key_name: str) -> List[str]:
if next_key_name.startswith(key_name)
]

def __scan_map(self, config_map: Dict[Any, Any], current_prefix: str) -> None:
# pylint: disable=too-many-boolean-expressions
def __scan_map(
self,
config_map: Dict[Any, Any],
current_prefix: str,
allow_periods_in_keys: bool,
) -> None:
for next_key, next_value in config_map.items():
if not isinstance(next_key, str):
raise ValueError(
Expand All @@ -455,21 +464,30 @@ def __scan_map(self, config_map: Dict[Any, Any], current_prefix: str) -> None:
or "\t" in next_key
or "\n" in next_key
or ApplicationProperties.__assignment_operator in next_key
or ApplicationProperties.__separator in next_key
or (
ApplicationProperties.__separator in next_key
and not allow_periods_in_keys
)
):
raise ValueError(
"Key strings cannot contain a whitespace character, "
+ f"a '{ApplicationProperties.__assignment_operator}' character, or "
+ f"a '{ApplicationProperties.__separator}' character."
)
if ApplicationProperties.__separator in next_key:
next_key = f"'{next_key}'"

if isinstance(next_value, dict):
self.__scan_map(
next_value, f"{current_prefix}{next_key}{self.__separator}"
next_value,
f"{current_prefix}{next_key}{self.__separator}",
allow_periods_in_keys,
)
else:
new_key = f"{current_prefix}{next_key}".lower()
self.__flat_property_map[new_key] = copy.deepcopy(next_value)
LOGGER.debug(
"Adding configuration '%s' : {%s}", new_key, str(next_value)
)

# pylint: enable=too-many-boolean-expressions
4 changes: 3 additions & 1 deletion application_properties/application_properties_toml_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ def load_and_set(
)
if configuration_map:
properties_object.load_from_dict(
configuration_map, clear_map=clear_property_map
configuration_map,
clear_map=clear_property_map,
allow_periods_in_keys=True,
)
did_apply_map = True
return did_apply_map and not did_have_one_error, did_have_one_error
Expand Down
11 changes: 10 additions & 1 deletion application_properties/multisource_configuration_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class MultisourceConfigurationLoaderOptions:
"""
Allow parsing of JSON files using the JSON5 parser. (Default = False)
"""
section_header_if_toml: Optional[str] = None
"""Optional section header to use when loading TOML configuration files.
"""


# pylint: disable=too-few-public-methods
Expand Down Expand Up @@ -137,6 +140,7 @@ def __load_as_yaml(
def __load_as_toml(
self,
file_name: str,
options: MultisourceConfigurationLoaderOptions,
application_properties: ApplicationProperties,
handle_error_fn: Callable[[str, Optional[Exception]], None],
) -> Tuple[bool, bool]:
Expand All @@ -151,6 +155,7 @@ def __load_as_toml(
) = ApplicationPropertiesTomlLoader.load_and_set(
application_properties,
file_name,
section_header=options.section_header_if_toml,
handle_error_fn=handle_error_fn,
clear_property_map=False,
check_for_file_presence=True,
Expand Down Expand Up @@ -179,7 +184,9 @@ def _load_config(
file_name, application_properties, handle_error_fn
)
assert config_file_type == ConfigurationFileType.TOML
return self.__load_as_toml(file_name, application_properties, handle_error_fn)
return self.__load_as_toml(
file_name, options, application_properties, handle_error_fn
)
# return False, False

# pylint: enable=too-many-arguments
Expand Down Expand Up @@ -604,6 +611,8 @@ def add_specified_configuration_file(
is made to load the file.
config_file_type: Type of configuration file to load. For auto-detecting
the file type, see the notes above.
section_header_if_toml: Optional section header to use when loading
TOML configuration files.

Returns:
Instance of `self` for chaining `add_*` functions and the `process` function
Expand Down
2 changes: 1 addition & 1 deletion application_properties/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Library version information.
"""

__version__ = "0.9.0"
__version__ = "0.9.1"
__project_name__ = "application_properties"
__description__ = (
"A simple, easy to use, unified manner of accessing program properties."
Expand Down
11 changes: 11 additions & 0 deletions clean.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ show_usage() {
echo " -m,--mypy-only Only run mypy checks and exit."
echo " -np,--no-publish Do not publish project summaries if successful."
echo " -ns,--no-sourcery Do not run any sourcery checks."
echo " -nu,--no-upgrades Do not run checks for upgrades."
echo " -s,--sourcery-only Only run sourcery checks and exit."
echo " --perf Collect standard performance metrics."
echo " --perf-only Only collect standard performance metrics."
Expand All @@ -105,6 +106,7 @@ parse_command_line() {
MYPY_ONLY_MODE=0
SOURCERY_ONLY_MODE=0
NO_SOURCERY_MODE=0
NO_UPGRADE_MODE=0
FORCE_RESET_MODE=0
RESET_PYTHON_VERSION=
PARAMS=()
Expand All @@ -131,6 +133,10 @@ parse_command_line() {
NO_SOURCERY_MODE=1
shift
;;
-nu | --no-upgrades)
NO_UPGRADE_MODE=1
shift
;;
-s | --sourcery-only)
SOURCERY_ONLY_MODE=1
shift
Expand Down Expand Up @@ -404,6 +410,11 @@ analyze_pylint_suppressions() {

look_for_upgrades() {

if [[ ${NO_UPGRADE_MODE} -ne 0 ]]; then
verbose_echo "{Skipping check for Python package upgrades by request.}"
return
fi

verbose_echo "{Looking for Python package upgrades in Pre-Commit and Pipenv.}"
if ! ./check_project_dependencies.sh; then
complete_process 1 "{One or more project dependencies can be updated. Please run './check_project_dependencies.sh --upgrade' to update them.}"
Expand Down
17 changes: 17 additions & 0 deletions newdocs/src/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,20 @@
### Fixed

- None

## Version 0.9.1 - Date: 2026-01-24

<!-- pyml disable-next-line no-duplicate-heading-->
### Fixed

- [Improper parsing of TOML](https://github.com/jackdewinter/application_properties/issues/269)
- The `.` character is considered a separator character for keys, with the code
checking to prevent that character from being used within a key. As TOML
will already break the key on that character, a bypass was added to allow the
TOML keys to include a `.` character IF it is in quotes.
- [Config flag fails to apply pyproject TOML](https://github.com/jackdewinter/application_properties/issues/318)
- If the `pyproject.toml` file was loaded implicitly, the file was loading
and processing the TOML file to only look at the "section header" that was
specified. If passed using `--config`, it was not. Added the `section_header_if_toml`
field to the `MultisourceConfigurationLoaderOptions` class to allow an optional
section header to be passed in when loading an "untyped" configuration file.
8 changes: 4 additions & 4 deletions publish/coverage.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"projectName": "application_properties",
"reportSource": "Unknown",
"branchLevel": {
"totalMeasured": 178,
"totalCovered": 178
"totalMeasured": 180,
"totalCovered": 180
},
"lineLevel": {
"totalMeasured": 665,
"totalCovered": 665
"totalMeasured": 669,
"totalCovered": 669
}
}

4 changes: 3 additions & 1 deletion publish/pylint_suppression.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"application_properties/__init__.py": {},
"application_properties/application_properties.py": {
"too-many-arguments": 4,
"broad-exception-caught": 1
"broad-exception-caught": 1,
"too-many-boolean-expressions": 1
},
"application_properties/application_properties_config_loader.py": {
"too-few-public-methods": 1,
Expand Down Expand Up @@ -39,6 +40,7 @@
"disables-by-name": {
"too-many-arguments": 14,
"broad-exception-caught": 1,
"too-many-boolean-expressions": 1,
"too-few-public-methods": 10,
"no-member": 2
}
Expand Down
2 changes: 1 addition & 1 deletion publish/test-results.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
},
{
"name": "test.test_application_properties_toml_loader",
"totalTests": 17,
"totalTests": 22,
"failedTests": 0,
"errorTests": 0,
"skippedTests": 0,
Expand Down
55 changes: 55 additions & 0 deletions test/patches/patch_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""
Module to provide a base class for any patch classes.
"""

import unittest
from typing import Any, List, Optional, Union
from unittest.mock import AsyncMock, MagicMock, _patch


class PatchBase:
"""
Class to provide a base class for any patch classes.
"""

def __init__(self, function_name_to_patch: str) -> None:
self.__mock_patcher: Optional[_patch[Union[MagicMock, AsyncMock]]] = None
self.__patched_function: Optional[MagicMock] = None
self.__function_name_to_patch = function_name_to_patch
self.__action_comments: List[str] = []

def _add_action_comment(self, comment_to_add: str) -> None:
# sourcery skip: remove-unnecessary-cast
self.__action_comments.append(str(comment_to_add))

def _add_side_effect(self, callable_function: Any) -> None:
assert self.__patched_function is not None
self.__patched_function.side_effect = callable_function

def start(self, log_action: bool = True) -> None:
"""
Start the capturing of calls and apply any needed mocking.
"""
if log_action:
self._add_action_comment("starting")
self.__mock_patcher = unittest.mock.patch(self.__function_name_to_patch)
assert self.__mock_patcher is not None
self.__patched_function = self.__mock_patcher.start()

def stop(
self, log_action: bool = True, print_action_comments: bool = False
) -> None:
"""
Stop the capturing of calls and any needed mocking.
"""
assert self.__mock_patcher is not None
if log_action:
self._add_action_comment("stopping")

self.__mock_patcher.stop()
self.__mock_patcher = None
self.__patched_function = None
if log_action:
self._add_action_comment("stopped")
if print_action_comments:
print("\n".join(self.__action_comments))
Loading
Loading