Skip to content

Commit 23eec76

Browse files
committed
Support RP1.0 without extension Taxonomy #73
1 parent 893db03 commit 23eec76

4 files changed

Lines changed: 145 additions & 91 deletions

File tree

src/xbrl_forge/__init__.py

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,9 @@
55
from .logger_setup import logger_conf
66
logger_conf()
77

8-
from .xbrl_generation.ContentDataclasses import ContentDocument
9-
from .xbrl_generation.XbrlProducer import XbrlProducer
108
from .xbrl_generation.PackageDataclasses import File
119
from .xbrl_generation.InputData import InputData
12-
from .xbrl_generation.HtmlProducer import HtmlProducer
13-
from .xbrl_generation.TaxonomyProducer import TaxonomyProducer
10+
from .xbrl_generation.PackageProducer import PackageProducer
1411
from .utils.schema_validation import validate_schema
1512
from .file_conversion import doc_to_data
1613

@@ -39,49 +36,5 @@ def create_xbrl(input_data_list: List[InputData], xthml_template: str = None) ->
3936
logger.info(f"Creating XBRL")
4037
# load data
4138
loaded_data: InputData = InputData.combine(input_data_list)
42-
local_namespace = None
43-
local_namespace_prefix = None
44-
local_taxonomy_schema = None
45-
if loaded_data.taxonomy:
46-
local_namespace=loaded_data.taxonomy.namespace
47-
local_namespace_prefix=loaded_data.taxonomy.prefix
48-
local_taxonomy_schema=loaded_data.taxonomy.schema_url
49-
reports_folder: File = None
50-
untagged_reports_folder: File = None
51-
inline_instances: int = 0
52-
non_inline_instances: int = 0
53-
for report in loaded_data.reports:
54-
if not reports_folder:
55-
reports_folder = File("reports", contained_files=[])
56-
if report.xhtml:
57-
html_producer: HtmlProducer = HtmlProducer(
58-
report,
59-
xthml_template=xthml_template,
60-
local_namespace=local_namespace,
61-
local_namespace_prefix=local_namespace_prefix,
62-
local_taxonomy_schema=local_taxonomy_schema
63-
)
64-
if html_producer.ixbrl:
65-
reports_folder.contained_files.append(html_producer.create_html())
66-
inline_instances += 1
67-
else:
68-
if not untagged_reports_folder:
69-
untagged_reports_folder: File = File("untagged_reports", contained_files=[])
70-
reports_folder.contained_files.append(untagged_reports_folder)
71-
untagged_reports_folder.contained_files.append(html_producer.create_html())
72-
else:
73-
xbrl_producer: XbrlProducer = XbrlProducer(
74-
report,
75-
local_namespace=local_namespace,
76-
local_namespace_prefix=local_namespace_prefix,
77-
local_taxonomy_schema=local_taxonomy_schema
78-
)
79-
reports_folder.contained_files.append(xbrl_producer.create_xbrl())
80-
non_inline_instances += 1
81-
if not loaded_data.taxonomy:
82-
return reports_folder
83-
taxonomy_producer: TaxonomyProducer = TaxonomyProducer(loaded_data.taxonomy)
84-
package_extension: str = "zip"
85-
if inline_instances == 1 and non_inline_instances == 0: package_extension = "xbri"
86-
if inline_instances == 0 and non_inline_instances == 1: package_extension = "xbr"
87-
return taxonomy_producer.create_files(reports_folder, package_extension)
39+
producer: PackageProducer = PackageProducer(loaded_data, xthml_template=xthml_template)
40+
return producer.get_package()

src/xbrl_forge/xbrl_generation/PackageDataclasses.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,19 @@
99

1010
logger = logging.getLogger(__name__)
1111

12+
@dataclass
13+
class PACKAGE_EXTENSIONS:
14+
ZIP: str = "zip"
15+
XBRI: str = "xbri"
16+
XBR: str = "xbr"
17+
1218
class File:
1319
name: str
1420
content: str
1521
contained_files: List['File']
1622
zip_extension: str
1723

