cfinterface 1.10.0__tar.gz → 1.10.2__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.
Files changed (163) hide show
  1. {cfinterface-1.10.0 → cfinterface-1.10.2}/CHANGELOG.md +12 -0
  2. {cfinterface-1.10.0 → cfinterface-1.10.2}/PKG-INFO +2 -2
  3. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/__init__.py +1 -1
  4. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/floatfield.py +5 -5
  5. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/files/blockfile.py +7 -5
  6. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/files/registerfile.py +7 -5
  7. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/files/sectionfile.py +7 -5
  8. cfinterface-1.10.2/tests/files/test_read_typing.py +38 -0
  9. {cfinterface-1.10.0 → cfinterface-1.10.2}/.github/workflows/benchmark.yml +0 -0
  10. {cfinterface-1.10.0 → cfinterface-1.10.2}/.github/workflows/docs.yml +0 -0
  11. {cfinterface-1.10.0 → cfinterface-1.10.2}/.github/workflows/main.yml +0 -0
  12. {cfinterface-1.10.0 → cfinterface-1.10.2}/.github/workflows/publish.yml +0 -0
  13. {cfinterface-1.10.0 → cfinterface-1.10.2}/.gitignore +0 -0
  14. {cfinterface-1.10.0 → cfinterface-1.10.2}/.pre-commit-config.yaml +0 -0
  15. {cfinterface-1.10.0 → cfinterface-1.10.2}/CONTRIBUTING.md +0 -0
  16. {cfinterface-1.10.0 → cfinterface-1.10.2}/LICENSE +0 -0
  17. {cfinterface-1.10.0 → cfinterface-1.10.2}/README.md +0 -0
  18. {cfinterface-1.10.0 → cfinterface-1.10.2}/benchmarks/__init__.py +0 -0
  19. {cfinterface-1.10.0 → cfinterface-1.10.2}/benchmarks/bench_floatfield_write.py +0 -0
  20. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/_utils/__init__.py +0 -0
  21. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/adapters/__init__.py +0 -0
  22. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/adapters/components/__init__.py +0 -0
  23. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/adapters/components/line/__init__.py +0 -0
  24. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/adapters/components/line/repository.py +0 -0
  25. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/adapters/components/repository.py +0 -0
  26. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/adapters/reading/__init__.py +0 -0
  27. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/adapters/reading/repository.py +0 -0
  28. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/adapters/writing/__init__.py +0 -0
  29. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/adapters/writing/repository.py +0 -0
  30. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/__init__.py +0 -0
  31. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/block.py +0 -0
  32. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/datetimefield.py +0 -0
  33. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/defaultblock.py +0 -0
  34. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/defaultregister.py +0 -0
  35. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/defaultsection.py +0 -0
  36. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/field.py +0 -0
  37. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/integerfield.py +0 -0
  38. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/line.py +0 -0
  39. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/literalfield.py +0 -0
  40. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/register.py +0 -0
  41. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/section.py +0 -0
  42. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/components/tabular.py +0 -0
  43. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/data/__init__.py +0 -0
  44. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/data/blockdata.py +0 -0
  45. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/data/registerdata.py +0 -0
  46. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/data/sectiondata.py +0 -0
  47. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/files/__init__.py +0 -0
  48. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/py.typed +0 -0
  49. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/reading/__init__.py +0 -0
  50. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/reading/blockreading.py +0 -0
  51. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/reading/registerreading.py +0 -0
  52. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/reading/sectionreading.py +0 -0
  53. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/storage.py +0 -0
  54. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/versioning.py +0 -0
  55. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/writing/__init__.py +0 -0
  56. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/writing/blockwriting.py +0 -0
  57. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/writing/registerwriting.py +0 -0
  58. {cfinterface-1.10.0 → cfinterface-1.10.2}/cfinterface/writing/sectionwriting.py +0 -0
  59. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/_static/logo_cfinterface.svg +0 -0
  60. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/conf.py +0 -0
  61. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/getting_started/contributing.rst +0 -0
  62. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/getting_started/tutorial.rst +0 -0
  63. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/guides/architecture.rst +0 -0
  64. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/guides/faq.rst +0 -0
  65. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/guides/migration-v1.9.rst +0 -0
  66. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/guides/performance.rst +0 -0
  67. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/index.rst +0 -0
  68. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/install/install.rst +0 -0
  69. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/adapters/files/components.rst +0 -0
  70. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/adapters/files/line.rst +0 -0
  71. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/adapters/files/reading.rst +0 -0
  72. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/adapters/files/writing.rst +0 -0
  73. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/adapters/index.rst +0 -0
  74. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/blocks/files/block.rst +0 -0
  75. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/blocks/files/blockdata.rst +0 -0
  76. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/blocks/files/blockfile.rst +0 -0
  77. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/blocks/index.rst +0 -0
  78. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/fields/components/datetimefield.rst +0 -0
  79. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/fields/components/field.rst +0 -0
  80. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/fields/components/floatfield.rst +0 -0
  81. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/fields/components/integerfield.rst +0 -0
  82. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/fields/components/literalfield.rst +0 -0
  83. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/fields/index.rst +0 -0
  84. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/line/index.rst +0 -0
  85. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/registers/files/register.rst +0 -0
  86. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/registers/files/registerdata.rst +0 -0
  87. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/registers/files/registerfile.rst +0 -0
  88. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/registers/index.rst +0 -0
  89. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/sections/files/section.rst +0 -0
  90. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/sections/files/sectiondata.rst +0 -0
  91. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/sections/files/sectionfile.rst +0 -0
  92. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/sections/index.rst +0 -0
  93. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/storage/files/storagetype.rst +0 -0
  94. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/storage/index.rst +0 -0
  95. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/tabular/files/tabularparser.rst +0 -0
  96. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/tabular/files/tabularsection.rst +0 -0
  97. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/tabular/index.rst +0 -0
  98. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/versioning/files/versioning.rst +0 -0
  99. {cfinterface-1.10.0 → cfinterface-1.10.2}/docs/source/reference/versioning/index.rst +0 -0
  100. {cfinterface-1.10.0 → cfinterface-1.10.2}/examples/README.rst +0 -0
  101. {cfinterface-1.10.0 → cfinterface-1.10.2}/examples/__init__.py +0 -0
  102. {cfinterface-1.10.0 → cfinterface-1.10.2}/examples/plot_block_file.py +0 -0
  103. {cfinterface-1.10.0 → cfinterface-1.10.2}/examples/plot_register_file.py +0 -0
  104. {cfinterface-1.10.0 → cfinterface-1.10.2}/examples/plot_section_file.py +0 -0
  105. {cfinterface-1.10.0 → cfinterface-1.10.2}/examples/plot_tabular_parsing.py +0 -0
  106. {cfinterface-1.10.0 → cfinterface-1.10.2}/examples/plot_versioned_file.py +0 -0
  107. {cfinterface-1.10.0 → cfinterface-1.10.2}/pyproject.toml +0 -0
  108. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/__init__.py +0 -0
  109. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/_utils/__init__.py +0 -0
  110. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/_utils/test_is_null.py +0 -0
  111. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/__init__.py +0 -0
  112. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/components/__init__.py +0 -0
  113. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/components/test_blockrepository.py +0 -0
  114. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/components/test_factory.py +0 -0
  115. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/components/test_linerepository.py +0 -0
  116. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/components/test_pattern_cache.py +0 -0
  117. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/components/test_registerrepository.py +0 -0
  118. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/components/test_sectionrepository.py +0 -0
  119. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/reading/__init__.py +0 -0
  120. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/reading/test_readingrepository.py +0 -0
  121. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/writing/__init__.py +0 -0
  122. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/adapters/writing/test_writingrepository.py +0 -0
  123. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/__init__.py +0 -0
  124. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/conftest.py +0 -0
  125. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_block.py +0 -0
  126. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_datetimefield.py +0 -0
  127. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_defaultblock.py +0 -0
  128. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_defaultregister.py +0 -0
  129. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_defaultsection.py +0 -0
  130. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_field.py +0 -0
  131. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_field_hypothesis.py +0 -0
  132. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_floatfield.py +0 -0
  133. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_floatfield_benchmark.py +0 -0
  134. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_integerfield.py +0 -0
  135. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_line.py +0 -0
  136. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_literalfield.py +0 -0
  137. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_register.py +0 -0
  138. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_section.py +0 -0
  139. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_storage_integration.py +0 -0
  140. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_tabular.py +0 -0
  141. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/components/test_tabular_hypothesis.py +0 -0
  142. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/conftest.py +0 -0
  143. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/data/__init__.py +0 -0
  144. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/data/test_blockdata.py +0 -0
  145. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/data/test_registerdata.py +0 -0
  146. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/data/test_sectiondata.py +0 -0
  147. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/files/__init__.py +0 -0
  148. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/files/test_blockfile.py +0 -0
  149. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/files/test_registerfile.py +0 -0
  150. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/files/test_sectionfile.py +0 -0
  151. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/mocks/__init__.py +0 -0
  152. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/mocks/mock_open.py +0 -0
  153. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/reading/__init__.py +0 -0
  154. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/reading/test_blockreading.py +0 -0
  155. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/reading/test_registerreading.py +0 -0
  156. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/reading/test_sectionreading.py +0 -0
  157. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/test_storage.py +0 -0
  158. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/test_storage_deprecation.py +0 -0
  159. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/test_versioning.py +0 -0
  160. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/writing/__init__.py +0 -0
  161. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/writing/test_blockwriting.py +0 -0
  162. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/writing/test_registerwriting.py +0 -0
  163. {cfinterface-1.10.0 → cfinterface-1.10.2}/tests/writing/test_sectionwriting.py +0 -0
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.10.2] - 2026-10-14
11
+
12
+ ### Fixed
13
+
14
+ - Type `SectionFile.read()`, `RegisterFile.read()` and `BlockFile.read()` (and their `read_many()`) as returning the calling subclass instead of the base class, so mypy sees the attributes of files such as `Dadger` or `Caso` read through them
15
+
16
+ ## [1.10.1] - 2026-04-13
17
+
18
+ ### Fixed
19
+
20
+ - Resolve mypy `arg-type` error in `FloatField._apply_compact` by passing the numeric value as a parameter instead of accessing `self._value` directly
21
+
10
22
  ## [1.10.0] - 2026-04-13
