odoo-addons-parser 0.6__tar.gz → 0.7__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 (46) hide show
  1. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/PKG-INFO +84 -88
  2. odoo_addons_parser-0.7/README.md +112 -0
  3. odoo_addons_parser-0.7/odoo_addons_parser/data_csv.py +92 -0
  4. odoo_addons_parser-0.7/odoo_addons_parser/data_xml.py +417 -0
  5. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/module.py +54 -0
  6. odoo_addons_parser-0.7/odoo_addons_parser/tests/common.py +408 -0
  7. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/tests/repo/module_test/__manifest__.py +9 -2
  8. odoo_addons_parser-0.7/odoo_addons_parser/tests/repo/module_test/data/res_partner.xml +18 -0
  9. odoo_addons_parser-0.7/odoo_addons_parser/tests/repo/module_test/demo/res_partner.xml +10 -0
  10. odoo_addons_parser-0.7/odoo_addons_parser/tests/repo/module_test/reports/reports.xml +37 -0
  11. odoo_addons_parser-0.7/odoo_addons_parser/tests/repo/module_test/reports/templates.xml +14 -0
  12. odoo_addons_parser-0.7/odoo_addons_parser/tests/repo/module_test/security/ir.model.access.csv +2 -0
  13. odoo_addons_parser-0.7/odoo_addons_parser/tests/repo/module_test/tests/test.xml +10 -0
  14. odoo_addons_parser-0.7/odoo_addons_parser/tests/repo/module_test/views/assets.xml +12 -0
  15. odoo_addons_parser-0.7/odoo_addons_parser/tests/repo/module_test/views/res_partner.xml +52 -0
  16. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/tests/test_module.py +24 -2
  17. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/tests/test_repository.py +6 -3
  18. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser.egg-info/PKG-INFO +84 -88
  19. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser.egg-info/SOURCES.txt +9 -0
  20. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/pyproject.toml +10 -0
  21. odoo_addons_parser-0.6/README.md +0 -126
  22. odoo_addons_parser-0.6/odoo_addons_parser/tests/common.py +0 -169
  23. odoo_addons_parser-0.6/odoo_addons_parser/tests/repo/module_test/views/res_partner.xml +0 -18
  24. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/.github/workflows/pre-commit.yml +0 -0
  25. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/.github/workflows/publish.yml +0 -0
  26. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/.github/workflows/test.yml +0 -0
  27. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/.gitignore +0 -0
  28. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/.pre-commit-config.yaml +0 -0
  29. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/LICENSE +0 -0
  30. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/MANIFEST.in +0 -0
  31. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/__init__.py +0 -0
  32. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/code.py +0 -0
  33. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/odoo.py +0 -0
  34. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/repository.py +0 -0
  35. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/tests/__init__.py +0 -0
  36. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/tests/repo/module_test/__init__.py +0 -0
  37. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/tests/repo/module_test/models/__init__.py +0 -0
  38. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/tests/repo/module_test/models/res_partner.py +0 -0
  39. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/tests/repo/module_test/models/res_users.py +0 -0
  40. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/tests/test_odoo.py +0 -0
  41. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/tests/test_treesitter_utils.py +0 -0
  42. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser/treesitter_utils.py +0 -0
  43. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser.egg-info/dependency_links.txt +0 -0
  44. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser.egg-info/requires.txt +0 -0
  45. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/odoo_addons_parser.egg-info/top_level.txt +0 -0
  46. {odoo_addons_parser-0.6 → odoo_addons_parser-0.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: odoo-addons-parser
3
- Version: 0.6
3
+ Version: 0.7
4
4
  Summary: Collect data from Odoo module folders.
5
5
  Author: Sébastien Alix
6
6
  License: GNU LESSER GENERAL PUBLIC LICENSE
@@ -173,8 +173,18 @@ Project-URL: homepage, https://github.com/sebalix/odoo-addons-parser
173
173
  Project-URL: documentation, https://github.com/sebalix/odoo-addons-parser
174
174
  Project-URL: repository, https://github.com/sebalix/odoo-addons-parser
175
175
  Keywords: odoo,oca,analyze,parser,collect,modules,addons
176
+ Classifier: Intended Audience :: Developers
176
177
  Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
178
+ Classifier: Operating System :: OS Independent
179
+ Classifier: Programming Language :: Python
177
180
  Classifier: Programming Language :: Python :: 3
181
+ Classifier: Programming Language :: Python :: 3.9
182
+ Classifier: Programming Language :: Python :: 3.10
183
+ Classifier: Programming Language :: Python :: 3.11
184
+ Classifier: Programming Language :: Python :: 3.12
185
+ Classifier: Programming Language :: Python :: 3.13
186
+ Classifier: Programming Language :: Python :: 3.14
187
+ Classifier: Programming Language :: Python :: 3 :: Only
178
188
  Classifier: Framework :: Odoo
179
189
  Requires-Python: >=3.9
180
190
  Description-Content-Type: text/markdown
@@ -187,24 +197,40 @@ Requires-Dist: pytest; extra == "test"
187
197
  Requires-Dist: coverage; extra == "test"
188
198
  Dynamic: license-file
189
199
 
200
+ # odoo-addons-parser
201
+
202
+ [![Version](https://img.shields.io/pypi/v/odoo-addons-parser.svg?maxAge=86400)](https://pypi.org/project/odoo-addons-parser)
203
+ [![Supported Versions](https://img.shields.io/pypi/pyversions/odoo-addons-parser.svg)](https://pypi.org/project/odoo-addons-parser)
190
204
  [![Pre-commit Status](https://github.com/sebalix/odoo-addons-parser/actions/workflows/pre-commit.yml/badge.svg?branch=main)](https://github.com/sebalix/odoo-addons-parser/actions/workflows/pre-commit.yml?query=branch%3Amain)
191
205
  [![Tests Status](https://github.com/sebalix/odoo-addons-parser/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/sebalix/odoo-addons-parser/actions/workflows/test.yml?query=branch%3Amain)
192
- [![Last version](https://img.shields.io/pypi/v/odoo-addons-parser)](https://pypi.org/project/odoo-addons-parser/)
193
206
 
194
- # odoo-addons-parser
207
+ Python package to collect and analyze data from Odoo module folders without requiring an Odoo runtime. It performs static file analysis to extract useful information from Odoo modules.
208
+
209
+ ## Features
210
+
211
+ - **Static Analysis**: Doesn't rely on any Odoo runtime; performs static files analysis
212
+ - **Code Statistics**: Count lines of code (Python, XML, JavaScript, and CSS)
213
+ - **Manifest Parsing**: Extract useful data from manifest files (authors, dependencies, etc.)
214
+ - **Model Extraction**: Extract Odoo models information (with fields and methods)
215
+ - **Data Extraction**: Extract data from XML and CSV files
216
+ - **Flexible Scanning**: Scan individual modules, repositories, or entire Odoo source code
195
217
 
196
- Python package to collect data from Odoo module folders.
218
+ ## Installation
197
219
 
198
- Features:
220
+ ```bash
221
+ uv pip install odoo-addons-parser
222
+ ```
223
+
224
+ Or with pip:
225
+ ```bash
226
+ pip install odoo-addons-parser
227
+ ```
199
228
 
200
- - scan an Odoo repository, a folder of modules (repository) or a module only
201
- - count the number of lines of code (Python, XML, JavaScript and CSS by default)
202
- - read the manifest file (to get useful data like authors or dependencies)
203
- - extract Odoo models info (fields, methods...)
229
+ ## Usage
204
230
 
205
- ## ModuleParser class
231
+ ### ModuleParser
206
232
 
207
- `ModuleParser` class aims to scan a module folder only:
233
+ Parse a single Odoo module:
208
234
 
209
235
  ```python
210
236
  from odoo_addons_parser import ModuleParser
@@ -213,103 +239,73 @@ from pprint import pprint as pp
213
239
  mod = ModuleParser("/path/to/OCA/server-tools/server_environment")
214
240
  pp(mod.to_dict())
215
241
  ```
216
- =>
242
+
243
+ Example output:
244
+
217
245
  ```python
218
- {'code': {'CSS': 0, 'JavaScript': 0, 'Python': 541, 'XML': 21},
219
- 'manifest': {'author': 'Camptocamp,Odoo Community Association (OCA)',
220
- 'category': 'Tools',
221
- 'data': ['security/ir.model.access.csv',
222
- 'security/res_groups.xml',
223
- 'serv_config.xml'],
224
- 'depends': ['base', 'base_sparse_field'],
225
- 'installable': True,
226
- 'license': 'GPL-3 or any later version',
227
- 'name': 'server configuration environment files',
228
- 'summary': 'move some configurations out of the database',
229
- 'version': '14.0.1.0.0',
230
- 'website': 'https://github.com/OCA/server-env'}},
231
- 'models': ...
232
- 'name': 'server_environment',
246
+ {
247
+ 'code': {'CSS': 0, 'JavaScript': 0, 'Python': 541, 'XML': 21},
248
+ 'manifest': {
249
+ 'author': 'Camptocamp,Odoo Community Association (OCA)',
250
+ 'category': 'Tools',
251
+ 'data': ['security/ir.model.access.csv', 'security/res_groups.xml', 'serv_config.xml'],
252
+ 'depends': ['base', 'base_sparse_field'],
253
+ 'installable': True,
254
+ 'license': 'GPL-3 or any later version',
255
+ 'name': 'server configuration environment files',
256
+ 'summary': 'move some configurations out of the database',
257
+ 'version': '14.0.1.0.0',
258
+ 'website': 'https://github.com/OCA/server-env'
259
+ },
260
+ 'models': ...,
261
+ 'name': 'server_environment'
262
+ }
233
263
  ```
234
264
 
235
- ## RepositoryParser class
265
+ ### RepositoryParser
236
266
 
237
- `RepositoryParser` class aims to scan a whole repository of addons
238
- (also named *addons path*):
267
+ Parse a whole repository of addons:
239
268
 
240
269
  ```python
241
270
  from odoo_addons_parser import RepositoryParser
271
+
242
272
  repo = RepositoryParser("/path/to/OCA/server-tools")
243
273
  pp(repo.to_dict())
244
274
  ```
245
- =>
246
- ```python
247
- {'data_encryption': {'code': {'CSS': 0,
248
- 'JavaScript': 0,
249
- 'Python': 187,
250
- 'XML': 0},
251
- 'manifest': {'application': False,
252
- 'author': 'Akretion, Odoo Community '
253
- 'Association (OCA)',
254
- 'category': 'Tools',
255
- 'data': ['security/ir.model.access.csv'],
256
- 'depends': ['base'],
257
- 'development_status': 'Alpha',
258
- 'external_dependencies': {'python': ['cryptography']},
259
- 'installable': True,
260
- 'license': 'AGPL-3',
261
- 'name': 'Encryption data',
262
- 'summary': 'Store accounts and credentials '
263
- 'encrypted by environment',
264
- 'version': '14.0.1.0.0',
265
- 'website': 'https://github.com/OCA/server-env'},
266
- 'models': ...,
267
- 'name': 'data_encryption'},
268
- 'mail_environment': {'code': {'CSS': 0,
269
- 'JavaScript': 0,
270
- 'Python': 43,
271
- 'XML': 0},
272
- 'manifest': {'author': 'Camptocamp, Odoo Community '
273
- 'Association (OCA)',
274
- 'category': 'Tools',
275
- 'depends': ['fetchmail',
276
- 'server_environment'],
277
- 'license': 'AGPL-3',
278
- 'name': 'Mail configuration with '
279
- 'server_environment',
280
- 'summary': 'Configure mail servers with '
281
- 'server_environment_files',
282
- 'version': '14.0.1.0.0',
283
- 'website': 'https://github.com/OCA/server-env'},
284
- 'models': ...,
285
- 'name': 'mail_environment'},
286
- [...]
287
- ```
288
275
 
289
- ## OdooParser class
276
+ ### OdooParser
290
277
 
291
- `OdooParser` special class aims to scan the Odoo source code repository
292
- (the one we clone from https://github.com/odoo/odoo). It'll parse the content
293
- of `./odoo/addons`, `./addons` and Odoo base classes such as `BaseModel`,
294
- `Model` and `TransientModel`:
278
+ Parse the Odoo source code repository:
295
279
 
296
280
  ```python
297
- >>> from odoo_addons_parser import OdooParser
298
- >>> odoo = OdooParser("/path/to/odoo/odoo")
299
- >>> data = odoo.to_dict()
300
- >>> list(data["__odoo__"]["models"])
301
- ["BaseModel", "Model", "TransientModel"]
302
- >>> "res.partner" in data["base"]["models"]
303
- True
281
+ from odoo_addons_parser import OdooParser
282
+
283
+ odoo = OdooParser("/path/to/odoo/odoo")
284
+ data = odoo.to_dict()
285
+ list(data["__odoo__"]["models"])
286
+ # ["BaseModel", "Model", "TransientModel"]
287
+ "res.partner" in data["base"]["models"]
288
+ # True
304
289
  ```
305
290
 
306
291
  ## Parameters
307
292
 
308
- Code stats or models scanning can be disabled thanks to `code_stats` and
309
- `scan_models` parameters, available on all classes:
293
+ You can disable specific features using parameters:
310
294
 
311
295
  ```python
296
+ # Disable code statistics
312
297
  repo = RepositoryParser("path/to/addons_path", code_stats=False)
298
+
299
+ # Disable model scanning
313
300
  mod = ModuleParser("path/to/addons_path/module", scan_models=False)
314
- odoo = OdooParser("path/to/odoo/odoo", code_stats=False)
301
+
302
+ # Disable data scanning
303
+ mod = ModuleParser("path/to/addons_path/module", scan_data=False)
304
+
305
+ # Disable all
306
+ odoo = OdooParser("/path/to/odoo/odoo", code_stats=False, scan_models=False, scan_data=False)
315
307
  ```
308
+
309
+ ## License
310
+
311
+ This project is licensed under the LGPL-3.0 License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,112 @@
1
+ # odoo-addons-parser
2
+
3
+ [![Version](https://img.shields.io/pypi/v/odoo-addons-parser.svg?maxAge=86400)](https://pypi.org/project/odoo-addons-parser)
4
+ [![Supported Versions](https://img.shields.io/pypi/pyversions/odoo-addons-parser.svg)](https://pypi.org/project/odoo-addons-parser)
5
+ [![Pre-commit Status](https://github.com/sebalix/odoo-addons-parser/actions/workflows/pre-commit.yml/badge.svg?branch=main)](https://github.com/sebalix/odoo-addons-parser/actions/workflows/pre-commit.yml?query=branch%3Amain)
6
+ [![Tests Status](https://github.com/sebalix/odoo-addons-parser/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/sebalix/odoo-addons-parser/actions/workflows/test.yml?query=branch%3Amain)
7
+
8
+ Python package to collect and analyze data from Odoo module folders without requiring an Odoo runtime. It performs static file analysis to extract useful information from Odoo modules.
9
+
10
+ ## Features
11
+
12
+ - **Static Analysis**: Doesn't rely on any Odoo runtime; performs static files analysis
13
+ - **Code Statistics**: Count lines of code (Python, XML, JavaScript, and CSS)
14
+ - **Manifest Parsing**: Extract useful data from manifest files (authors, dependencies, etc.)
15
+ - **Model Extraction**: Extract Odoo models information (with fields and methods)
16
+ - **Data Extraction**: Extract data from XML and CSV files
17
+ - **Flexible Scanning**: Scan individual modules, repositories, or entire Odoo source code
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ uv pip install odoo-addons-parser
23
+ ```
24
+
25
+ Or with pip:
26
+ ```bash
27
+ pip install odoo-addons-parser
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ### ModuleParser
33
+
34
+ Parse a single Odoo module:
35
+
36
+ ```python
37
+ from odoo_addons_parser import ModuleParser
38
+ from pprint import pprint as pp
39
+
40
+ mod = ModuleParser("/path/to/OCA/server-tools/server_environment")
41
+ pp(mod.to_dict())
42
+ ```
43
+
44
+ Example output:
45
+
46
+ ```python
47
+ {
48
+ 'code': {'CSS': 0, 'JavaScript': 0, 'Python': 541, 'XML': 21},
49
+ 'manifest': {
50
+ 'author': 'Camptocamp,Odoo Community Association (OCA)',
51
+ 'category': 'Tools',
52
+ 'data': ['security/ir.model.access.csv', 'security/res_groups.xml', 'serv_config.xml'],
53
+ 'depends': ['base', 'base_sparse_field'],
54
+ 'installable': True,
55
+ 'license': 'GPL-3 or any later version',
56
+ 'name': 'server configuration environment files',
57
+ 'summary': 'move some configurations out of the database',
58
+ 'version': '14.0.1.0.0',
59
+ 'website': 'https://github.com/OCA/server-env'
60
+ },
61
+ 'models': ...,
62
+ 'name': 'server_environment'
63
+ }
64
+ ```
65
+
66
+ ### RepositoryParser
67
+
68
+ Parse a whole repository of addons:
69
+
70
+ ```python
71
+ from odoo_addons_parser import RepositoryParser
72
+
73
+ repo = RepositoryParser("/path/to/OCA/server-tools")
74
+ pp(repo.to_dict())
75
+ ```
76
+
77
+ ### OdooParser
78
+
79
+ Parse the Odoo source code repository:
80
+
81
+ ```python
82
+ from odoo_addons_parser import OdooParser
83
+
84
+ odoo = OdooParser("/path/to/odoo/odoo")
85
+ data = odoo.to_dict()
86
+ list(data["__odoo__"]["models"])
87
+ # ["BaseModel", "Model", "TransientModel"]
88
+ "res.partner" in data["base"]["models"]
89
+ # True
90
+ ```
91
+
92
+ ## Parameters
93
+
94
+ You can disable specific features using parameters:
95
+
96
+ ```python
97
+ # Disable code statistics
98
+ repo = RepositoryParser("path/to/addons_path", code_stats=False)
99
+
100
+ # Disable model scanning
101
+ mod = ModuleParser("path/to/addons_path/module", scan_models=False)
102
+
103
+ # Disable data scanning
104
+ mod = ModuleParser("path/to/addons_path/module", scan_data=False)
105
+
106
+ # Disable all
107
+ odoo = OdooParser("/path/to/odoo/odoo", code_stats=False, scan_models=False, scan_data=False)
108
+ ```
109
+
110
+ ## License
111
+
112
+ This project is licensed under the LGPL-3.0 License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,92 @@
1
+ # Copyright 2023 Sebastien Alix <https://github.com/sebalix>
2
+ # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
3
+
4
+ import csv
5
+ import logging
6
+ import pathlib
7
+ from typing import Any, Dict, List, Optional
8
+
9
+ _logger = logging.getLogger(__name__)
10
+
11
+
12
+ class CsvParseError(Exception):
13
+ """Exception raised for CSV parsing errors."""
14
+
15
+ pass
16
+
17
+
18
+ class CsvFile:
19
+ """Parse and extract data from Odoo CSV files."""
20
+
21
+ def __init__(
22
+ self, module_path: pathlib.Path, file_path: pathlib.Path, loaded: bool = False
23
+ ):
24
+ self.module_path = module_path
25
+ self.module_name = self.module_path.name
26
+ self.file_path = file_path
27
+ self.relative_file_path = self.file_path.relative_to(self.module_path)
28
+ self.loaded = loaded
29
+ self.model_name = self._extract_model_name()
30
+ self.records = self._parse_csv()
31
+
32
+ def _extract_model_name(self) -> str:
33
+ """Extract model name from filename.
34
+
35
+ E.g. 'res.country.csv' -> 'res.country'.
36
+ """
37
+ if self.file_path.name.endswith(".csv"):
38
+ return self.file_path.stem
39
+ raise CsvParseError(f"Invalid CSV filename: {self.file_path.name}")
40
+
41
+ def _parse_csv(self) -> List[Dict[str, Any]]:
42
+ """Parse CSV file and return list of records."""
43
+ records = []
44
+ try:
45
+ with open(self.file_path, "r", encoding="utf-8") as file_:
46
+ reader = csv.DictReader(file_)
47
+ for row_num, row in enumerate(reader, start=2):
48
+ try:
49
+ record = self._process_row(row, row_num)
50
+ if record:
51
+ records.append(record)
52
+ except Exception as e:
53
+ _logger.warning(
54
+ f"Error processing row {row_num} in {self.file_path}: {e}"
55
+ )
56
+ continue
57
+ except Exception as e:
58
+ raise CsvParseError(f"Error reading CSV file {self.file_path}: {e}")
59
+ return records
60
+
61
+ def _process_row(
62
+ self, row: Dict[str, str], row_num: int
63
+ ) -> Optional[Dict[str, Any]]:
64
+ """Process a single CSV row into a structured record."""
65
+ if not row:
66
+ return None
67
+ # Extract data from row
68
+ data = {}
69
+ for field_name, value in row.items():
70
+ if ":" in field_name:
71
+ # Handle field references like "country_id:id"
72
+ base_field = field_name.split(":")[0]
73
+ data[base_field] = value
74
+ else:
75
+ data[field_name] = value
76
+ # Validate required fields
77
+ if "id" not in data:
78
+ _logger.warning(f"Row {row_num} missing 'id' field in {self.file_path}")
79
+ return None
80
+ # Create structured record
81
+ record = {
82
+ "id": data["id"],
83
+ "model": self.model_name,
84
+ "file_path": str(self.relative_file_path),
85
+ "data": data,
86
+ "loaded": self.loaded,
87
+ }
88
+ return record
89
+
90
+ def to_dict(self) -> Dict[str, List[Dict[str, Any]]]:
91
+ """Convert parsed CSV data to dictionary format."""
92
+ return {self.model_name: self.records}