geändert: README.md
geändert: pyproject.toml geändert: src/config_parser/__init__.py gelöscht: src/config_parser/__main__.py geändert: src/config_parser/ini.py neue Datei: src/config_parser/parse/__init__.py geändert: src/config_parser/parse/ini.py geändert: src/config_parser/parse/json.py neue Datei: src/config_parser/serialize/__init__.py neue Datei: src/config_parser/serialize/ini.py neue Datei: src/config_parser/serialize/json.py neue Datei: tests/json/test_serializer.py
This commit is contained in:
@@ -74,4 +74,16 @@ If the configuration file content is:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
the result will be `{'section1': {'key1': 'value1', 'key2': 'value2', 'number': 42, 'number2': 3.14, 'number3': -1, 'boolean': True, 'boolean2': False, 'null': None}, 'section2': {'hello': 'world'}, 'section3': {'key': 'value'}}`
|
the result will be `{'section1': {'key1': 'value1', 'key2': 'value2', 'number': 42, 'number2': 3.14, 'number3': -1, 'boolean': True, 'boolean2': False, 'null': None}, 'section2': {'hello': 'world'}, 'section3': {'key': 'value'}}`
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
### Version 1.1.0
|
||||||
|
- JSON and INI serializer
|
||||||
|
|
||||||
|
### Version 1.0.0
|
||||||
|
- JSON parser
|
||||||
|
- better API
|
||||||
|
|
||||||
|
### Version 0.1.0
|
||||||
|
- First release
|
||||||
|
- INI parser
|
||||||
+1
-1
@@ -4,5 +4,5 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "config-parser"
|
name = "config-parser"
|
||||||
version = "1.0.0"
|
version = "1.1.0"
|
||||||
description = "A configuration file parser."
|
description = "A configuration file parser."
|
||||||
@@ -2,13 +2,26 @@
|
|||||||
A library for parsing configuration files in various formats.
|
A library for parsing configuration files in various formats.
|
||||||
|
|
||||||
Modules:
|
Modules:
|
||||||
- configuration: Base classes.
|
- _configuration: Base classes.
|
||||||
- ini: INI file parser and serializer.
|
- ini: INI configuration.
|
||||||
- exceptions: Custom exceptions for configuration parsing.
|
- json: JSON configuration.
|
||||||
|
- exceptions: Exceptions for configuration parsing.
|
||||||
|
- parse: A package including the parsers.
|
||||||
|
- serialize: A package including the serializers.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from ._configuration import Configuration
|
from ._configuration import Configuration
|
||||||
|
# from . import exceptions
|
||||||
|
# from . import json
|
||||||
|
# from . import ini
|
||||||
|
# from . import parse
|
||||||
|
# from . import serialize
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'Configuration'
|
'Configuration',
|
||||||
|
'exceptions',
|
||||||
|
'json',
|
||||||
|
'ini',
|
||||||
|
'parse',
|
||||||
|
'serialize'
|
||||||
]
|
]
|
||||||
+10
-14
@@ -1,16 +1,17 @@
|
|||||||
import typing
|
import typing
|
||||||
from ._configuration import Configuration
|
from ._configuration import Configuration
|
||||||
from .parse.ini import COMMENT_PREFIXES, QUOTATION_MARKS, parse_ini
|
from .parse.ini import _COMMENT_PREFIXES, _QUOTATION_MARKS, parse_ini
|
||||||
|
from .serialize.ini import serialize as serialize_ini
|
||||||
|
|
||||||
class INIConfiguration(Configuration):
|
class INIConfiguration(Configuration):
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter({k: dict(v) if isinstance(v, INIConfigurationGroup) else v for k, v in self._config.items()}.items())
|
return iter({k: dict(v) if isinstance(v, INIConfigurationGroup) else v for k, v in self._config.items()}.items())
|
||||||
|
|
||||||
@classmethod
|
@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):
|
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):
|
||||||
'''
|
'''
|
||||||
Parses INI configuration from a string and returns an instance of INIConfiguration.
|
Parses INI configuration from a string and returns an instance of INIConfiguration.
|
||||||
|
|
||||||
:param cls: The class method is called on.
|
:param cls: The class method is called on.
|
||||||
:type cls: typing.Type[INIConfiguration]
|
:type cls: typing.Type[INIConfiguration]
|
||||||
:param data: The INI configuration data to parse.
|
:param data: The INI configuration data to parse.
|
||||||
@@ -42,26 +43,21 @@ class INIConfiguration(Configuration):
|
|||||||
def to_string(self, separator: str = '='):
|
def to_string(self, separator: str = '='):
|
||||||
'''
|
'''
|
||||||
Serializes the INIConfiguration instance to an INI formatted string.
|
Serializes the INIConfiguration instance to an INI formatted string.
|
||||||
|
|
||||||
:param separator: The separator to use between keys and values in the output string.
|
:param separator: The separator to use between keys and values in the output string.
|
||||||
:type separator: str
|
:type separator: str
|
||||||
|
|
||||||
:return: An INI formatted string representing the INIConfiguration instance.
|
:return: An INI formatted string representing the INIConfiguration instance.
|
||||||
:rtype: str
|
:rtype: str
|
||||||
'''
|
'''
|
||||||
result = ''
|
|
||||||
for key, value in self._config.items():
|
return serialize_ini(self._config, separator)
|
||||||
if isinstance(value, INIConfigurationGroup):
|
|
||||||
result += value.to_string(separator=separator)
|
|
||||||
else:
|
|
||||||
result += f'{key}{separator}{value}\n'
|
|
||||||
return result.strip()
|
|
||||||
|
|
||||||
class INIConfigurationGroup(INIConfiguration):
|
class INIConfigurationGroup(INIConfiguration):
|
||||||
def __init__(self, name: str):
|
def __init__(self, name: str):
|
||||||
'''
|
'''
|
||||||
A class representing a group in an INI configuration.
|
A class representing a group in an INI configuration.
|
||||||
|
|
||||||
:param name: The name of the group.
|
:param name: The name of the group.
|
||||||
:type name: str
|
:type name: str
|
||||||
'''
|
'''
|
||||||
@@ -71,11 +67,11 @@ class INIConfigurationGroup(INIConfiguration):
|
|||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
def to_string(self, separator: str = '='):
|
def to_string(self, separator: str = '='):
|
||||||
'''
|
'''
|
||||||
Serializes the INIConfigurationGroup instance to an INI formatted string.
|
Serializes the INIConfigurationGroup instance to an INI formatted string.
|
||||||
|
|
||||||
:param separator: The separator to use between keys and values in the output string.
|
:param separator: The separator to use between keys and values in the output string.
|
||||||
:type separator: str
|
:type separator: str
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
'''
|
||||||
|
The parsers
|
||||||
|
|
||||||
|
Modules:
|
||||||
|
- ini: INI parser.
|
||||||
|
- json: JSON parser.
|
||||||
|
'''
|
||||||
|
|
||||||
|
# from . import json
|
||||||
|
# from . import ini
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'json',
|
||||||
|
'ini'
|
||||||
|
]
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import typing
|
import typing
|
||||||
from ..exceptions import INIInvalidGroupHeader, INIInvalidKeyValueLine, INISyntaxError
|
from ..exceptions import INIInvalidGroupHeader, INIInvalidKeyValueLine, INISyntaxError
|
||||||
|
|
||||||
QUOTATION_MARKS = ['"', "'"]
|
_QUOTATION_MARKS = ['"', "'"]
|
||||||
COMMENT_PREFIXES = ['#', ';']
|
_COMMENT_PREFIXES = ['#', ';']
|
||||||
KEY_VALUE_LINE = 0
|
_KEY_VALUE_LINE = 0
|
||||||
GROUP_HEADER_LINE = 1
|
_GROUP_HEADER_LINE = 1
|
||||||
COMMENT_LINE = 2
|
_COMMENT_LINE = 2
|
||||||
|
|
||||||
def reverse_dict(d: typing.Dict) -> typing.Dict:
|
def reverse_dict(d: typing.Dict) -> typing.Dict:
|
||||||
'''
|
'''
|
||||||
@@ -19,7 +19,7 @@ def reverse_dict(d: typing.Dict) -> typing.Dict:
|
|||||||
'''
|
'''
|
||||||
return {k: v for k, v in list(reversed(d.items()))}
|
return {k: v for k, v in list(reversed(d.items()))}
|
||||||
|
|
||||||
def parse_key_value_line(line: str, comment_prefixes: typing.Collection[str] = COMMENT_PREFIXES, quotation_marks: typing.Collection[str] = QUOTATION_MARKS, ignore_errors: bool = False) -> typing.Dict[str, str]:
|
def parse_key_value_line(line: str, comment_prefixes: typing.Collection[str] = _COMMENT_PREFIXES, quotation_marks: typing.Collection[str] = _QUOTATION_MARKS, ignore_errors: bool = False) -> typing.Dict[str, str]:
|
||||||
'''
|
'''
|
||||||
Parses a key-value line.
|
Parses a key-value line.
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ def parse_group_header(line: str, ignore_errors: bool = False) -> str:
|
|||||||
raise INIInvalidGroupHeader('the header is invalid')
|
raise INIInvalidGroupHeader('the header is invalid')
|
||||||
|
|
||||||
|
|
||||||
def parse_line_type(line: str, comment_prefixes: typing.Collection[str] = COMMENT_PREFIXES, ignore_errors: bool = False) -> int:
|
def parse_line_type(line: str, comment_prefixes: typing.Collection[str] = _COMMENT_PREFIXES, ignore_errors: bool = False) -> int:
|
||||||
'''
|
'''
|
||||||
Returns the type of a line.
|
Returns the type of a line.
|
||||||
|
|
||||||
@@ -111,14 +111,14 @@ def parse_line_type(line: str, comment_prefixes: typing.Collection[str] = COMMEN
|
|||||||
'''
|
'''
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if any(line.startswith(prefix) for prefix in comment_prefixes) or not line.strip():
|
if any(line.startswith(prefix) for prefix in comment_prefixes) or not line.strip():
|
||||||
return COMMENT_LINE
|
return _COMMENT_LINE
|
||||||
elif line.startswith('[') and line.endswith(']') and len(line) > 2:
|
elif line.startswith('[') and line.endswith(']') and len(line) > 2:
|
||||||
return GROUP_HEADER_LINE
|
return _GROUP_HEADER_LINE
|
||||||
elif '=' in line or ':' in line:
|
elif '=' in line or ':' in line:
|
||||||
return KEY_VALUE_LINE
|
return _KEY_VALUE_LINE
|
||||||
else:
|
else:
|
||||||
if ignore_errors:
|
if ignore_errors:
|
||||||
return COMMENT_LINE
|
return _COMMENT_LINE
|
||||||
raise INISyntaxError('the line is invalid')
|
raise INISyntaxError('the line is invalid')
|
||||||
|
|
||||||
def compress_conf(conf):
|
def compress_conf(conf):
|
||||||
@@ -126,7 +126,7 @@ def compress_conf(conf):
|
|||||||
conf = conf.replace('\n\n', '\n')
|
conf = conf.replace('\n\n', '\n')
|
||||||
return conf.strip()
|
return conf.strip()
|
||||||
|
|
||||||
def parse_ini(conf, comment_prefixes=COMMENT_PREFIXES, quotation_marks=QUOTATION_MARKS, ignore_errors: bool = False, global_group: bool = True) -> typing.Dict[str, typing.Dict[str, str]]:
|
def parse_ini(conf, comment_prefixes=_COMMENT_PREFIXES, quotation_marks=_QUOTATION_MARKS, ignore_errors: bool = False, global_group: bool = True) -> typing.Dict[str, typing.Dict[str, str]]:
|
||||||
'''Parses INI configuration from a string and returns a nested dictionary.
|
'''Parses INI configuration from a string and returns a nested dictionary.
|
||||||
|
|
||||||
:param conf: The INI configuration string to parse.
|
:param conf: The INI configuration string to parse.
|
||||||
@@ -147,11 +147,11 @@ def parse_ini(conf, comment_prefixes=COMMENT_PREFIXES, quotation_marks=QUOTATION
|
|||||||
current_group = {}
|
current_group = {}
|
||||||
for line in list(reversed(conf.split('\n'))):
|
for line in list(reversed(conf.split('\n'))):
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if parse_line_type(line, comment_prefixes=comment_prefixes, ignore_errors=ignore_errors) == COMMENT_LINE:
|
if parse_line_type(line, comment_prefixes=comment_prefixes, ignore_errors=ignore_errors) == _COMMENT_LINE:
|
||||||
continue
|
continue
|
||||||
if parse_line_type(line, comment_prefixes=comment_prefixes, ignore_errors=ignore_errors) == GROUP_HEADER_LINE:
|
if parse_line_type(line, comment_prefixes=comment_prefixes, ignore_errors=ignore_errors) == _GROUP_HEADER_LINE:
|
||||||
result[parse_group_header(line, ignore_errors=ignore_errors)] = reverse_dict(current_group)
|
result[parse_group_header(line, ignore_errors=ignore_errors)] = reverse_dict(current_group)
|
||||||
current_group = {}
|
current_group = {}
|
||||||
if parse_line_type(line, comment_prefixes=comment_prefixes, ignore_errors=ignore_errors) == KEY_VALUE_LINE:
|
if parse_line_type(line, comment_prefixes=comment_prefixes, ignore_errors=ignore_errors) == _KEY_VALUE_LINE:
|
||||||
current_group = current_group | parse_key_value_line(line, comment_prefixes=comment_prefixes, quotation_marks=quotation_marks, ignore_errors=ignore_errors)
|
current_group = current_group | parse_key_value_line(line, comment_prefixes=comment_prefixes, quotation_marks=quotation_marks, ignore_errors=ignore_errors)
|
||||||
return reverse_dict(result)
|
return reverse_dict(result)
|
||||||
@@ -2,7 +2,7 @@ from ..exceptions import EscapeSequenceSyntaxError, JSONValueSyntaxError, JSONNu
|
|||||||
import typing
|
import typing
|
||||||
import re
|
import re
|
||||||
|
|
||||||
JSON_ESCAPE_SEQUENCES = {
|
_JSON_ESCAPE_SEQUENCES = {
|
||||||
'"': '"',
|
'"': '"',
|
||||||
'\\': '\\',
|
'\\': '\\',
|
||||||
'/': '/',
|
'/': '/',
|
||||||
@@ -62,7 +62,7 @@ def parse_escape_sequences(string: str) -> bool:
|
|||||||
if c == 'u':
|
if c == 'u':
|
||||||
unicode_escape_sequence = ''
|
unicode_escape_sequence = ''
|
||||||
else:
|
else:
|
||||||
result += JSON_ESCAPE_SEQUENCES[c]
|
result += _JSON_ESCAPE_SEQUENCES[c]
|
||||||
|
|
||||||
if unicode_escape_sequence:
|
if unicode_escape_sequence:
|
||||||
raise EscapeSequenceSyntaxError(f'Invalid unicode escape sequence in JSON string: \\u{unicode_escape_sequence}')
|
raise EscapeSequenceSyntaxError(f'Invalid unicode escape sequence in JSON string: \\u{unicode_escape_sequence}')
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
'''
|
||||||
|
The serializers
|
||||||
|
|
||||||
|
Modules:
|
||||||
|
- ini: INI serializer.
|
||||||
|
- json: JSON serializer.
|
||||||
|
'''
|
||||||
|
|
||||||
|
# from . import json
|
||||||
|
# from . import ini
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'json',
|
||||||
|
'ini'
|
||||||
|
]
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
from ..exceptions import INISyntaxError
|
||||||
|
|
||||||
|
def serialize(data: dict, separator: str) -> str:
|
||||||
|
'''
|
||||||
|
Serializes the data to an INI formatted string.
|
||||||
|
|
||||||
|
:param data: The INI configuration.
|
||||||
|
:type data: dict
|
||||||
|
|
||||||
|
:param separator: The separator.
|
||||||
|
:type separator: str
|
||||||
|
|
||||||
|
:return: The INI formatted string.
|
||||||
|
:rtype: str
|
||||||
|
'''
|
||||||
|
|
||||||
|
result = ''
|
||||||
|
for key, value in data.items():
|
||||||
|
if hasattr(value, '_name'):
|
||||||
|
result += value.to_string(separator=separator)
|
||||||
|
else:
|
||||||
|
result += f'{key}{separator}{value}\n'
|
||||||
|
return result.strip()
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
import copy
|
||||||
|
from typing import *
|
||||||
|
import collections.abc
|
||||||
|
|
||||||
|
_ESCAPE_SEQUENCES = {
|
||||||
|
'\"': r'\"',
|
||||||
|
'\\': r'\\',
|
||||||
|
'\b': r'\b',
|
||||||
|
'\f': r'\f',
|
||||||
|
'\n': r'\n',
|
||||||
|
'\r': r'\r',
|
||||||
|
'\t': r'\t',
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Mapper:
|
||||||
|
def __init__(self, mapping = {}):
|
||||||
|
self._mapping = copy.deepcopy(mapping)
|
||||||
|
|
||||||
|
def _set(self, key, value):
|
||||||
|
self._mapping[key] = value
|
||||||
|
|
||||||
|
def set(self, key, value):
|
||||||
|
self._set(key, value)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def map(self, value):
|
||||||
|
return self._mapping[value]
|
||||||
|
|
||||||
|
_MAPPER = _Mapper().set(True, 'true').set(False, 'false').set(None, 'null')
|
||||||
|
|
||||||
|
def _serialize_object(data: dict, level: int, indent: int, indent_char: str, separators: Tuple[str, str]) -> str:
|
||||||
|
result = '{'
|
||||||
|
_count = 0
|
||||||
|
for _key, value in data.items():
|
||||||
|
_count += 1
|
||||||
|
key = _serialize(_key, 0, 0, '', separators)
|
||||||
|
value = _serialize(value, level + 1, indent, indent_char, separators)
|
||||||
|
if not isinstance(_key, str):
|
||||||
|
key = '"' + key + '"'
|
||||||
|
if indent:
|
||||||
|
result += '\n'
|
||||||
|
result += (level + 1) * indent * indent_char
|
||||||
|
result += key
|
||||||
|
result += separators[1]
|
||||||
|
result += value
|
||||||
|
if _count != len(data.keys()):
|
||||||
|
if indent:
|
||||||
|
result += separators[0].strip()
|
||||||
|
else:
|
||||||
|
result += separators[0]
|
||||||
|
if indent:
|
||||||
|
result += '\n'
|
||||||
|
result += level * indent * indent_char + '}'
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _serialize_array(data: Sequence, level: int, indent: int, indent_char: str, separators: Tuple[str, str]) -> str:
|
||||||
|
result = '['
|
||||||
|
_count = 0
|
||||||
|
for value in data:
|
||||||
|
_count += 1
|
||||||
|
value = _serialize(value, level + 1, indent, indent_char, separators)
|
||||||
|
if indent:
|
||||||
|
result += '\n'
|
||||||
|
result += (level + 1) * indent * indent_char
|
||||||
|
result += value
|
||||||
|
if _count != len(data):
|
||||||
|
if indent:
|
||||||
|
result += separators[0].strip()
|
||||||
|
else:
|
||||||
|
result += separators[0]
|
||||||
|
if indent:
|
||||||
|
result += '\n'
|
||||||
|
result += level * indent * indent_char + ']'
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _serialize_string(data: str) -> str:
|
||||||
|
_data = data
|
||||||
|
data = ''
|
||||||
|
for c in _data:
|
||||||
|
data += _ESCAPE_SEQUENCES.get(c, c)
|
||||||
|
return '"' + data + '"'
|
||||||
|
|
||||||
|
|
||||||
|
def _serialize_number(data: int | float) -> str:
|
||||||
|
return str(data)
|
||||||
|
|
||||||
|
def _serialize(data: dict | list | str | int | float | bool | None, level: int, indent: int, indent_char: str, separators: Tuple[str, str]) -> str:
|
||||||
|
if isinstance(data, (bool, type(None))):
|
||||||
|
return _MAPPER.map(data)
|
||||||
|
elif isinstance(data, dict):
|
||||||
|
return _serialize_object(data, level, indent, indent_char, separators)
|
||||||
|
elif isinstance(data, str):
|
||||||
|
return _serialize_string(data)
|
||||||
|
elif isinstance(data, (int, float)):
|
||||||
|
return _serialize_number(data)
|
||||||
|
elif isinstance(data, collections.abc.Sequence):
|
||||||
|
return _serialize_array(data, level, indent, indent_char, separators)
|
||||||
|
else:
|
||||||
|
raise TypeError(f'Object of type {type(data).__name__} is not JSON serializable')
|
||||||
|
|
||||||
|
def _char_whitespaces(whitespaces: Tuple[int | str, int | str] | int | str) -> Tuple[str, str]:
|
||||||
|
if isinstance(whitespaces, collections.abc.Sequence) and not isinstance(whitespaces, str):
|
||||||
|
if len(whitespaces) != 2:
|
||||||
|
raise ValueError(f'expected exactly two elements in whitespaces, got {len(whitespaces)}')
|
||||||
|
if isinstance(whitespaces, (str, int)):
|
||||||
|
whitespaces = whitespaces, whitespaces
|
||||||
|
if isinstance(whitespaces[0], int):
|
||||||
|
whitespaces = whitespaces[0] * ' ', whitespaces[1]
|
||||||
|
if isinstance(whitespaces[1], int):
|
||||||
|
whitespaces = whitespaces[0], whitespaces[1] * ' '
|
||||||
|
return whitespaces
|
||||||
|
|
||||||
|
def serialize(data: dict | list | str | int | float | bool | None, indent: int = 0, indent_char: str = ' ', separators: Tuple[str, str] = (', ', ': ')) -> str:
|
||||||
|
'''
|
||||||
|
Serializes the data to a JSON formatted string.
|
||||||
|
|
||||||
|
:param data: The data.
|
||||||
|
:type data: dict | list | str | int | float | bool | None
|
||||||
|
:param indent: The indentation
|
||||||
|
:type indent: int
|
||||||
|
:param indent_char: The character the indentation will be filled with
|
||||||
|
:type indent_char: str
|
||||||
|
:param separators: A tuple with the separators. The first string is the element separator and the second string is the key value separator.
|
||||||
|
:type separators: tuple
|
||||||
|
|
||||||
|
:raises TypeError: If the type is not JSON serializable.
|
||||||
|
|
||||||
|
:return: The JSON formatted string.
|
||||||
|
:rtype: str
|
||||||
|
'''
|
||||||
|
|
||||||
|
if len(separators) != 2:
|
||||||
|
raise ValueError(f'expected exactly two elements in separators, got {len(separators)}.')
|
||||||
|
|
||||||
|
return _serialize(data, 0, indent, indent_char, separators)
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
from src.config_parser.serialize.json import serialize as serialize_json
|
||||||
|
|
||||||
|
def test_serialize_json():
|
||||||
|
assert serialize_json(True) == 'true'
|
||||||
|
assert serialize_json(False) == 'false'
|
||||||
|
assert serialize_json(True, indent = 4) == 'true'
|
||||||
|
|
||||||
|
assert serialize_json(None) == 'null'
|
||||||
|
|
||||||
|
assert serialize_json({1: {None: True}}, indent = 4) == '''{
|
||||||
|
"1": {
|
||||||
|
"null": true
|
||||||
|
}
|
||||||
|
}'''
|
||||||
|
assert serialize_json({1: {None: True}}) == '{"1": {"null": true}}'
|
||||||
|
assert serialize_json({1: {None: True}, 2: 'Hello, World!'}, separators = (',', ':')) == '{"1":{"null":true},"2":"Hello, World!"}'
|
||||||
|
|
||||||
|
array = [True, False, 1, None, 'Hello, World!']
|
||||||
|
assert serialize_json(array) == '[true, false, 1, null, "Hello, World!"]'
|
||||||
|
assert serialize_json(array, 4, 'X', (';', ':')) == '''[
|
||||||
|
XXXXtrue;
|
||||||
|
XXXXfalse;
|
||||||
|
XXXX1;
|
||||||
|
XXXXnull;
|
||||||
|
XXXX"Hello, World!"
|
||||||
|
]'''
|
||||||
|
assert serialize_json((1, 2, 3)) == '[1, 2, 3]'
|
||||||
|
assert serialize_json(range(3)) == '[0, 1, 2]'
|
||||||
|
assert serialize_json(b'\x0142') == '[1, 52, 50]'
|
||||||
|
|
||||||
|
assert serialize_json('Hello, World!') == '"Hello, World!"'
|
||||||
|
assert serialize_json('Hello,\nWorld!') == '"Hello,\\nWorld!"'
|
||||||
|
assert serialize_json('Hello,"World!') == '"Hello,\\"World!"'
|
||||||
|
assert serialize_json('Hello,\\World!') == '"Hello,\\\\World!"'
|
||||||
|
assert serialize_json('Hello,\bWorld!') == '"Hello,\\bWorld!"'
|
||||||
|
assert serialize_json('Hello,\tWorld!') == '"Hello,\\tWorld!"'
|
||||||
|
assert serialize_json('Hello,\rWorld!') == '"Hello,\\rWorld!"'
|
||||||
|
assert serialize_json('Hello,\fWorld!') == '"Hello,\\fWorld!"'
|
||||||
|
|
||||||
|
assert serialize_json(0) == '0'
|
||||||
|
assert serialize_json(1) == '1'
|
||||||
|
assert serialize_json(-1) == '-1'
|
||||||
|
assert serialize_json(0.0) == '0.0'
|
||||||
|
assert serialize_json(-0.0) == '-0.0'
|
||||||
|
assert serialize_json(-42.0) == '-42.0'
|
||||||
|
|
||||||
|
try:
|
||||||
|
serialize_json({1, 2, 3})
|
||||||
|
assert False, 'Expected TypeError'
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
Reference in New Issue
Block a user