11
23
 
12
24
  ### Added
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: cfinterface
3
- Version: 1.10.0
3
+ Version: 1.10.2
4
4
  Summary: Interface for handling custom formatted files
5
5
  Project-URL: Documentation, https://rjmalves.github.io/cfinterface/
6
6
  Project-URL: Repository, https://github.com/rjmalves/cfinterface/
@@ -6,7 +6,7 @@ cfi is a Python module for handling custom formatted files
6
6
  and provide reading, storing and writing utilities.
7
7
  """
8
8
 
9
- __version__ = "1.10.0"
9
+ __version__ = "1.10.2"
10
10
 
11
11
  from . import components # noqa
12
12
  from . import data # noqa
@@ -65,8 +65,8 @@ class FloatField(Field):
65
65
  else:
66
66
  return np.array([self._value], dtype=self.__type).tobytes()
67
67
 
68
- def _apply_compact(self, value: str) -> str:
69
- if self.__compact and 0 < abs(self._value) < 1:
68
+ def _apply_compact(self, value: str, numeric: float) -> str:
69
+ if self.__compact and 0 < abs(numeric) < 1:
70
70
  if value.startswith("0."):
71
71
  return value[1:]
72
72
  if value.startswith("-0."):
@@ -107,7 +107,7 @@ class FloatField(Field):
107
107
  d=self.__decimal_digits,
108
108
  format=formatting_format,
109
109
  ).replace("E", self.__format)
110
- value = self._apply_compact(value)
110
+ value = self._apply_compact(value, self.value)
111
111
  if len(value) > self._size:
112
112
  excess = len(value) - self._size
113
113
  new_d = self.__decimal_digits - excess
@@ -118,7 +118,7 @@ class FloatField(Field):
118
118
  d=new_d,
119
119
  format=formatting_format,
120
120
  ).replace("E", self.__format)
121
- value = self._apply_compact(value)
121
+ value = self._apply_compact(value, self.value)
122
122
  if len(value) > self._size:
123
123
  new_d = max(0, new_d - 1)
124
124
  value = "{:.{d}{format}}".format(
@@ -126,7 +126,7 @@ class FloatField(Field):
126
126
  d=new_d,
127
127
  format=formatting_format,
128
128
  ).replace("E", self.__format)
129
- value = self._apply_compact(value)
129
+ value = self._apply_compact(value, self.value)
130
130
  return value.rjust(self.size)
131
131
 
132
132
  @property
@@ -1,5 +1,5 @@
1
1
  import warnings
2
- from typing import IO, TYPE_CHECKING, Any
2
+ from typing import IO, TYPE_CHECKING, Any, TypeVar
3
3
 
4
4
  from cfinterface.components.block import Block
5
5
  from cfinterface.components.defaultblock import DefaultBlock
@@ -12,6 +12,8 @@ from cfinterface.writing.blockwriting import BlockWriting
12
12
  if TYPE_CHECKING:
13
13
  from cfinterface.versioning import VersionMatchResult
14
14
 
15
+ _BlockFileT = TypeVar("_BlockFileT", bound="BlockFile")
16
+
15
17
 
16
18
  class BlockFile:
17
19
  """
