arelle-release 2.37.56__py3-none-any.whl → 2.37.58__py3-none-any.whl

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.

Potentially problematic release.


This version of arelle-release might be problematic. Click here for more details.

Files changed (27) hide show
  1. arelle/Cntlr.py +1 -0
  2. arelle/CntlrCmdLine.py +1 -0
  3. arelle/DialogPluginManager.py +6 -4
  4. arelle/ErrorManager.py +7 -1
  5. arelle/PluginManager.py +129 -100
  6. arelle/ValidateDuplicateFacts.py +1 -1
  7. arelle/XbrlConst.py +1 -0
  8. arelle/_version.py +2 -2
  9. arelle/plugin/validate/EDINET/Constants.py +19 -18
  10. arelle/plugin/validate/EDINET/ControllerPluginData.py +11 -4
  11. arelle/plugin/validate/EDINET/CoverPageRequirements.py +118 -0
  12. arelle/plugin/validate/EDINET/FilingFormat.py +253 -0
  13. arelle/plugin/validate/EDINET/FormType.py +81 -0
  14. arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +171 -33
  15. arelle/plugin/validate/EDINET/resources/cover-page-requirements.csv +27 -0
  16. arelle/plugin/validate/EDINET/rules/edinet.py +1 -1
  17. arelle/plugin/validate/EDINET/rules/gfm.py +271 -2
  18. arelle/plugin/validate/EDINET/rules/upload.py +183 -10
  19. arelle/plugin/validate/ROS/PluginValidationDataExtension.py +2 -0
  20. arelle/plugin/validate/ROS/ValidationPluginExtension.py +1 -0
  21. arelle/plugin/validate/ROS/rules/ros.py +37 -7
  22. {arelle_release-2.37.56.dist-info → arelle_release-2.37.58.dist-info}/METADATA +1 -1
  23. {arelle_release-2.37.56.dist-info → arelle_release-2.37.58.dist-info}/RECORD +27 -23
  24. {arelle_release-2.37.56.dist-info → arelle_release-2.37.58.dist-info}/WHEEL +0 -0
  25. {arelle_release-2.37.56.dist-info → arelle_release-2.37.58.dist-info}/entry_points.txt +0 -0
  26. {arelle_release-2.37.56.dist-info → arelle_release-2.37.58.dist-info}/licenses/LICENSE.md +0 -0
  27. {arelle_release-2.37.56.dist-info → arelle_release-2.37.58.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,253 @@
1
+ """
2
+ See COPYRIGHT.md for copyright information.
3
+ """
4
+ from __future__ import annotations
5
+
6
+ from dataclasses import dataclass
7
+ from enum import Enum
8
+
9
+ from .FormType import FormType
10
+
11
+
12
+ class Ordinance(Enum):
13
+ # The below values are based on the "府令" ("Ordinance") column
14
+ # of Table 2-3-1 in "Framework Design of EDINET Taxonomy" (ESE140301.pdf).
15
+ DISCLOSURE = '開示府令'
16
+ SPECIFIED_SECURITIES_DISCLOSURE = '特定有価証券開示府令'
17
+ OTHER_SHARE_PURCHASE_TENDER_OFFER = '他社株買付府令'
18
+ OWN_SHARE_PURCHASE_TENDER_OFFER = '自社株買付府令'
19
+ LARGE_SHAREHOLDING = '大量保有府令'
20
+ INTERNAL_CONTROL = '内部統制府令'
21
+
22
+
23
+ class DocumentType(Enum):
24
+ # The below values are based on the "書類種別" ("Document Type") column
25
+ # of Table 2-3-1 in "Framework Design of EDINET Taxonomy" (ESE140301.pdf).
26
+ ANNUAL_SECURITIES_REPORT = '有価証券報告書'
27
+ EXTRAORDINARY_REPORT = '臨時報告書'
28
+ INTERNAL_CONTROL_REPORT = '内部統制報告書'
29
+ LARGE_SHAREHOLDING_REPORT = '大量保有報告書'
30
+ OPINION_STATEMENT = '意見表明報告書'
31
+ REPORT_ON_STATUS_OF_OWN_SHARE_REPURCHASE = '自己株券買付状況報告書'
32
+ RESPONSE_TO_QUESTIONS_REPORT = '対質問回答報告書'
33
+ SECURITIES_REGISTRATION_STATEMENT = '有価証券届出書'
34
+ SEMI_ANNUAL_REPORT = '半期報告書'
35
+ SHELF_REGISTRATION_STATEMENT = '発行登録書'
36
+ SHELF_REGISTRATION_SUPPLEMENT = '発行登録追補書類'
37
+ TENDER_OFFER_REPORT = '公開買付報告書'
38
+ TENDER_OFFER_STATEMENT = '公開買付届出書'
39
+ WITHDRAWAL_OF_TENDER_OFFER_STATEMENT = '公開買付撤回届出書'
40
+
41
+
42
+ class Taxonomy(Enum):
43
+ # The order of the below taxonomy values is based on Table 2-3-1 in
44
+ # "Framework Design of EDINET Taxonomy" (ESE140301.pdf).The same table was used to
45
+ # determine the applicable taxonomies in the FilingFormat configurations below.
46
+ # The prefixes associated with each taxonomy were inferred from the above
47
+ # document and "(Appendix) Conventions and Rules for EDINET Taxonomy" (ESE140304.pdf)
48
+ DEI = 'jpdei' # 'DEIタクソノミ'
49
+ FINANCIAL_STATEMENT = 'jppfs' # '財務諸表本表タクソノミ'
50
+ IFRS = 'jpigp' # 国際会計基準タクソノミ
51
+ DISCLOSURE_ORDINANCE = 'jpcrp' # '開示府令タクソノミ'
52
+ EXTRAORDINARY_REPORT = 'jpcrp-esr' # '臨時報告書タクソノミ'
53
+ STATUS_OF_SHARE_BUYBACKS = 'jpsps-esr' # '自己株券買付状況報告書タクソノミ'
54
+ CABINET_OFFICE_ORDINANCE_ON_SPECIFIED_SECURITIES_DISCLOSURE = 'jpsps' # '特定有価証券開示府令タクソノミ'
55
+ STATUS_OF_SPECIFIC_SECURITIES_TREASURY_STOCK_PURCHASES = 'jpsps-sbr' # '特定有価証券自己株券買付状況報告書タクソノミ'
56
+ SPECIFIED_SECURITIES_EXTRAORDINARY_REPORT = 'jpsps-esr' # '特定有価証券臨時報告書タクソノミ'
57
+ TENDER_OFFER_NOTIFICATION = 'jptoo-ton' # '他社株公開買付届出書タクソノミ'
58
+ OTHER_COMPANY_OPINION_STATEMENT = 'jptoo-pst' # '他社株意見表明報告書タクソノミ'
59
+ TENDER_OFFER_WITHDRAWAL_NOTIFICATION = 'jptoo-wto' # '他社株公開買付撤回届出書タクソノミ'
60
+ TENDER_OFFER_REPORT = 'jptoo-tor' # '他社株公開買付報告書タクソノミ'
61
+ OTHER_COMPANY_STOCK_QUESTION_AND_ANSWER_REPORT = 'jptoo-toa' # '他社株対質問回答報告書タクソノミ'
62
+ TENDER_OFFER = 'jptoi' # '自社株公開買付タクソノミ'
63
+ LARGE_VOLUME_HOLDINGS = 'jplvh' # '大量保有タクソノミ'
64
+ INTERNAL_CONTROL = 'jpctl' # '内部統制タクソノミ'
65
+
66
+ @classmethod
67
+ def parse(cls, value: str) -> Taxonomy | None:
68
+ try:
69
+ return cls(value)
70
+ except ValueError:
71
+ return None
72
+
73
+ @dataclass(frozen=True)
74
+ class FilingFormat:
75
+ ordinance: Ordinance
76
+ documentType: DocumentType
77
+ formType: FormType
78
+ taxonomies: frozenset[Taxonomy]
79
+
80
+ def includesTaxonomyPrefix(self, prefix: str) -> bool:
81
+ taxonomy = Taxonomy.parse(prefix.split('_')[0])
82
+ return taxonomy is not None and (
83
+ taxonomy == Taxonomy.DEI or # DEI is always included
84
+ taxonomy in self.taxonomies
85
+ )
86
+
87
+ DEFAULT_DISCLOSURE_TAXONOMIES = frozenset({
88
+ Taxonomy.FINANCIAL_STATEMENT,
89
+ Taxonomy.IFRS,
90
+ Taxonomy.DISCLOSURE_ORDINANCE,
91
+ })
92
+ DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES = frozenset({
93
+ Taxonomy.FINANCIAL_STATEMENT,
94
+ Taxonomy.CABINET_OFFICE_ORDINANCE_ON_SPECIFIED_SECURITIES_DISCLOSURE,
95
+ })
96
+ FINANCIAL_STATEMENT_TAXONOMIES = frozenset({
97
+ Taxonomy.DISCLOSURE_ORDINANCE,
98
+ Taxonomy.FINANCIAL_STATEMENT,
99
+ })
100
+
101
+ # The below values are based on Table 2-3-1 in "Framework Design of EDINET Taxonomy" (ESE140301.pdf).
102
+ # The order is preserved. The index is used to map to other data structures. EDINET documentation often
103
+ # references this same list of formats in this same order.
104
+ FILING_FORMATS = (
105
+ # 開示府令
106
+
107
+ # 有価証券届出書 第二号様式
108
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_2, DEFAULT_DISCLOSURE_TAXONOMIES),
109
+ # 有価証券届出書 第二号の二様式
110
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_2_2, frozenset({Taxonomy.DISCLOSURE_ORDINANCE})),
111
+ # 有価証券届出書 第二号の三様式
112
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_2_3, frozenset({Taxonomy.DISCLOSURE_ORDINANCE})),
113
+ # 有価証券届出書 第二号の四様式
114
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_2_4, DEFAULT_DISCLOSURE_TAXONOMIES),
115
+ # 有価証券届出書 第二号の五様式
116
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_2_5, DEFAULT_DISCLOSURE_TAXONOMIES),
117
+ # 有価証券届出書 第二号の六様式
118
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_2_6, DEFAULT_DISCLOSURE_TAXONOMIES),
119
+ # 有価証券届出書 第二号の七様式
120
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_2_7, DEFAULT_DISCLOSURE_TAXONOMIES),
121
+ # 有価証券報告書 第三号様式
122
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_3, DEFAULT_DISCLOSURE_TAXONOMIES),
123
+ # 有価証券報告書 第三号の二様式
124
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_3_2, DEFAULT_DISCLOSURE_TAXONOMIES),
125
+ # 有価証券報告書 第四号様式
126
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_4, DEFAULT_DISCLOSURE_TAXONOMIES),
127
+ # 半期報告書 第四号の三様式
128
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_4_3, DEFAULT_DISCLOSURE_TAXONOMIES),
129
+ # 半期報告書 第五号様式
130
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_5, DEFAULT_DISCLOSURE_TAXONOMIES),
131
+ # 半期報告書 第五号の二様式
132
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_5_2, DEFAULT_DISCLOSURE_TAXONOMIES),
133
+ # 臨時報告書 第五号の三様式
134
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.EXTRAORDINARY_REPORT, FormType.FORM_5_3, frozenset({Taxonomy.EXTRAORDINARY_REPORT})),
135
+ # 有価証券届出書 第七号様式
136
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_7, FINANCIAL_STATEMENT_TAXONOMIES),
137
+ # 有価証券届出書 第七号の四様式
138
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_7_4, FINANCIAL_STATEMENT_TAXONOMIES),
139
+ # 有価証券報告書 第八号様式
140
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_8, FINANCIAL_STATEMENT_TAXONOMIES),
141
+ # 有価証券報告書 第九号様式
142
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_9, FINANCIAL_STATEMENT_TAXONOMIES),
143
+
144
+ # 半期報告書 第九号の三様式
145
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_9_3, FINANCIAL_STATEMENT_TAXONOMIES),
146
+ # 半期報告書 第十号様式
147
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_10, FINANCIAL_STATEMENT_TAXONOMIES),
148
+ # 発行登録書 第十一号様式
149
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SHELF_REGISTRATION_STATEMENT, FormType.FORM_11, frozenset({Taxonomy.DISCLOSURE_ORDINANCE})),
150
+ # 発行登録書 第十一号の二様式
151
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SHELF_REGISTRATION_STATEMENT, FormType.FORM_11_2, frozenset({Taxonomy.DISCLOSURE_ORDINANCE})),
152
+ # 発行登録書 第十一号の二の二様式
153
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SHELF_REGISTRATION_STATEMENT, FormType.FORM_11_2_2, frozenset({Taxonomy.DISCLOSURE_ORDINANCE})),
154
+ # 発行登録追補書類 第十二号様式
155
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SHELF_REGISTRATION_SUPPLEMENT, FormType.FORM_12, frozenset({Taxonomy.DISCLOSURE_ORDINANCE})),
156
+ # 発行登録追補書類 第十二号の二様式
157
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.SHELF_REGISTRATION_SUPPLEMENT, FormType.FORM_12_2, frozenset({Taxonomy.DISCLOSURE_ORDINANCE})),
158
+ # 自己株券買付状況報 告書 第十七号様式
159
+ FilingFormat(Ordinance.DISCLOSURE, DocumentType.REPORT_ON_STATUS_OF_OWN_SHARE_REPURCHASE, FormType.FORM_17, frozenset({Taxonomy.STATUS_OF_SHARE_BUYBACKS})),
160
+
161
+ # 特定有価証券開示府令
162
+
163
+ # 有価証券届出書 第四号様式
164
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_4, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
165
+ # 有価証券届出書 第四号の三様式
166
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_4_3, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
167
+ # 有価証券届出書 第四号の三の二様式
168
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_4_3_2, frozenset({Taxonomy.CABINET_OFFICE_ORDINANCE_ON_SPECIFIED_SECURITIES_DISCLOSURE})),
169
+ # 有価証券届出書 第四号の三の三様式
170
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_4_3_3, frozenset({Taxonomy.CABINET_OFFICE_ORDINANCE_ON_SPECIFIED_SECURITIES_DISCLOSURE})),
171
+ # 有価証券届出書 第五号の二様式
172
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_5_2, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
173
+ # 有価証券届出書 第五号の四様式
174
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_5_4, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
175
+ # 有価証券届出書 第六号様式
176
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_6, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
177
+ # 有価証券届出書 第六号の五様式
178
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SECURITIES_REGISTRATION_STATEMENT, FormType.FORM_6_5, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
179
+ # 有価証券報告書【みなし有価証券届出書】第六号の七及び第七号 様式 - manually switched to ANNUAL_SECURITIES_REPORT
180
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_6_7_AND_FORM_7, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
181
+ # 有価証券報告書【みなし有価証券届出書】第六号の九及び第九号 様式 - manually switched to ANNUAL_SECURITIES_REPORT
182
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_6_9_AND_FORM_9, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
183
+ # 有価証券報告書 第七号様式
184
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_7, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
185
+ # 有価証券報告書 第七号の三様式
186
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_7_3, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
187
+ # 有価証券報告書 第八号の二様式
188
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_8_2, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
189
+ # 有価証券報告書 第八号の四様式
190
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_8_4, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
191
+ # 有価証券報告書 第九号様式
192
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_9, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
193
+ # 有価証券報告書 第九号の五様式
194
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.ANNUAL_SECURITIES_REPORT, FormType.FORM_9_5, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
195
+ # 半期報告書 第十号様式
196
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_10, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
197
+ # 半期報告書 第十号の三様式
198
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_10_3, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
199
+ # 半期報告書 第十一号の二様式
200
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_11_2, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
201
+ # 半期報告書 第十一号の四様式
202
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_11_4, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
203
+ # 半期報告書 第十二号様式
204
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_12, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
205
+ # 半期報告書 第十二号の五様式
206
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SEMI_ANNUAL_REPORT, FormType.FORM_12_5, DEFAULT_SPECIFIED_SECURITIES_DISCLOSURE_TAXONOMIES),
207
+ # 発行登録書 第十五号様式
208
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SHELF_REGISTRATION_STATEMENT, FormType.FORM_15, frozenset({Taxonomy.CABINET_OFFICE_ORDINANCE_ON_SPECIFIED_SECURITIES_DISCLOSURE})),
209
+ # 発行登録書 第十五号の三様式
210
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SHELF_REGISTRATION_STATEMENT, FormType.FORM_15_3, frozenset({Taxonomy.CABINET_OFFICE_ORDINANCE_ON_SPECIFIED_SECURITIES_DISCLOSURE})),
211
+ # 発行登録追補書類 第二十一号様式
212
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.SHELF_REGISTRATION_SUPPLEMENT, FormType.FORM_21, frozenset({Taxonomy.CABINET_OFFICE_ORDINANCE_ON_SPECIFIED_SECURITIES_DISCLOSURE})),
213
+ # 自己株券買付状況報 告書 第二十五号の三様式
214
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.REPORT_ON_STATUS_OF_OWN_SHARE_REPURCHASE, FormType.FORM_25_3, frozenset({Taxonomy.STATUS_OF_SPECIFIC_SECURITIES_TREASURY_STOCK_PURCHASES})),
215
+ # 臨時報告書
216
+ FilingFormat(Ordinance.SPECIFIED_SECURITIES_DISCLOSURE, DocumentType.EXTRAORDINARY_REPORT, FormType.NONE_SPECIFIED, frozenset({Taxonomy.SPECIFIED_SECURITIES_EXTRAORDINARY_REPORT})),
217
+
218
+ # 他社株買付府令
219
+
220
+ # 公開買付届出書 第二号様式
221
+ FilingFormat(Ordinance.OTHER_SHARE_PURCHASE_TENDER_OFFER, DocumentType.TENDER_OFFER_STATEMENT, FormType.FORM_2, frozenset({Taxonomy.TENDER_OFFER_NOTIFICATION})),
222
+ # 意見表明報告書 第四号様式
223
+ FilingFormat(Ordinance.OTHER_SHARE_PURCHASE_TENDER_OFFER, DocumentType.OPINION_STATEMENT, FormType.FORM_4, frozenset({Taxonomy.OTHER_COMPANY_OPINION_STATEMENT})),
224
+ # 公開買付撤回届出書 第五号様式
225
+ FilingFormat(Ordinance.OTHER_SHARE_PURCHASE_TENDER_OFFER, DocumentType.WITHDRAWAL_OF_TENDER_OFFER_STATEMENT, FormType.FORM_5, frozenset({Taxonomy.TENDER_OFFER_WITHDRAWAL_NOTIFICATION})),
226
+ # 公開買付報告書 第六号様式
227
+ FilingFormat(Ordinance.OTHER_SHARE_PURCHASE_TENDER_OFFER, DocumentType.TENDER_OFFER_REPORT, FormType.FORM_6, frozenset({Taxonomy.TENDER_OFFER_REPORT})),
228
+ # 対質問回答報告書 第八号様式
229
+ FilingFormat(Ordinance.OTHER_SHARE_PURCHASE_TENDER_OFFER, DocumentType.RESPONSE_TO_QUESTIONS_REPORT, FormType.FORM_8, frozenset({Taxonomy.OTHER_COMPANY_STOCK_QUESTION_AND_ANSWER_REPORT})),
230
+
231
+ # 自社株買付府令
232
+
233
+ # 公開買付届出書 第二号様式
234
+ FilingFormat(Ordinance.OWN_SHARE_PURCHASE_TENDER_OFFER, DocumentType.TENDER_OFFER_STATEMENT, FormType.FORM_2, frozenset({Taxonomy.TENDER_OFFER})),
235
+ # 公開買付撤回届出書 第三号様式
236
+ FilingFormat(Ordinance.OWN_SHARE_PURCHASE_TENDER_OFFER, DocumentType.WITHDRAWAL_OF_TENDER_OFFER_STATEMENT, FormType.FORM_3, frozenset({Taxonomy.TENDER_OFFER})),
237
+ # 公開買付報告書 第四号様式
238
+ FilingFormat(Ordinance.OWN_SHARE_PURCHASE_TENDER_OFFER, DocumentType.TENDER_OFFER_REPORT, FormType.FORM_4, frozenset({Taxonomy.TENDER_OFFER})),
239
+
240
+ # 大量保有府令
241
+
242
+ # 大量保有報告書 第一号様式
243
+ FilingFormat(Ordinance.LARGE_SHAREHOLDING, DocumentType.LARGE_SHAREHOLDING_REPORT, FormType.FORM_1, frozenset({Taxonomy.LARGE_VOLUME_HOLDINGS})),
244
+ # 大量保有報告書 第一号及び第二号様式
245
+ FilingFormat(Ordinance.LARGE_SHAREHOLDING, DocumentType.LARGE_SHAREHOLDING_REPORT, FormType.FORM_1_AND_2, frozenset({Taxonomy.LARGE_VOLUME_HOLDINGS})),
246
+ # 大量保有報告書 第三号様式
247
+ FilingFormat(Ordinance.LARGE_SHAREHOLDING, DocumentType.LARGE_SHAREHOLDING_REPORT, FormType.FORM_3, frozenset({Taxonomy.LARGE_VOLUME_HOLDINGS})),
248
+
249
+ # 内部統制府令
250
+
251
+ # 内部統制報告書 第一号様式
252
+ FilingFormat(Ordinance.INTERNAL_CONTROL, DocumentType.INTERNAL_CONTROL_REPORT, FormType.FORM_1, frozenset({Taxonomy.INTERNAL_CONTROL})),
253
+ )
@@ -0,0 +1,81 @@
1
+ """
2
+ See COPYRIGHT.md for copyright information.
3
+ """
4
+ from __future__ import annotations
5
+
6
+ from enum import Enum
7
+
8
+
9
+ class FormType(Enum):
10
+ FORM_1 = '第一号様式'
11
+ FORM_1_AND_2 = '第一号及び第二号様式'
12
+ FORM_2 = '第二号様式'
13
+ FORM_2_2 = '第二号の二様式'
14
+ FORM_2_3 = '第二号の三様式'
15
+ FORM_2_4 = '第二号の四様式'
16
+ FORM_2_5 = '第二号の五様式'
17
+ FORM_2_6 = '第二号の六様式'
18
+ FORM_2_7 = '第二号の七様式'
19
+ FORM_3 = '第三号様式'
20
+ FORM_3_2 = '第三号の二様式'
21
+ FORM_4 = '第四号様式'
22
+ FORM_4_3 = '第四号の三様式'
23
+ FORM_4_3_2 = '第四号の三の二様式'
24
+ FORM_4_3_3 = '第四号の三の三様式'
25
+ FORM_5 = '第五号様式'
26
+ FORM_5_2 = '第五号の二様式'
27
+ FORM_5_3 = '第五号の三様式'
28
+ FORM_5_4 = '第五号の四様式'
29
+ FORM_6 = '第六号様式'
30
+ FORM_6_5 = '第六号の五様式'
31
+ FORM_6_7_AND_FORM_7 = '第六号の七及び第七号様式'
32
+ FORM_6_9_AND_FORM_9 = '第六号の九及び第九号様式'
33
+ FORM_7 = '第七号様式'
34
+ FORM_7_3 = '第七号の三様式'
35
+ FORM_7_4 = '第七号の四様式'
36
+ FORM_8 = '第八号様式'
37
+ FORM_8_2 = '第八号の二様式'
38
+ FORM_8_4 = '第八号の四様式'
39
+ FORM_9 = '第九号様式'
40
+ FORM_9_3 = '第九号の三様式'
41
+ FORM_9_5 = '第九号の五様式'
42
+ FORM_10 = '第十号様式'
43
+ FORM_10_3 = '第十号の三様式'
44
+ FORM_11 = '第十一号様式'
45
+ FORM_11_2 = '第十一号の二様式'
46
+ FORM_11_2_2 = '第十一号の二の二様式'
47
+ FORM_11_4 = '第十一号の四様式'
48
+ FORM_12 = '第十二号様式'
49
+ FORM_12_2 = '第十二号の二様式'
50
+ FORM_12_5 = '第十二号の五様式'
51
+ FORM_15 = '第十五号様式'
52
+ FORM_15_3 = '第十五号の三様式'
53
+ FORM_17 = '第十七号様式'
54
+ FORM_21 = '第二十一号様式'
55
+ FORM_25_3 = '第二十五号の三様式'
56
+ NONE_SPECIFIED = '様式なし'
57
+
58
+ @classmethod
59
+ def parse(cls, value: str) -> FormType | None:
60
+ try:
61
+ return cls(value)
62
+ except ValueError:
63
+ return None
64
+
65
+ @property
66
+ def isCorporateForm(self) -> bool:
67
+ return self in CORPORATE_FORMS
68
+
69
+ @property
70
+ def isStockReport(self) -> bool:
71
+ return self in STOCK_REPORT_FORMS
72
+
73
+ CORPORATE_FORMS =frozenset([
74
+ FormType.FORM_2_4,
75
+ FormType.FORM_2_7,
76
+ FormType.FORM_3,
77
+ ])
78
+ STOCK_REPORT_FORMS = frozenset([
79
+ FormType.FORM_3,
80
+ FormType.FORM_4,
81
+ ])
@@ -9,14 +9,13 @@ from decimal import Decimal
9
9
  from functools import lru_cache