18-
def __init__(cls, name: str, content: str = None, contained_files: List['File'] = None, zip_extension: str = "zip"):
24+
def __init__(cls, name: str, content: str = None, contained_files: List['File'] = None, zip_extension: str = PACKAGE_EXTENSIONS.ZIP):
1925
cls.name = name
2026
cls.content = content
2127
cls.contained_files = [] if contained_files == None else contained_files
@@ -119,4 +125,4 @@ def to_dict(cls) -> dict:
119125
return {
120126
"schema_location": cls.schema_location,
121127
"element_id": cls.element_id
122-
}
128+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import json
2+
3+
from typing import List, Dict
4+
5+
from .PackageDataclasses import File, PACKAGE_EXTENSIONS
6+
from .InputData import InputData
7+
from .HtmlProducer import HtmlProducer
8+
from .XbrlProducer import XbrlProducer
9+
from .TaxonomyProducer import TaxonomyProducer
10+
11+
PACKAGE_EXTENSION_URIS: Dict[str, str] = {
12+
PACKAGE_EXTENSIONS.ZIP: "https://xbrl.org/report-package/2023",
13+
PACKAGE_EXTENSIONS.XBRI: "https://xbrl.org/report-package/2023/xbri",
14+
PACKAGE_EXTENSIONS.XBR: "https://xbrl.org/report-package/2023/xbr"
15+
}
16+
17+
class PackageProducer:
18+
local_namespace: str
19+
local_namespace_prefix: str
20+
local_taxonomy_schema: str
21+
root_folder: File
22+
23+
def __init__(cls, input_data: InputData, xthml_template: str = None):
24+
# get namespace data
25+
cls.local_namespace = None
26+
cls.local_namespace_prefix = None
27+
cls.local_taxonomy_schema = None
28+
if input_data.taxonomy:
29+
cls.local_namespace=input_data.taxonomy.namespace
30+
cls.local_namespace_prefix=input_data.taxonomy.prefix
31+
cls.local_taxonomy_schema=input_data.taxonomy.schema_url
32+
# create reports
33+
inline_xbrl_reports: List[File] = []
34+
xbrl_reports: List[File] = []
35+
xhtml_reports: List[File] = []
36+
for report in input_data.reports:
37+
if report.xhtml:
38+
html_producer: HtmlProducer = HtmlProducer(
39+
report,
40+
xthml_template=xthml_template,
41+
local_namespace=cls.local_namespace,
42+
local_namespace_prefix=cls.local_namespace_prefix,
43+
local_taxonomy_schema=cls.local_taxonomy_schema
44+
)
45+
if html_producer.ixbrl:
46+
inline_xbrl_reports.append(html_producer.create_html())
47+
else:
48+
xhtml_reports.append(html_producer.create_html())
49+
else:
50+
xbrl_producer: XbrlProducer = XbrlProducer(
51+
report,
52+
local_namespace=cls.local_namespace,
53+
local_namespace_prefix=cls.local_namespace_prefix,
54+
local_taxonomy_schema=cls.local_taxonomy_schema
55+
)
56+
xbrl_reports.append(xbrl_producer.create_xbrl())
57+
# create taxonomy
58+
taxonomy_meta_inf_files: List[File] = []
59+
taxonomy_folder: File = None
60+
if input_data.taxonomy:
61+
taxonomy_producer: TaxonomyProducer = TaxonomyProducer(input_data.taxonomy)
62+
taxonomy_meta_inf_files = taxonomy_producer.get_meta_inf_files()
63+
taxonomy_folder = taxonomy_producer.get_taxonomy()
64+
65+
package_extension: str = PACKAGE_EXTENSIONS.ZIP
66+
if len(inline_xbrl_reports) == 1 and not xbrl_reports:
67+
package_extension = PACKAGE_EXTENSIONS.XBRI
68+
elif len(xbrl_reports) == 1 and not inline_xbrl_reports:
69+
package_extension = PACKAGE_EXTENSIONS.XBR
70+
71+
# create base folder
72+
root_folder_name: str = "EMPTY"
73+
if input_data.taxonomy:
74+
root_folder_name = f'{"_".join(input_data.taxonomy.metadata.name.split())}'
75+
elif inline_xbrl_reports:
76+
root_folder_name = inline_xbrl_reports[0].name.split(".")[0]
77+
elif xbrl_reports:
78+
root_folder_name = xbrl_reports[0].name.split(".")[0]
79+
elif xhtml_reports:
80+
root_folder_name = xhtml_reports[0].name.split(".")[0]
81+
cls.root_folder: File = File(name=root_folder_name, zip_extension=package_extension)
82+
83+
# add content
84+
meta_inf_folder: File = File(name="META-INF", contained_files=taxonomy_meta_inf_files)
85+
cls.root_folder.contained_files.append(meta_inf_folder)
86+
if taxonomy_folder:
87+
cls.root_folder.contained_files.append(taxonomy_folder)
88+
if xbrl_reports or inline_xbrl_reports or xhtml_reports:
89+
reports_folder: File = File("reports", contained_files=xbrl_reports + inline_xbrl_reports)
90+
cls.root_folder.contained_files.append(reports_folder)
91+
if xhtml_reports:
92+
untagged_reports_folder: File = File("untagged_reports", contained_files=xhtml_reports)
93+
reports_folder.contained_files.append(untagged_reports_folder)
94+
# add reportPackage.json
95+
meta_inf_folder.contained_files.append(File(
96+
name="reportPackage.json",
97+
content=json.dumps({
98+
"documentInfo": {
99+
"documentType": PACKAGE_EXTENSION_URIS.get(package_extension)
100+
}
101+
})
102+
))
103+
104+
def get_package(cls) -> File:
105+
return cls.root_folder

src/xbrl_forge/xbrl_generation/TaxonomyProducer.py

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,34 @@
3131

3232
class TaxonomyProducer:
3333
taxonomy_document: TaxonomyDocument
34+
taxonomy_root_folder: File
35+
taxonomy_folder: File
36+
meta_inf_files: List[File]
3437

