cfinterface 1.5.2__tar.gz → 1.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cfinterface-1.5.2 → cfinterface-1.7.0}/PKG-INFO +3 -1
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/__init__.py +1 -1
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/adapters/reading/repository.py +9 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/adapters/writing/repository.py +9 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/block.py +2 -0
- cfinterface-1.7.0/cfinterface/components/datetimefield.py +96 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/defaultblock.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/defaultregister.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/defaultsection.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/field.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/floatfield.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/integerfield.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/line.py +9 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/literalfield.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/register.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/section.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/data/blockdata.py +18 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/data/registerdata.py +20 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/data/sectiondata.py +20 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/files/blockfile.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/files/registerfile.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/files/sectionfile.py +2 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/reading/blockreading.py +9 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/reading/registerreading.py +9 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/reading/sectionreading.py +9 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/writing/blockwriting.py +6 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/writing/registerwriting.py +6 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/writing/sectionwriting.py +6 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface.egg-info/PKG-INFO +3 -1
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_datetimefield.py +19 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/data/test_blockdata.py +9 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/data/test_registerdata.py +11 -2
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/data/test_sectiondata.py +9 -0
- cfinterface-1.5.2/cfinterface/components/datetimefield.py +0 -66
- {cfinterface-1.5.2 → cfinterface-1.7.0}/LICENSE.md +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/README.md +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/_utils/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/adapters/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/adapters/components/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/adapters/components/line/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/adapters/components/line/repository.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/adapters/components/repository.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/adapters/reading/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/adapters/writing/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/components/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/data/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/files/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/py.typed +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/reading/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface/writing/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface.egg-info/SOURCES.txt +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface.egg-info/dependency_links.txt +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface.egg-info/requires.txt +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/cfinterface.egg-info/top_level.txt +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/examples/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/setup.cfg +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/setup.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/adapters/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/adapters/components/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/adapters/components/test_blockrepository.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/adapters/components/test_linerepository.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/adapters/components/test_registerrepository.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/adapters/components/test_sectionrepository.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/adapters/reading/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/adapters/reading/test_readingrepository.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/adapters/writing/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/adapters/writing/test_writingrepository.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_block.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_defaultblock.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_defaultregister.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_defaultsection.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_field.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_floatfield.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_integerfield.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_line.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_literalfield.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_register.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/components/test_section.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/data/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/files/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/files/test_blockfile.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/files/test_registerfile.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/files/test_sectionfile.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/mocks/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/mocks/mock_open.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/reading/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/reading/test_blockreading.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/reading/test_registerreading.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/reading/test_sectionreading.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/writing/__init__.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/writing/test_blockwriting.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/writing/test_registerwriting.py +0 -0
- {cfinterface-1.5.2 → cfinterface-1.7.0}/tests/writing/test_sectionwriting.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cfinterface
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.0
|
|
4
4
|
Summary: Interface for handling custom formatted files
|
|
5
5
|
Home-page: https://github.com/rjmalves/cfi
|
|
6
6
|
Author: Rogerio Alves
|
|
@@ -12,6 +12,8 @@ Classifier: Development Status :: 4 - Beta
|
|
|
12
12
|
Requires-Python: >=3.8
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE.md
|
|
15
|
+
Requires-Dist: numpy
|
|
16
|
+
Requires-Dist: pandas
|
|
15
17
|
|
|
16
18
|
# cfinterface
|
|
17
19
|
|
|
@@ -4,6 +4,9 @@ from io import BytesIO, StringIO
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class Repository(ABC):
|
|
7
|
+
|
|
8
|
+
__slots__ = ["_content", "_wrap_io"]
|
|
9
|
+
|
|
7
10
|
def __init__(
|
|
8
11
|
self, content: Union[str, bytes], wrap_io: bool = False, *args
|
|
9
12
|
) -> None:
|
|
@@ -36,6 +39,9 @@ class Repository(ABC):
|
|
|
36
39
|
|
|
37
40
|
|
|
38
41
|
class BinaryRepository(Repository):
|
|
42
|
+
|
|
43
|
+
__slots__ = ["_filepointer"]
|
|
44
|
+
|
|
39
45
|
def __init__(
|
|
40
46
|
self, content: Union[str, bytes], wrap_io: bool = False, *args
|
|
41
47
|
) -> None:
|
|
@@ -72,6 +78,9 @@ class BinaryRepository(Repository):
|
|
|
72
78
|
|
|
73
79
|
|
|
74
80
|
class TextualRepository(Repository):
|
|
81
|
+
|
|
82
|
+
__slots__ = ["_filepointer", "_encoding"]
|
|
83
|
+
|
|
75
84
|
def __init__(
|
|
76
85
|
self,
|
|
77
86
|
content: str,
|
|
@@ -3,6 +3,9 @@ from abc import ABC, abstractmethod
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class Repository(ABC):
|
|
6
|
+
|
|
7
|
+
__slots__ = ["_to", "_wrap_io"]
|
|
8
|
+
|
|
6
9
|
def __init__(self, to: Union[str, IO], *args) -> None:
|
|
7
10
|
self._to = to
|
|
8
11
|
self._wrap_io = isinstance(to, str)
|
|
@@ -30,6 +33,9 @@ class Repository(ABC):
|
|
|
30
33
|
|
|
31
34
|
|
|
32
35
|
class BinaryRepository(Repository):
|
|
36
|
+
|
|
37
|
+
__slots__ = ["_filepointer"]
|
|
38
|
+
|
|
33
39
|
def __init__(self, path: str, *args) -> None:
|
|
34
40
|
super().__init__(path)
|
|
35
41
|
self._filepointer: BinaryIO = None # type: ignore
|
|
@@ -59,6 +65,9 @@ class BinaryRepository(Repository):
|
|
|
59
65
|
|
|
60
66
|
|
|
61
67
|
class TextualRepository(Repository):
|
|
68
|
+
|
|
69
|
+
__slots__ = ["_filepointer", "_encoding"]
|
|
70
|
+
|
|
62
71
|
def __init__(self, path: str, encoding: str) -> None:
|
|
63
72
|
super().__init__(path)
|
|
64
73
|
self._filepointer: TextIO = None # type: ignore
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
import pandas as pd # type: ignore
|
|
3
|
+
from typing import Optional, Union, List
|
|
4
|
+
|
|
5
|
+
from cfinterface.components.field import Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DatetimeField(Field):
|
|
9
|
+
"""
|
|
10
|
+
Class for representing an datetime field for being read from and
|
|
11
|
+
written to a file. The format to read and write the value is given
|
|
12
|
+
by an optional argument.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__slots__ = ["__format"]
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
size: int = 16,
|
|
20
|
+
starting_position: int = 0,
|
|
21
|
+
format: Union[str, List[str]] = "%Y/%m/%d",
|
|
22
|
+
value: Optional[datetime] = None,
|
|
23
|
+
) -> None:
|
|
24
|
+
super().__init__(size, starting_position, value)
|
|
25
|
+
self.__format = format
|
|
26
|
+
|
|
27
|
+
# Override
|
|
28
|
+
def _binary_read(self, line: bytes) -> datetime:
|
|
29
|
+
formats = (
|
|
30
|
+
[self.__format]
|
|
31
|
+
if isinstance(self.__format, str)
|
|
32
|
+
else self.__format
|
|
33
|
+
)
|
|
34
|
+
for fmt in formats:
|
|
35
|
+
try:
|
|
36
|
+
return datetime.strptime(
|
|
37
|
+
line[self._starting_position : self._ending_position]
|
|
38
|
+
.decode("utf-8")
|
|
39
|
+
.strip(),
|
|
40
|
+
fmt,
|
|
41
|
+
)
|
|
42
|
+
except ValueError:
|
|
43
|
+
pass
|
|
44
|
+
raise ValueError("Could not read datetime")
|
|
45
|
+
|
|
46
|
+
# Override
|
|
47
|
+
def _textual_read(self, line: str) -> datetime:
|
|
48
|
+
formats = (
|
|
49
|
+
[self.__format]
|
|
50
|
+
if isinstance(self.__format, str)
|
|
51
|
+
else self.__format
|
|
52
|
+
)
|
|
53
|
+
for fmt in formats:
|
|
54
|
+
try:
|
|
55
|
+
return datetime.strptime(
|
|
56
|
+
line[
|
|
57
|
+
self._starting_position : self._ending_position
|
|
58
|
+
].strip(),
|
|
59
|
+
fmt,
|
|
60
|
+
)
|
|
61
|
+
except ValueError:
|
|
62
|
+
pass
|
|
63
|
+
raise ValueError("Could not read datetime")
|
|
64
|
+
|
|
65
|
+
# Override
|
|
66
|
+
def _binary_write(self) -> bytes:
|
|
67
|
+
if self.value is None or pd.isnull(self.value):
|
|
68
|
+
return b"".ljust(self.size)
|
|
69
|
+
else:
|
|
70
|
+
format = (
|
|
71
|
+
self.__format
|
|
72
|
+
if isinstance(self.__format, str)
|
|
73
|
+
else self.__format[0]
|
|
74
|
+
)
|
|
75
|
+
return self.value.strftime(format).ljust(self.size).encode("utf-8")
|
|
76
|
+
|
|
77
|
+
# Override
|
|
78
|
+
def _textual_write(self) -> str:
|
|
79
|
+
if self.value is None or pd.isnull(self.value):
|
|
80
|
+
value = ""
|
|
81
|
+
else:
|
|
82
|
+
format = (
|
|
83
|
+
self.__format
|
|
84
|
+
if isinstance(self.__format, str)
|
|
85
|
+
else self.__format[0]
|
|
86
|
+
)
|
|
87
|
+
value = self.value.strftime(format)
|
|
88
|
+
return value.ljust(self._size)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def value(self) -> Optional[datetime]:
|
|
92
|
+
return self._value
|
|
93
|
+
|
|
94
|
+
@value.setter
|
|
95
|
+
def value(self, val: datetime):
|
|
96
|
+
self._value = val
|
|
@@ -8,6 +8,8 @@ class BlockData:
|
|
|
8
8
|
Class for a storing, managing and accessing data for a block file.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
__slots__ = ["__root", "__head"]
|
|
12
|
+
|
|
11
13
|
T = TypeVar("T")
|
|
12
14
|
|
|
13
15
|
def __init__(self, root: Block) -> None:
|
|
@@ -148,6 +150,22 @@ class BlockData:
|
|
|
148
150
|
else:
|
|
149
151
|
return filtered_blocks
|
|
150
152
|
|
|
153
|
+
def remove_blocks_of_type(self, t: Type[T], **kwargs):
|
|
154
|
+
"""
|
|
155
|
+
Removes a set of blocks given a type and an optional group of
|
|
156
|
+
filters, similar to `get_blocks_of_type()`
|
|
157
|
+
|
|
158
|
+
:param t: The block type that is desired
|
|
159
|
+
:type t: Type[T]
|
|
160
|
+
"""
|
|
161
|
+
filtered_blocks = self.get_blocks_of_type(t, **kwargs)
|
|
162
|
+
if isinstance(filtered_blocks, Block):
|
|
163
|
+
self.remove(filtered_blocks)
|
|
164
|
+
elif isinstance(filtered_blocks, list):
|
|
165
|
+
for b in filtered_blocks:
|
|
166
|
+
if isinstance(b, Block) and b != self.__root:
|
|
167
|
+
self.remove(b)
|
|
168
|
+
|
|
151
169
|
@property
|
|
152
170
|
def first(self) -> Block:
|
|
153
171
|
return self.__root
|
|
@@ -8,6 +8,8 @@ class RegisterData:
|
|
|
8
8
|
Class for a storing, managing and accessing data for a register file.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
__slots__ = ["__root", "__head"]
|
|
12
|
+
|
|
11
13
|
T = TypeVar("T")
|
|
12
14
|
|
|
13
15
|
def __init__(self, root: Register) -> None:
|
|
@@ -147,6 +149,24 @@ class RegisterData:
|
|
|
147
149
|
else:
|
|
148
150
|
return filtered_registers
|
|
149
151
|
|
|
152
|
+
def remove_registers_of_type(self, t: Type[T], **kwargs):
|
|
153
|
+
"""
|
|
154
|
+
Removes a set of registers given a type and an optional group of
|
|
155
|
+
filters, similar to `get_registers_of_type()`
|
|
156
|
+
|
|
157
|
+
:param t: The register type that is desired
|
|
158
|
+
:type t: Type[T]
|
|
159
|
+
"""
|
|
160
|
+
filtered_registers = self.get_registers_of_type(t, **kwargs)
|
|
161
|
+
if isinstance(filtered_registers, t) and isinstance(
|
|
162
|
+
filtered_registers, Register
|
|
163
|
+
):
|
|
164
|
+
self.remove(filtered_registers)
|
|
165
|
+
elif isinstance(filtered_registers, list):
|
|
166
|
+
for r in filtered_registers:
|
|
167
|
+
if isinstance(r, Register) and r != self.__root:
|
|
168
|
+
self.remove(r)
|
|
169
|
+
|
|
150
170
|
@property
|
|
151
171
|
def first(self) -> Register:
|
|
152
172
|
return self.__root
|
|
@@ -8,6 +8,8 @@ class SectionData:
|
|
|
8
8
|
Class for a storing, managing and accessing data for a section file.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
__slots__ = ["__root", "__head"]
|
|
12
|
+
|
|
11
13
|
T = TypeVar("T")
|
|
12
14
|
|
|
13
15
|
def __init__(self, root: Section) -> None:
|
|
@@ -148,6 +150,24 @@ class SectionData:
|
|
|
148
150
|
else:
|
|
149
151
|
return filtered_sections
|
|
150
152
|
|
|
153
|
+
def remove_sections_of_type(self, t: Type[T], **kwargs):
|
|
154
|
+
"""
|
|
155
|
+
Removes a set of sections given a type and an optional group of
|
|
156
|
+
filters, similar to `get_sections_of_type()`
|
|
157
|
+
|
|
158
|
+
:param t: The section type that is desired
|
|
159
|
+
:type t: Type[T]
|
|
160
|
+
"""
|
|
161
|
+
filtered_sections = self.get_sections_of_type(t, **kwargs)
|
|
162
|
+
if isinstance(filtered_sections, t) and isinstance(
|
|
163
|
+
filtered_sections, Section
|
|
164
|
+
):
|
|
165
|
+
self.remove(filtered_sections)
|
|
166
|
+
elif isinstance(filtered_sections, list):
|
|
167
|
+
for s in filtered_sections:
|
|
168
|
+
if isinstance(s, Section) and s != self.__root:
|
|
169
|
+
self.remove(s)
|
|
170
|
+
|
|
151
171
|
@property
|
|
152
172
|
def first(self) -> Section:
|
|
153
173
|
return self.__root
|
|
@@ -13,6 +13,15 @@ class BlockReading:
|
|
|
13
13
|
Class for reading custom files based on a BlockData structure.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
+
__slots__ = [
|
|
17
|
+
"__allowed_blocks",
|
|
18
|
+
"__data",
|
|
19
|
+
"__last_position_filepointer",
|
|
20
|
+
"__storage",
|
|
21
|
+
"__linesize",
|
|
22
|
+
"__repository",
|
|
23
|
+
]
|
|
24
|
+
|
|
16
25
|
def __init__(
|
|
17
26
|
self,
|
|
18
27
|
allowed_blocks: List[Type[Block]],
|
|
@@ -13,6 +13,15 @@ class RegisterReading:
|
|
|
13
13
|
Class for reading custom files based on a RegisterData structure.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
+
__slots__ = [
|
|
17
|
+
"__allowed_registers",
|
|
18
|
+
"__data",
|
|
19
|
+
"__last_position_filepointer",
|
|
20
|
+
"__storage",
|
|
21
|
+
"__linesize",
|
|
22
|
+
"__repository",
|
|
23
|
+
]
|
|
24
|
+
|
|
16
25
|
def __init__(
|
|
17
26
|
self,
|
|
18
27
|
allowed_registers: List[Type[Register]],
|
|
@@ -13,6 +13,15 @@ class SectionReading:
|
|
|
13
13
|
Class for reading custom files based on a SectionData structure.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
+
__slots__ = [
|
|
17
|
+
"__sections",
|
|
18
|
+
"__data",
|
|
19
|
+
"__last_position_filepointer",
|
|
20
|
+
"__storage",
|
|
21
|
+
"__linesize",
|
|
22
|
+
"__repository",
|
|
23
|
+
]
|
|
24
|
+
|
|
16
25
|
def __init__(
|
|
17
26
|
self,
|
|
18
27
|
sections: List[Type[Section]],
|
|
@@ -11,6 +11,12 @@ class BlockWriting:
|
|
|
11
11
|
Class for writing custom files based on a BlockData structure.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
+
__slots__ = [
|
|
15
|
+
"__data",
|
|
16
|
+
"__storage",
|
|
17
|
+
"__repository",
|
|
18
|
+
]
|
|
19
|
+
|
|
14
20
|
def __init__(self, data: BlockData, storage: str = "") -> None:
|
|
15
21
|
self.__data = data
|
|
16
22
|
self.__storage = storage
|
|
@@ -12,6 +12,12 @@ class RegisterWriting:
|
|
|
12
12
|
Class for writing custom files based on a RegisterData structure.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
+
__slots__ = [
|
|
16
|
+
"__data",
|
|
17
|
+
"__storage",
|
|
18
|
+
"__repository",
|
|
19
|
+
]
|
|
20
|
+
|
|
15
21
|
def __init__(self, data: RegisterData, storage: str = "") -> None:
|
|
16
22
|
self.__data = data
|
|
17
23
|
self.__storage = storage
|
|
@@ -12,6 +12,12 @@ class SectionWriting:
|
|
|
12
12
|
Class for writing custom files based on a SectionData structure.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
+
__slots__ = [
|
|
16
|
+
"__data",
|
|
17
|
+
"__storage",
|
|
18
|
+
"__repository",
|
|
19
|
+
]
|
|
20
|
+
|
|
15
21
|
def __init__(self, data: SectionData, storage: str = "") -> None:
|
|
16
22
|
self.__data = data
|
|
17
23
|
self.__storage = storage
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cfinterface
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.0
|
|
4
4
|
Summary: Interface for handling custom formatted files
|
|
5
5
|
Home-page: https://github.com/rjmalves/cfi
|
|
6
6
|
Author: Rogerio Alves
|
|
@@ -12,6 +12,8 @@ Classifier: Development Status :: 4 - Beta
|
|
|
12
12
|
Requires-Python: >=3.8
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE.md
|
|
15
|
+
Requires-Dist: numpy
|
|
16
|
+
Requires-Dist: pandas
|
|
15
17
|
|
|
16
18
|
# cfinterface
|
|
17
19
|
|
|
@@ -21,6 +21,15 @@ def test_datetimefield_read():
|
|
|
21
21
|
assert field.value == datetime.strptime(data, format)
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
def test_datetimefield_read_format_list():
|
|
25
|
+
data = "2020/01/10"
|
|
26
|
+
formats = ["%Y-%m-%d", "%Y/%m/%d"]
|
|
27
|
+
field = DatetimeField(10, 0, format=formats)
|
|
28
|
+
line = f"{data}-something-else"
|
|
29
|
+
field.read(line)
|
|
30
|
+
assert field.value == datetime.strptime(data, formats[1])
|
|
31
|
+
|
|
32
|
+
|
|
24
33
|
def test_datetimefield_write():
|
|
25
34
|
data = "2020/01/10"
|
|
26
35
|
format = "%Y/%m/%d"
|
|
@@ -31,6 +40,16 @@ def test_datetimefield_write():
|
|
|
31
40
|
assert line_before == line_after
|
|
32
41
|
|
|
33
42
|
|
|
43
|
+
def test_datetimefield_write_format_list():
|
|
44
|
+
data = "2020/01/10"
|
|
45
|
+
formats = ["%Y-%m-%d", "%Y/%m/%d"]
|
|
46
|
+
line_before = f"field-{data}-else"
|
|
47
|
+
date_data = datetime.strptime(data, formats[1])
|
|
48
|
+
field = DatetimeField(10, 6, format=formats, value=date_data)
|
|
49
|
+
line_after = field.write(line_before)
|
|
50
|
+
assert line_before.replace("/", "-") == line_after
|
|
51
|
+
|
|
52
|
+
|
|
34
53
|
def test_datetimefield_write_empty():
|
|
35
54
|
field = DatetimeField(5, 0)
|
|
36
55
|
assert len(field.write("")) == 5
|
|
@@ -125,3 +125,12 @@ def test_blockdata_get_blocks_of_type_filter():
|
|
|
125
125
|
bd.append(DummyBlock(data=11))
|
|
126
126
|
assert len(bd.get_blocks_of_type(DummyBlock)) == 3
|
|
127
127
|
assert bd.get_blocks_of_type(DummyBlock, my_data=10) == b1
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_blockdata_remove_blocks_of_type_no_filter():
|
|
131
|
+
b1 = DummyBlock(data=10)
|
|
132
|
+
bd = BlockData(b1)
|
|
133
|
+
bd.append(DummyBlock())
|
|
134
|
+
bd.append(DummyBlock(data=11))
|
|
135
|
+
bd.remove_blocks_of_type(DummyBlock)
|
|
136
|
+
assert len(bd) == 1
|
|
@@ -108,17 +108,26 @@ def test_registerdata_of_type():
|
|
|
108
108
|
assert len([b for b in rd.of_type(DummyRegister)]) == 2
|
|
109
109
|
|
|
110
110
|
|
|
111
|
-
def
|
|
111
|
+
def test_registerdata_get_registers_of_type_no_filter():
|
|
112
112
|
r1 = DummyRegister(data=[10])
|
|
113
113
|
rd = RegisterData(r1)
|
|
114
114
|
rd.append(Register())
|
|
115
115
|
assert rd.get_registers_of_type(DummyRegister) == r1
|
|
116
116
|
|
|
117
117
|
|
|
118
|
-
def
|
|
118
|
+
def test_registerdata_get_registers_of_type_filter():
|
|
119
119
|
r1 = DummyRegister(data=[10])
|
|
120
120
|
rd = RegisterData(r1)
|
|
121
121
|
rd.append(DummyRegister())
|
|
122
122
|
rd.append(DummyRegister(data=[11]))
|
|
123
123
|
assert len(rd.get_registers_of_type(DummyRegister)) == 3
|
|
124
124
|
assert rd.get_registers_of_type(DummyRegister, my_data=10) == r1
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_registerdata_remove_registers_of_type_no_filter():
|
|
128
|
+
r1 = DummyRegister(data=[10])
|
|
129
|
+
rd = RegisterData(r1)
|
|
130
|
+
rd.append(DummyRegister())
|
|
131
|
+
rd.append(DummyRegister(data=[11]))
|
|
132
|
+
rd.remove_registers_of_type(DummyRegister)
|
|
133
|
+
assert len(rd) == 1
|
|
@@ -122,3 +122,12 @@ def test_sectiondata_get_sections_of_type_filter():
|
|
|
122
122
|
bd.append(DummySection(data=11))
|
|
123
123
|
assert len(bd.get_sections_of_type(DummySection)) == 3
|
|
124
124
|
assert bd.get_sections_of_type(DummySection, my_data=10) == b1
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_sectiondata_remove_sections_of_type_no_filter():
|
|
128
|
+
b1 = DummySection(data=10)
|
|
129
|
+
bd = SectionData(b1)
|
|
130
|
+
bd.append(DummySection())
|
|
131
|
+
bd.append(DummySection(data=11))
|
|
132
|
+
bd.remove_sections_of_type(DummySection)
|
|
133
|
+
assert len(bd) == 1
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
import pandas as pd # type: ignore
|
|
3
|
-
from typing import Optional
|
|
4
|
-
|
|
5
|
-
from cfinterface.components.field import Field
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class DatetimeField(Field):
|
|
9
|
-
"""
|
|
10
|
-
Class for representing an datetime field for being read from and
|
|
11
|
-
written to a file. The format to read and write the value is given
|
|
12
|
-
by an optional argument.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
def __init__(
|
|
16
|
-
self,
|
|
17
|
-
size: int = 16,
|
|
18
|
-
starting_position: int = 0,
|
|
19
|
-
format: str = "%Y/%m/%d",
|
|
20
|
-
value: Optional[datetime] = None,
|
|
21
|
-
) -> None:
|
|
22
|
-
super().__init__(size, starting_position, value)
|
|
23
|
-
self.__format = format
|
|
24
|
-
|
|
25
|
-
# Override
|
|
26
|
-
def _binary_read(self, line: bytes) -> datetime:
|
|
27
|
-
return datetime.strptime(
|
|
28
|
-
line[self._starting_position : self._ending_position]
|
|
29
|
-
.decode("utf-8")
|
|
30
|
-
.strip(),
|
|
31
|
-
self.__format,
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
# Override
|
|
35
|
-
def _textual_read(self, line: str) -> datetime:
|
|
36
|
-
return datetime.strptime(
|
|
37
|
-
line[self._starting_position : self._ending_position].strip(),
|
|
38
|
-
self.__format,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
# Override
|
|
42
|
-
def _binary_write(self) -> bytes:
|
|
43
|
-
if self.value is None or pd.isnull(self.value):
|
|
44
|
-
return b"".ljust(self.size)
|
|
45
|
-
else:
|
|
46
|
-
return (
|
|
47
|
-
self.value.strftime(self.__format)
|
|
48
|
-
.ljust(self.size)
|
|
49
|
-
.encode("utf-8")
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
# Override
|
|
53
|
-
def _textual_write(self) -> str:
|
|
54
|
-
if self.value is None or pd.isnull(self.value):
|
|
55
|
-
value = ""
|
|
56
|
-
else:
|
|
57
|
-
value = self.value.strftime(self.__format)
|
|
58
|
-
return value.ljust(self._size)
|
|
59
|
-
|
|
60
|
-
@property
|
|
61
|
-
def value(self) -> Optional[datetime]:
|
|
62
|
-
return self._value
|
|
63
|
-
|
|
64
|
-
@value.setter
|
|
65
|
-
def value(self, val: datetime):
|
|
66
|
-
self._value = val
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cfinterface-1.5.2 → cfinterface-1.7.0}/tests/adapters/components/test_registerrepository.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|