10
10
  from pathlib import Path
11
11
 
12
- from lxml.etree import DTD, XML, _ElementTree, _Comment, _ProcessingInstruction
12
+ from lxml.etree import DTD, XML
13
13
  from operator import attrgetter
14
14
  from typing import Callable, Hashable, Iterable, cast
15
15
 
16
16
  import os
17
17
  import regex
18
18
 
19
- from arelle import UrlUtil
20
19
  from arelle.LinkbaseType import LinkbaseType
21
20
  from arelle.ModelDocument import Type as ModelDocumentType, ModelDocument
22
21
  from arelle.ModelDtsObject import ModelConcept
@@ -31,8 +30,11 @@ from arelle.XhtmlValidate import htmlEltUriAttrs
31
30
  from arelle.XmlValidate import VALID
32
31
  from arelle.typing import TypeGetText
33
32
  from arelle.utils.PluginData import PluginData
34
- from .Constants import CORPORATE_FORMS, FormType, xhtmlDtdExtension, PROHIBITED_HTML_TAGS, PROHIBITED_HTML_ATTRIBUTES
33
+ from .Constants import xhtmlDtdExtension, PROHIBITED_HTML_TAGS, PROHIBITED_HTML_ATTRIBUTES
35
34
  from .ControllerPluginData import ControllerPluginData