3538
def __init__(cls, document: TaxonomyDocument):
3639
cls.taxonomy_document = document
37-
38-
def create_files(cls, reports_folder: File = None, package_extension: str = "zip") -> File:
39-
# create base folder structure
40-
root_folder = File(name=f'{"_".join(cls.taxonomy_document.metadata.name.split())}', zip_extension=package_extension)
41-
if reports_folder:
42-
root_folder.contained_files.append(reports_folder)
40+
cls.taxonomy_root_folder = None
41+
cls.taxonomy_folder = None
4342
# create taxonomy files
44-
taxonomy_folder = root_folder
4543
for part in cls.taxonomy_document.rewrite_path:
46-
parent_folder = taxonomy_folder
47-
taxonomy_folder = File(name=part)
48-
parent_folder.contained_files.append(taxonomy_folder)
49-
cls._create_taxonomy_files(taxonomy_folder)
50-
# create meta information
51-
meta_inf_folder = File(name="META-INF", contained_files=cls._create_meta_inf_files(package_extension if reports_folder else None))
52-
root_folder.contained_files.append(meta_inf_folder)
53-
return root_folder
44+
if not cls.taxonomy_root_folder:
45+
cls.taxonomy_root_folder = File(name=part)
46+
cls.taxonomy_folder = cls.taxonomy_root_folder
47+
else:
48+
parent_folder = cls.taxonomy_folder
49+
cls.taxonomy_folder = File(name=part)
50+
parent_folder.contained_files.append(cls.taxonomy_folder)
51+
cls._create_taxonomy_files()
52+
cls.meta_inf_files = []
53+
cls._create_meta_inf_files()
54+
55+
def get_taxonomy(cls) -> File:
56+
return cls.taxonomy_root_folder
57+
58+
def get_meta_inf_files(cls) -> List[File]:
59+
return cls.meta_inf_files
5460

55-
def _create_meta_inf_files(cls, package_extension: str = None) -> List[File]:
61+
def _create_meta_inf_files(cls) -> List[File]:
5662
# create catalog file
5763
catalog_namespace: str = "urn:oasis:names:tc:entity:xmlns:xml:catalog"
5864
catalog_namespace_map = {
@@ -160,7 +166,7 @@ def _create_meta_inf_files(cls, package_extension: str = None) -> List[File]:
160166
)
161167
ep_lang_element.text = entrypoint.language
162168

163-
return_files: List[File] = [
169+
cls.meta_inf_files = [
164170
File(
165171
name="catalog.xml",
166172
content=xml_to_string(
@@ -176,52 +182,36 @@ def _create_meta_inf_files(cls, package_extension: str = None) -> List[File]:
176182
)
177183
]
178184

179-
if package_extension:
180-
supported_package_extensions: Dict[str, str] = {
181-
"zip": "https://xbrl.org/report-package/2023",
182-
"xbri": "https://xbrl.org/report-package/2023/xbri",
183-
"xbr": "https://xbrl.org/report-package/2023/xbr"
184-
}
185-
return_files.append(File(
186-
name="reportPackage.json",
187-
content=json.dumps({
188-
"documentInfo": {
189-
"documentType": supported_package_extensions.get(package_extension)
190-
}
191-
})
192-
))
193-
return return_files
194-
195-
def _create_taxonomy_files(cls, taxonomy_folder: File) -> None:
185+
def _create_taxonomy_files(cls) -> None:
196186
logger.debug(f"Creating taxonomy schema for namespace {cls.taxonomy_document.namespace}")
197-
cls._create_schema(taxonomy_folder)
187+
cls._create_schema(cls.taxonomy_folder)
198188
presentation_linkbase_filename: str = f"{cls.taxonomy_document.files_base_name}_pre.xml"
199189
logger.debug(f"Creating presentation linkbase {presentation_linkbase_filename}")
200190
cls._create_linkbase(
201191
presentation_linkbase_filename,
202-
taxonomy_folder,
192+
cls.taxonomy_folder,
203193
cls._create_presentation()
204194
)
205195
calculation_linkbase_filename: str = f"{cls.taxonomy_document.files_base_name}_cal.xml"
206196
logger.debug(f"Creating calculation linkbase {calculation_linkbase_filename}")
207197
cls._create_linkbase(
208198
calculation_linkbase_filename,
209-
taxonomy_folder,
199+
cls.taxonomy_folder,
210200
cls._create_calculation()
211201
)
212202
definition_linkbase_filename: str = f"{cls.taxonomy_document.files_base_name}_def.xml"
213203
logger.debug(f"Creating defintion linkbase {definition_linkbase_filename}")
214204
cls._create_linkbase(
215205
definition_linkbase_filename,
216-
taxonomy_folder,
206+
cls.taxonomy_folder,
217207
cls._create_definition()
218208
)
219209
for labels_lang in cls.taxonomy_document.labels:
220210
label_linkbase_filename: str = f"{cls.taxonomy_document.files_base_name}_lab-{labels_lang}.xml"
221211
logger.debug(f"Creating label linkbase language {labels_lang} {label_linkbase_filename}")
222212
cls._create_linkbase(
223213
label_linkbase_filename,
224-
taxonomy_folder,
214+
cls.taxonomy_folder,
225215
cls._create_label_linkbase(labels_lang)
226216
)
227217

0 commit comments

Comments
 (0)