@@ -48,12 +50,12 @@ class BlockFile:
48
50
 
49
51
  @classmethod
50
52
  def read(
51
- cls,
53
+ cls: type[_BlockFileT],
52
54
  content: str | bytes,
53
55
  *args: Any,
54
56
  version: str | None = None,
55
57
  **kwargs: Any,
56
- ) -> "BlockFile":
58
+ ) -> _BlockFileT:
57
59
  """Read from a file path or buffer. ``version`` selects a component set
58
60
  from VERSIONS without mutating the class."""
59
61
  components = cls.BLOCKS
@@ -86,11 +88,11 @@ class BlockFile:
86
88
 
87
89
  @classmethod
88
90
  def read_many(
89
- cls,
91
+ cls: type[_BlockFileT],
90
92
  paths: list[str],
91
93
  *,
92
94
  version: str | None = None,
93
- ) -> dict[str, "BlockFile"]:
95
+ ) -> dict[str, _BlockFileT]:
94
96
  """Read multiple files and return a dict keyed by file path.
95
97
 
96
98
  Parameters
@@ -1,5 +1,5 @@
1
1
  import warnings
2
- from typing import IO, TYPE_CHECKING, Any
2
+ from typing import IO, TYPE_CHECKING, Any, TypeVar
3
3
 
4
4
  from cfinterface.components.defaultregister import DefaultRegister
5
5
  from cfinterface.components.register import Register
@@ -12,6 +12,8 @@ from cfinterface.writing.registerwriting import RegisterWriting
12
12
  if TYPE_CHECKING:
13
13
  from cfinterface.versioning import VersionMatchResult
14
14
 
15
+ _RegisterFileT = TypeVar("_RegisterFileT", bound="RegisterFile")
16
+
15
17
 
16
18
  class RegisterFile:
17
19
  """