35
+ from .CoverPageRequirements import CoverPageRequirements, COVER_PAGE_ITEM_LOCAL_NAMES
36
+ from .FilingFormat import FilingFormat, FILING_FORMATS
37
+ from .FormType import FormType
36
38
  from .ManifestInstance import ManifestInstance
37
39
  from .Statement import Statement, STATEMENTS, BalanceSheet, StatementInstance, StatementType
38
40
  from .UploadContents import UploadContents
@@ -42,6 +44,20 @@ _: TypeGetText
42
44
 
43
45
  _DEBIT_QNAME_PATTERN = regex.compile('.*(Liability|Liabilities|Equity)')
44
46
 
47
+ STANDARD_TAXONOMY_URL_PREFIXES = frozenset((
48
+ 'http://disclosure.edinet-fsa.go.jp/taxonomy/',
49
+ 'https://disclosure.edinet-fsa.go.jp/taxonomy/',
50
+ 'http://www.xbrl.org/20',
51
+ 'https://www.xbrl.org/20',
52
+ 'http://www.xbrl.org/lrr/',
53
+ 'https://www.xbrl.org/lrr/',
54
+ 'http://xbrl.org/20',
55
+ 'https://xbrl.org/20',
56
+ 'http://www.xbrl.org/dtr/',
57
+ 'https://www.xbrl.org/dtr/',
58
+ 'http://www.w3.org/1999/xlink',
59
+ 'https://www.w3.org/1999/xlink'
60
+ ))
45
61
 
