diff --git a/README.md b/README.md index 6ccf220..62df85c 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,9 @@ For the full documentation, see the Python docstrings. ## Changelog +### Version 0.2.0 +- support for specifying mutability when parsing a configuration + ### Version 0.1.1 - backward compatibility for Python < 3.12: in Python < 3.12, f-string expression parts could not contain backslashes. The code contained an f-string with backslahes in the expression part. As an alternative to the f-string, normal strings are concatenated now. diff --git a/pyproject.toml b/pyproject.toml index 341633c..7b3ad2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,6 +4,6 @@ build-backend = "setuptools.build_meta" [project] name = "jcloud-config-parser" -version = "0.1.1" +version = "0.2.0" description = "A configuration file parser." license = "Apache-2.0" \ No newline at end of file diff --git a/src/jcloud_config_parser/_configuration.py b/src/jcloud_config_parser/_configuration.py index d62982b..9fd5fba 100644 --- a/src/jcloud_config_parser/_configuration.py +++ b/src/jcloud_config_parser/_configuration.py @@ -40,7 +40,6 @@ class Configuration: raise TypeError('configuration is immutable') return wrapper - def _set(self, name: str, value: str) -> None: @self._mutate def _set(name: str, value: str) -> None: diff --git a/src/jcloud_config_parser/ini.py b/src/jcloud_config_parser/ini.py index 6fecfa7..e6bad64 100644 --- a/src/jcloud_config_parser/ini.py +++ b/src/jcloud_config_parser/ini.py @@ -14,7 +14,7 @@ from __future__ import annotations import typing -from ._configuration import Configuration +from ._configuration import Configuration, set_mutability from .parse.ini import _COMMENT_PREFIXES, _QUOTATION_MARKS, parse_ini from .serialize.ini import serialize as serialize_ini @@ -28,7 +28,7 @@ class INIConfiguration(Configuration): return iter({k: dict(v) if isinstance(v, INIConfigurationSection) else v for k, v in self._config.items()}.items()) @classmethod - def from_string(cls, data: str | bytes, comment_prefixes: typing.Collection[str] = _COMMENT_PREFIXES, quotation_marks: typing.Collection[str] = _QUOTATION_MARKS, ignore_errors: bool = False, default: INIConfiguration = None): + def from_string(cls, data: str | bytes, comment_prefixes: typing.Collection[str] = _COMMENT_PREFIXES, quotation_marks: typing.Collection[str] = _QUOTATION_MARKS, ignore_errors: bool = False, default: INIConfiguration = None, mutable: bool = True): ''' Parses INI configuration from a string and returns an instance of INIConfiguration. @@ -44,6 +44,8 @@ class INIConfiguration(Configuration): :type ignore_errors: bool :param default: The default configuration. :type default: INIConfiguration + :param mutable: The mutability of the configuration + :type mutable: bool :raises INISyntaxError: If there is a syntax error in the INI configuration and ``ignore_errors`` is ``False``. @@ -68,6 +70,8 @@ class INIConfiguration(Configuration): if propk not in dict(configuration[section]).keys(): configuration[section][propk] = propv + set_mutability(configuration, mutable) + return configuration def to_string(self, separator: str = '='): diff --git a/src/jcloud_config_parser/json.py b/src/jcloud_config_parser/json.py index e007209..99b596a 100644 --- a/src/jcloud_config_parser/json.py +++ b/src/jcloud_config_parser/json.py @@ -39,7 +39,7 @@ class JSONConfiguration(Configuration): return iter({k: v.value for k, v in self._config.items()}.items()) @classmethod - def from_string(cls, data: str | bytes, ignore_errors: bool = False): + def from_string(cls, data: str | bytes, ignore_errors: bool = False, mutable: bool = True): ''' Parses JSON configuration from a string and returns an instance of JSONConfiguration. @@ -47,6 +47,8 @@ class JSONConfiguration(Configuration): :type data: str :param ignore_errors: If True, errors will be ignored. :type ignore_errors: bool + :param mutable: The mutability of the configuration + :type mutable: bool :raises JSONValueSyntaxError: If a value is invalid and ``ignore_errors`` is ``False``. :raises JSONObjectSyntaxError: If an object is invalid and ``ignore_errors`` is ``False``. @@ -63,11 +65,11 @@ class JSONConfiguration(Configuration): try: data = parse_type(data).parse(data) if isinstance(data, JSONObject): - return cls({k: _configuration(v) for k, v in data.value.items()}) + return cls({k: _configuration(v) for k, v in data.value.items()}, mutable = mutable) elif not ignore_errors: raise JSONTypeError(f'expected object, got {data._type}. Use jcloud_config_parser.parse.json.parse_json to parse JSONs.') except: if ignore_errors: - return cls() + return cls(mutable = mutable) else: raise \ No newline at end of file diff --git a/tests/ini/test_ini.py b/tests/ini/test_ini.py index 5e969d8..2aead6d 100644 --- a/tests/ini/test_ini.py +++ b/tests/ini/test_ini.py @@ -94,4 +94,26 @@ def test_mutability(): del config.key assert False, 'Expected TypeError' except TypeError: - pass \ No newline at end of file + pass + + configuration = '[section]\nkey=value' + config = INIConfiguration.from_string(configuration) + config.key1 = 'value1' + + set_mutability(config, False) + try: + config.key2 = 'value2' + assert False, 'Expected TypeError' + except TypeError: + pass + + config = INIConfiguration.from_string(configuration, mutable = False) + + try: + config.key1 = 'value1' + assert False, 'Expected TypeError' + except TypeError: + pass + + set_mutability(config, True) + config.key2 = 'value2' \ No newline at end of file diff --git a/tests/json/test_json.py b/tests/json/test_json.py index 11d1e98..7327472 100644 --- a/tests/json/test_json.py +++ b/tests/json/test_json.py @@ -15,6 +15,7 @@ from src.jcloud_config_parser.json import JSONConfiguration from src.jcloud_config_parser.exceptions import JSONObjectSyntaxError, JSONValueSyntaxError, JSONStringSyntaxError, JSONArraySyntaxError, EscapeSequenceSyntaxError from src.jcloud_config_parser import set_mutability +from src.jcloud_config_parser.parse.json import JSONString def test_json_configuration(): # Test valid JSON configuration parsing @@ -224,7 +225,7 @@ def test_json_configuration(): pass def test_mutability(): - config = JSONConfiguration(mutable=False) + config = JSONConfiguration(mutable = False) try: config.key = 'value' assert False, 'Expected TypeError' @@ -243,4 +244,27 @@ def test_mutability(): del config.key assert False, 'Expected TypeError' except TypeError: - pass \ No newline at end of file + pass + + configuration = '{"key": "value"}' + config = JSONConfiguration.from_string(configuration) + config.key1 = JSONString("value1") + + set_mutability(config, False) + + try: + config.key2 = JSONString('value2') + assert False, 'Expected TypeError' + except TypeError: + pass + + config = JSONConfiguration.from_string(configuration, mutable = False) + + try: + config.key1 = JSONString('value1') + assert False, 'Expected TypeError' + except TypeError: + pass + + set_mutability(config, True) + config.key2 = JSONString('value2') \ No newline at end of file