@@ -65,12 +67,12 @@ class RegisterFile:
65
67
 
66
68
  @classmethod
67
69
  def read(
68
- cls,
70
+ cls: type[_RegisterFileT],
69
71
  content: str | bytes,
70
72
  *args: Any,
71
73
  version: str | None = None,
72
74
  **kwargs: Any,
73
- ) -> "RegisterFile":
75
+ ) -> _RegisterFileT:
74
76
  """Read from a file path or buffer. ``version`` selects a component set
75
77
  from VERSIONS without mutating the class."""
76
78
  components = cls.REGISTERS
@@ -103,11 +105,11 @@ class RegisterFile:
103
105
 
104
106
  @classmethod
105
107
  def read_many(
106
- cls,
108
+ cls: type[_RegisterFileT],
107
109
  paths: list[str],
108
110
  *,
109
111
  version: str | None = None,
110
- ) -> dict[str, "RegisterFile"]:
112
+ ) -> dict[str, _RegisterFileT]:
111
113
  """Read multiple files and return a dict keyed by file path.
112
114
 
113
115
  Parameters
@@ -1,5 +1,5 @@
1
1
  import warnings
2
- from typing import IO, TYPE_CHECKING, Any
2
+ from typing import IO, TYPE_CHECKING, Any, TypeVar
3
3
 
4
4
  from cfinterface.components.defaultsection import DefaultSection
5
5
  from cfinterface.components.section import Section
@@ -12,6 +12,8 @@ from cfinterface.writing.sectionwriting import SectionWriting
12
12
  if TYPE_CHECKING:
13
13
  from cfinterface.versioning import VersionMatchResult
14
14
 
15
+ _SectionFileT = TypeVar("_SectionFileT", bound="SectionFile")
16
+
15
17
 
16
18
  class SectionFile:
17
19
  """