46
62
  @dataclass(frozen=True)
47
63
  class UriReference:
@@ -58,35 +74,59 @@ class PluginValidationDataExtension(PluginData):
58
74
  consolidatedOrNonConsolidatedAxisQn: QName
59
75
  documentTypeDeiQn: QName
60
76
  jpcrpEsrFilingDateCoverPageQn: QName
77
+ jpcrpEsrNamespace: str
61
78
  jpcrpFilingDateCoverPageQn: QName
79
+ jpcrpNamespace: str
80
+ jpdeiNamespace: str
81
+ jpigpNamespace: str
82
+ jppfsNamespace: str
62
83
  jpspsFilingDateCoverPageQn: QName
84
+ jpspsNamespace: str
63
85
  nonConsolidatedMemberQn: QName
64
86
  ratioOfFemaleDirectorsAndOtherOfficersQn: QName
65
87
 
66
88
  contextIdPattern: regex.Pattern[str]
89
+ coverPageItems: tuple[QName, ...]
90
+ coverPageRequirementsPath: Path
91
+ coverPageTitleQns: tuple[QName, ...]
67
92
 
68
93
  _uriReferences: list[UriReference]
69
94
 
70
95
  def __init__(self, name: str, validateXbrl: ValidateXbrl):
71
96
  super().__init__(name)
