diff --git a/common.py b/common.py index f158a3f..6c6429d 100644 --- a/common.py +++ b/common.py @@ -6,21 +6,9 @@ import csv import re from datetime import datetime -from os import makedirs, path +from os import path -from typing import Any, Dict, Iterable, List, OrderedDict, Union - -# String escape sequences -STRING_ESCAPE_SEQUENCES = ( - ('\\', '\\\\'), # Must be the first one to avoid recursion! - ('\b', '\\b'), - ('\f', '\\f'), - ('\n', '\\n'), - ('\r', '\\r'), - ('\t', '\\t'), - ('\v', '\\v'), - ('"', '\\"'), -) +from typing import Any, Dict, List, OrderedDict, Union def init_cache(uuid_cache_file: str) -> Dict[str, str]: @@ -52,29 +40,6 @@ def now() -> str: return datetime.utcnow().replace(microsecond=0).isoformat() + 'Z' -def escape_string(string: str) -> str: - """ - Escape a string according to LibrePCB S-Expression escaping rules. - """ - for search, replacement in STRING_ESCAPE_SEQUENCES: - string = string.replace(search, replacement) - return string - - -def format_float(number: float) -> str: - """ - Format a float according to LibrePCB normalization rules. - """ - formatted = '{:.3f}'.format(number) - if formatted == '-0.000': - return '0.0' # Remove useless sign - if formatted[-1] == '0': - if formatted[-2] == '0': - return formatted[:-2] - return formatted[:-1] - return formatted - - def format_ipc_dimension(number: float, decimal_places: int = 2) -> str: """ Format a dimension (e.g. lead span or height) according to IPC rules. @@ -91,13 +56,6 @@ def format_ipc_dimension(number: float, decimal_places: int = 2) -> str: return str(int(round(number, 6 - decimal_places))) -def indent(level: int, lines: Iterable[str]) -> List[str]: - """ - Indent the lines by the specified level. - """ - return [' ' * level + line for line in lines] - - def sign(val: Union[int, float]) -> int: """ Return 1 for positive or zero values, -1 otherwise. @@ -135,19 +93,3 @@ def _convert(text: str) -> Union[int, str]: return int(text) if text.isdigit() else text return [_convert(x) for x in re.split(r'(\d+)', key) if x] - - -def serialize_common( - serializable: Any, output_directory: str, uuid: str, long_type: str, short_type: str -) -> None: - """ - Centralized serialize() implementation shared between Component, Symbol, Device, Package - """ - dir_path = path.join(output_directory, uuid) - if not (path.exists(dir_path) and path.isdir(dir_path)): - makedirs(dir_path) - with open(path.join(dir_path, f'.librepcb-{short_type}'), 'w', newline='\n') as f: - f.write('2\n') - with open(path.join(dir_path, f'{long_type}.lp'), 'w', newline='\n') as f: - f.write(str(serializable)) - f.write('\n') diff --git a/entities/common.py b/entities/common.py index f45c9c9..7c94e47 100644 --- a/entities/common.py +++ b/entities/common.py @@ -6,9 +6,7 @@ from typing import List, Optional -from common import escape_string, format_float - -from .helper import indent_entities +from .helper import escape_string, format_float, indent_entities class EnumValue(Enum): diff --git a/entities/component.py b/entities/component.py index bbcb233..2ded04f 100644 --- a/entities/component.py +++ b/entities/component.py @@ -1,7 +1,5 @@ from typing import Iterable, List, Optional -from common import serialize_common - from .common import ( Author, BoolValue, @@ -19,7 +17,7 @@ UUIDValue, Version, ) -from .helper import indent_entities +from .helper import indent_entities, serialize_common class DefaultValue(StringValue): diff --git a/entities/device.py b/entities/device.py index c493e89..83fd1f8 100644 --- a/entities/device.py +++ b/entities/device.py @@ -1,11 +1,9 @@ from typing import Iterable, List, Optional -from common import escape_string, serialize_common -from entities.attribute import Attribute -from entities.common import BoolValue - +from .attribute import Attribute from .common import ( Author, + BoolValue, Category, Created, Deprecated, @@ -19,7 +17,7 @@ Version, ) from .component import SignalUUID -from .helper import indent_entities +from .helper import escape_string, indent_entities, serialize_common class ComponentUUID(UUIDValue): diff --git a/entities/helper.py b/entities/helper.py index 7b14a25..7b03d64 100644 --- a/entities/helper.py +++ b/entities/helper.py @@ -1,6 +1,25 @@ -from typing import Any, Iterable +from os import makedirs, path -from common import indent +from typing import Any, Iterable, List + +# String escape sequences +STRING_ESCAPE_SEQUENCES = ( + ('\\', '\\\\'), # Must be the first one to avoid recursion! + ('\b', '\\b'), + ('\f', '\\f'), + ('\n', '\\n'), + ('\r', '\\r'), + ('\t', '\\t'), + ('\v', '\\v'), + ('"', '\\"'), +) + + +def indent(level: int, lines: Iterable[str]) -> List[str]: + """ + Indent the lines by the specified level. + """ + return [' ' * level + line for line in lines] def indent_entity(entity: Any) -> str: @@ -27,3 +46,42 @@ def indent_entities(entities: Iterable[Any]) -> str: ' (bar "2")\\n (bar "3")\\n' """ return ''.join(map(indent_entity, entities)) + + +def escape_string(string: str) -> str: + """ + Escape a string according to LibrePCB S-Expression escaping rules. + """ + for search, replacement in STRING_ESCAPE_SEQUENCES: + string = string.replace(search, replacement) + return string + + +def format_float(number: float) -> str: + """ + Format a float according to LibrePCB normalization rules. + """ + formatted = '{:.3f}'.format(number) + if formatted == '-0.000': + return '0.0' # Remove useless sign + if formatted[-1] == '0': + if formatted[-2] == '0': + return formatted[:-2] + return formatted[:-1] + return formatted + + +def serialize_common( + serializable: Any, output_directory: str, uuid: str, long_type: str, short_type: str +) -> None: + """ + Centralized serialize() implementation shared between Component, Symbol, Device, Package + """ + dir_path = path.join(output_directory, uuid) + if not (path.exists(dir_path) and path.isdir(dir_path)): + makedirs(dir_path) + with open(path.join(dir_path, f'.librepcb-{short_type}'), 'w', newline='\n') as f: + f.write('2\n') + with open(path.join(dir_path, f'{long_type}.lp'), 'w', newline='\n') as f: + f.write(str(serializable)) + f.write('\n') diff --git a/entities/package.py b/entities/package.py index e855a65..ee84573 100644 --- a/entities/package.py +++ b/entities/package.py @@ -1,7 +1,5 @@ from typing import Iterable, List, Optional, Union -from common import format_float, serialize_common - from .common import ( Align, Author, @@ -29,7 +27,7 @@ Version, Vertex, ) -from .helper import indent_entities +from .helper import format_float, indent_entities, serialize_common class Package3DModel: diff --git a/entities/symbol.py b/entities/symbol.py index aa5135b..844c1d0 100644 --- a/entities/symbol.py +++ b/entities/symbol.py @@ -1,7 +1,5 @@ from typing import Iterable, List -from common import format_float, serialize_common - from .common import ( Author, Category, @@ -20,7 +18,7 @@ Text, Version, ) -from .helper import indent_entities +from .helper import format_float, indent_entities, serialize_common class NamePosition: diff --git a/test_common.py b/test_common.py index e01e098..d524349 100644 --- a/test_common.py +++ b/test_common.py @@ -1,6 +1,7 @@ import pytest -from common import escape_string, format_float, format_ipc_dimension, human_sort_key, sign +from common import format_ipc_dimension, human_sort_key, sign +from entities.helper import escape_string, format_float @pytest.mark.parametrize(