@@ -48,12 +50,12 @@ class SectionFile:
48
50
 
49
51
  @classmethod
50
52
  def read(
51
- cls,
53
+ cls: type[_SectionFileT],
52
54
  content: str | bytes,
53
55
  *args: Any,
54
56
  version: str | None = None,
55
57
  **kwargs: Any,
56
- ) -> "SectionFile":
58
+ ) -> _SectionFileT:
57
59
  """Read from a file path or buffer. ``version`` selects a component set
58
60
  from VERSIONS without mutating the class."""
59
61
  components = cls.SECTIONS
@@ -86,11 +88,11 @@ class SectionFile:
86
88
 
87
89
  @classmethod
88
90
  def read_many(
89
- cls,
91
+ cls: type[_SectionFileT],
90
92
  paths: list[str],
91
93
  *,
92
94
  version: str | None = None,
93
- ) -> dict[str, "SectionFile"]:
95
+ ) -> dict[str, _SectionFileT]:
94
96
  """Read multiple files and return a dict keyed by file path.
95
97
 
96
98
  Parameters
@@ -0,0 +1,38 @@
1
+ from pathlib import Path
2
+
3
+ import pytest
4
+ from mypy import api
5
+
6
+ SUBCLASS_READS = """
7
+ from cfinterface.files.blockfile import BlockFile
8
+ from cfinterface.files.registerfile import RegisterFile
9
+ from cfinterface.files.sectionfile import SectionFile
10
+
11
+
12
+ class MySectionFile(SectionFile):
13
+ pass
14
+
15
+
16
+ class MyRegisterFile(RegisterFile):
17
+ pass
18
+
19
+
20
+ class MyBlockFile(BlockFile):
21
+ pass
22
+
23
+
24
+ section: MySectionFile = MySectionFile.read("file.txt")
25
+ register: MyRegisterFile = MyRegisterFile.read("file.txt")
26
+ block: MyBlockFile = MyBlockFile.read("file.txt")
27
+ sections: dict[str, MySectionFile] = MySectionFile.read_many(["file.txt"])
28
+ registers: dict[str, MyRegisterFile] = MyRegisterFile.read_many(["file.txt"])
29
+ blocks: dict[str, MyBlockFile] = MyBlockFile.read_many(["file.txt"])
30
+ """
31
+
32
+
33
+ @pytest.mark.slow
34
+ def test_read_is_typed_as_returning_the_subclass(tmp_path: Path):
35
+ stdout, stderr, status = api.run(
36
+ ["--cache-dir", str(tmp_path), "-c", SUBCLASS_READS]
37
+ )
38
+ assert status == 0, stdout + stderr
File without changes
File without changes
File without changes