72
- jpcrpEsrNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpcrp-esr/2024-11-01/jpcrp-esr_cor"
97
+
98
+ # Namespaces
99
+ self.jpcrpEsrNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpcrp-esr/2024-11-01/jpcrp-esr_cor"
73
100
  self.jpcrpNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpcrp/2024-11-01/jpcrp_cor'
74
- jpdeiNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpdei/2013-08-31/jpdei_cor'
75
- jpigpNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpigp/2024-11-01/jpigp_cor"
76
- jppfsNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jppfs/2024-11-01/jppfs_cor"
77
- jpspsNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpsps/2024-11-01/jpsps_cor'
78
- self.accountingStandardsDeiQn = qname(jpdeiNamespace, 'AccountingStandardsDEI')
79
- self.assetsIfrsQn = qname(jpigpNamespace, 'AssetsIFRS')
80
- self.consolidatedOrNonConsolidatedAxisQn = qname(jppfsNamespace, 'ConsolidatedOrNonConsolidatedAxis')
81
- self.documentTypeDeiQn = qname(jpdeiNamespace, 'DocumentTypeDEI')
101
+ self.jpdeiNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpdei/2013-08-31/jpdei_cor'
102
+ self.jpigpNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jpigp/2024-11-01/jpigp_cor"
103
+ self.jppfsNamespace = "http://disclosure.edinet-fsa.go.jp/taxonomy/jppfs/2024-11-01/jppfs_cor"
104
+ self.jpspsNamespace = 'http://disclosure.edinet-fsa.go.jp/taxonomy/jpsps/2024-11-01/jpsps_cor'
105
+
106
+ # QNames
107
+ self.accountingStandardsDeiQn = qname(self.jpdeiNamespace, 'AccountingStandardsDEI')
108
+ self.assetsIfrsQn = qname(self.jpigpNamespace, 'AssetsIFRS')
109
+ self.consolidatedOrNonConsolidatedAxisQn = qname(self.jppfsNamespace, 'ConsolidatedOrNonConsolidatedAxis')
110
+ self.documentTypeDeiQn = qname(self.jpdeiNamespace, 'DocumentTypeDEI')
82
111
  self.issuedSharesTotalNumberOfSharesEtcQn = qname(self.jpcrpNamespace, 'IssuedSharesTotalNumberOfSharesEtcTextBlock')
83
- self.jpcrpEsrFilingDateCoverPageQn = qname(jpcrpEsrNamespace, 'FilingDateCoverPage')
112
+ self.jpcrpEsrFilingDateCoverPageQn = qname(self.jpcrpEsrNamespace, 'FilingDateCoverPage')
84
113
  self.jpcrpFilingDateCoverPageQn = qname(self.jpcrpNamespace, 'FilingDateCoverPage')
85
- self.jpspsFilingDateCoverPageQn = qname(jpspsNamespace, 'FilingDateCoverPage')
86
- self.nonConsolidatedMemberQn = qname(jppfsNamespace, "NonConsolidatedMember")
114
+ self.jpspsFilingDateCoverPageQn = qname(self.jpspsNamespace, 'FilingDateCoverPage')
115
+ self.nonConsolidatedMemberQn = qname(self.jppfsNamespace, "NonConsolidatedMember")
87
116
  self.ratioOfFemaleDirectorsAndOtherOfficersQn = qname(self.jpcrpNamespace, "RatioOfFemaleDirectorsAndOtherOfficers")
88
117
 
89
118
  self.contextIdPattern = regex.compile(r'(Prior[1-9]Year|CurrentYear|Prior[1-9]Interim|Interim)(Duration|Instant)')
119
+ self.coverPageItems = tuple(
120
+ qname(self.jpdeiNamespace, localName)
121
+ for localName in COVER_PAGE_ITEM_LOCAL_NAMES
122
+ )
123
+ self.coverPageRequirementsPath = Path(__file__).parent / "resources" / "cover-page-requirements.csv"
124
+ self.coverPageTitleQns = (
125
+ qname(self.jpspsNamespace, "DocumentTitleAnnualSecuritiesReportCoverPage"),
126
+ qname(self.jpcrpNamespace, "DocumentTitleCoverPage"),
127
+ qname(self.jpcrpEsrNamespace, "DocumentTitleCoverPage"),
128
+ qname(self.jpspsNamespace, "DocumentTitleCoverPage"),
129
+ )
90
130
 
91
131
  self._uriReferences = []
92
132
  self._initialize(validateXbrl.modelXbrl)
@@ -140,17 +180,39 @@ class PluginValidationDataExtension(PluginData):
140
180
 
141
181
  @lru_cache(1)
142
182
  def isCorporateForm(self, modelXbrl: ModelXbrl) -> bool:
143
- documentTypes = self.getDocumentTypes(modelXbrl)
144
- if any(documentType == form.value for form in CORPORATE_FORMS for documentType in documentTypes):
145
- return True
146
- return False
183
+ formTypes = self.getFormTypes(modelXbrl)
184
+ return any(
185
+ formType.isCorporateForm
186
+ for formType in formTypes
187
+ )
147
188
 
148
189
  def isCorporateReport(self, modelXbrl: ModelXbrl) -> bool:
149
190
  return self.jpcrpNamespace in modelXbrl.namespaceDocs
150
191
 
192
+ def isExtensionUri(self, uri: str, modelXbrl: ModelXbrl) -> bool:
193
+ if uri.startswith(modelXbrl.uriDir):
194
+ return True
195
+ return not any(uri.startswith(taxonomyUri) for taxonomyUri in STANDARD_TAXONOMY_URL_PREFIXES)
196
+
197
+ @lru_cache(1)
151
198
  def isStockForm(self, modelXbrl: ModelXbrl) -> bool:
152
- documentTypes = self.getDocumentTypes(modelXbrl)
153
- return any(documentType == form.value for form in FormType if form.isStockReport for documentType in documentTypes)
199
+ formTypes = self.getFormTypes(modelXbrl)
200
+ return any(
201
+ formType.isStockReport
202
+ for formType in formTypes
203
+ )
204
+
205
+ @lru_cache(1)
206
+ def getExtensionConcepts(self, modelXbrl: ModelXbrl) -> list[ModelConcept]:
207
+ """
208
+ Returns a list of extension concepts in the DTS.
209
+ """
210
+ extensionConcepts = []
211
+ for concepts in modelXbrl.nameConcepts.values():
212
+ for concept in concepts:
213
+ if self.isExtensionUri(concept.qname.namespaceURI, modelXbrl):
214
+ extensionConcepts.append(concept)
215
+ return extensionConcepts
154
216
 
155
217
  def getBalanceSheets(self, modelXbrl: ModelXbrl, statement: Statement) -> list[BalanceSheet]:
156
218
  """
@@ -207,6 +269,10 @@ class PluginValidationDataExtension(PluginData):
207
269
  )
208
270
  return balanceSheets
209
271
 
272
+ def getCoverPageRequirements(self, modelXbrl: ModelXbrl) -> CoverPageRequirements:
273
+ controllerPluginData = ControllerPluginData.get(modelXbrl.modelManager.cntlr, self.name)
274
+ return controllerPluginData.getCoverPageRequirements(self.coverPageRequirementsPath, self.coverPageItems, FILING_FORMATS)
275
+
210
276
  def getProblematicTextBlocks(self, modelXbrl: ModelXbrl) -> list[ModelInlineFact]:
211
277
  problematicTextBlocks: list[ModelInlineFact] = []
212
278
  dtd = DTD(os.path.join(modelXbrl.modelManager.cntlr.configDir, xhtmlDtdExtension))
@@ -248,15 +314,6 @@ class PluginValidationDataExtension(PluginData):
248
314
  def getDeduplicatedFacts(self, modelXbrl: ModelXbrl) -> list[ModelFact]:
249
315
  return getDeduplicatedFacts(modelXbrl, DeduplicationType.CONSISTENT_PAIRS)
250
316
 
251
- @lru_cache(1)
252
- def getDocumentTypes(self, modelXbrl: ModelXbrl) -> set[str]:
253
- documentFacts = modelXbrl.factsByQname.get(self.documentTypeDeiQn, set())
254
- documentTypes = set()
255
- for fact in documentFacts:
256
- if fact.xValid >= VALID:
257
- documentTypes.add(fact.textValue)
258
- return documentTypes
259
-
260
317
  def getFactsByContextAndUnit(
261
318
  self, modelXbrl: ModelXbrl,
262
319
  getContextKey: Callable[[ModelContext], Hashable],
@@ -297,6 +354,80 @@ class PluginValidationDataExtension(PluginData):
297
354
  if isinstance(elt, (ModelObject, LinkPrototype))
298
355
  ]
299
356
 
357
+ @lru_cache(1)
358
+ def getFilingFormat(self, modelXbrl: ModelXbrl) -> FilingFormat | None:
359
+ # This function attempts to identify the filing format based on form number and title concepts.
360
+ # The provided form number value directly informs the format.
361
+ # However, the document title is not necessarily an explicit setting of the format's
362
+ # document type. In the samples available to us and in a handful of public filings,
363
+ # it is effective to match the first segment of the title value against document type
364
+ # values assigned to the various FilingFormats. This may only be by coincidence or convention.
365
+ # If it doesn't end up being reliable, we may need to find another way to identify the form.
366
+ # For example, by disclosure system selection or CLI argument.
367
+ documentTitleFacts = []
368
+ for qname in self.coverPageTitleQns:
369
+ for fact in self.iterValidNonNilFacts(modelXbrl, qname):
370
+ documentTitleFacts.append(fact)
371
+ formTypes = self.getFormTypes(modelXbrl)
372
+ filingFormats = []
373
+ for filingFormatIndex, filingFormat in enumerate(FILING_FORMATS):
374
+ if filingFormat.formType not in formTypes:
375
+ continue
376
+ prefixes = {taxonomy.value for taxonomy in filingFormat.taxonomies}
377
+ if not any(
378
+ str(fact.xValue).startswith(filingFormat.documentType.value) and
379
+ fact.concept.qname.prefix.split('_')[0] in prefixes
380
+ for fact in documentTitleFacts
381
+ ):
382
+ continue
383
+ filingFormats.append((filingFormat, filingFormatIndex))
384
+ if len(filingFormats) == 0:
385
+ modelXbrl.error(
386
+ "arelle:NoMatchingEdinetFormat",
387
+ _("No matching EDINET filing formats could be identified based on form "
388
+ "type (%(formTypes)s) and title."),
389
+ formTypes=formTypes,
390
+ modelObject=documentTitleFacts,
391
+ )
392
+ return None
393
+ if len(filingFormats) > 1:
394
+ formatIndexes = [str(idx + 1) for _, idx in filingFormats]
395
+ modelXbrl.error(
396
+ "arelle:MultipleMatchingEdinetFormats",
397
+ _("Multiple EDINET filing formats (%(formatIndexes)s) matched based on form "
398
+ "type %(formTypes)s and title."),
399
+ formatIndexes=formatIndexes,
400
+ formTypes=formTypes,
401
+ modelObject=documentTitleFacts,
402
+ )
403
+ return None
404
+ filingFormat, filingFormatIndex = filingFormats[0]
405
+ modelXbrl.modelManager.cntlr.addToLog("Identified filing format: #{}, {}, {}, {}, {}".format(
406
+ filingFormatIndex + 1,
407
+ filingFormat.ordinance.value,
408
+ filingFormat.documentType.value,
409
+ filingFormat.formType.value,
410
+ ', '.join(taxonomy.value for taxonomy in filingFormat.taxonomies)
411
+ ), messageCode="info")
412
+ return filingFormat
413
+
414
+ @lru_cache(1)
415
+ def getFormTypes(self, modelXbrl: ModelXbrl) -> set[FormType]:
416
+ """
417
+ Retrieves form type values from the instance.
418
+ Note that the underlying concept is labeled "DocumentTypeDEI",
419
+ but "Document Type" refers to something else in EDINET documentation.
420
+ In practice, the value of this field is the form number / form type.
421
+ :param modelXbrl: Instance to get form types from.
422
+ :return: Set of discovered form types.
423
+ """
424
+ formTypes = set()
425
+ for fact in self.iterValidNonNilFacts(modelXbrl, self.documentTypeDeiQn):
426
+ formType = FormType.parse(fact.textValue)
427
+ if formType is not None:
428
+ formTypes.add(formType)
429
+ return formTypes
430
+
300
431
  @lru_cache(1)
301
432
  def getManifestInstance(self, modelXbrl: ModelXbrl) -> ManifestInstance | None:
302
433
  controllerPluginData = ControllerPluginData.get(modelXbrl.modelManager.cntlr, self.name)
@@ -350,10 +481,17 @@ class PluginValidationDataExtension(PluginData):
350
481
  def isStandardTaxonomyUrl(self, uri: str, modelXbrl: ModelXbrl) -> bool:
351
482
  return modelXbrl.modelManager.disclosureSystem.hrefValidForDisclosureSystem(uri)
352
483
 
484
+ def iterFacts(self, modelXbrl: ModelXbrl, qname: QName) -> Iterable[ModelFact]:
485
+ yield from modelXbrl.factsByQname.get(qname, set())
486
+
487
+ def iterValidFacts(self, modelXbrl: ModelXbrl, qname: QName) -> Iterable[ModelFact]:
488
+ for fact in self.iterFacts(modelXbrl, qname):
489
+ if fact.xValid >= VALID:
490
+ yield fact
491
+
353
492
  def iterValidNonNilFacts(self, modelXbrl: ModelXbrl, qname: QName) -> Iterable[ModelFact]:
354
- facts = modelXbrl.factsByQname.get(qname, set())
355
- for fact in facts:
356
- if fact.xValid >= VALID and not fact.isNil:
493
+ for fact in self.iterValidFacts(modelXbrl, qname):
494
+ if not fact.isNil:
357
495
  yield fact
358
496
 
359
497
  def addUsedFilepath(self, modelXbrl: ModelXbrl, path: Path) -> None: