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,27 @@
1
+ ◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎
2
+ ×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,×,×,×,×,×,×
3
+ ○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○
4
+ ◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎
5
+ ◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,△,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎
6
+ ×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,×,×,×,×,×,×
7
+ ×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,×,×,×,×,×,×,×,×,×,×,×,×
8
+ ◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎
9
+ ◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,×,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎
10
+ ○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,×,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,○,○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
11
+ ○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,×,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,○,○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
12
+ ○,×,×,○,○,○,○,○,○,○,○,○,○,×,○,○,○,○,○,○,×,×,×,×,×,×,○,○,×,×,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
13
+ ○,×,×,○,○,○,○,◎,◎,◎,○,◎,◎,×,◎,◎,◎,◎,○,◎,×,×,×,×,×,×,○,○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
14
+ ○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,×,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,○,○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
15
+ ○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,×,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,○,○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
16
+ ○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,×,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,○,○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
17
+ ○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,×,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,○,○,×,×,○,○,○,○,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
18
+ ○,×,×,○,○,○,○,○,○,○,○,○,○,×,○,○,○,○,○,○,×,×,×,×,×,×,○,○,×,×,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
19
+ ○,×,×,○,○,○,○,○,○,○,○,○,○,×,○,○,○,○,○,○,×,×,×,×,×,×,○,○,×,×,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
20
+ ○,×,×,○,○,○,○,○,○,○,○,○,○,×,○,○,○,○,○,○,×,×,×,×,×,×,○,○,×,×,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
21
+ ○,×,×,○,○,○,○,×,×,×,×,×,×,×,○,○,×,×,×,×,×,×,×,×,×,×,○,○,×,×,○,○,○,○,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
22
+ ○,×,×,○,○,○,○,×,×,×,×,×,×,×,○,○,×,×,×,×,×,×,×,×,×,×,○,○,×,×,○,○,○,○,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×,×
23
+ ◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎
24
+ ◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎
25
+ ○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○,○
26
+ ◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎
27
+ ◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎,◎
@@ -93,7 +93,7 @@ def rule_EC1057E(
93
93
  Ensure that there is a nonnil value disclosed for FilingDateCoverPage
94
94
  Note: This rule is only applicable to the public documents.
95
95
  """
96
- dei = pluginData.getDocumentTypes(val.modelXbrl)
96
+ dei = pluginData.getFormTypes(val.modelXbrl)
97
97
  if len(dei) > 0:
98
98
  if not (pluginData.hasValidNonNilFact(val.modelXbrl, pluginData.jpcrpEsrFilingDateCoverPageQn)
99
99
  or pluginData.hasValidNonNilFact(val.modelXbrl, pluginData.jpcrpFilingDateCoverPageQn)
@@ -10,6 +10,7 @@ from typing import Any, cast, Iterable
10
10
  import regex
11
11
 
12
12
  from arelle import XbrlConst, XmlUtil
13
+ from arelle.ModelDtsObject import ModelConcept
13
14
  from arelle.ModelInstanceObject import ModelFact
14
15
  from arelle.ModelObject import ModelObject
15
16
  from arelle.ModelValue import QName
@@ -26,12 +27,14 @@ from arelle.utils.Units import getDuplicateUnitGroups
26
27
  from arelle.utils.validate.Decorator import validation
27
28
  from arelle.utils.validate.Validation import Validation
28
29
  from arelle.utils.validate.ValidationUtil import etreeIterWithDepth
30
+ from ..Constants import NUMERIC_LABEL_ROLES
29
31
  from ..DisclosureSystems import (DISCLOSURE_SYSTEM_EDINET)
30
32
  from ..PluginValidationDataExtension import PluginValidationDataExtension
31
33
 
32
34
 
33
35
  _: TypeGetText
34
36
 
37
+ DISALLOWED_LABEL_WHITE_SPACE_CHARACTERS = regex.compile(r'\s{2,}')
35
38
  GFM_CONTEXT_DATE_PATTERN = regex.compile(r"^[12][0-9]{3}-[01][0-9]-[0-3][0-9]$")
36
39
  GFM_RECOMMENDED_NAMESPACE_PREFIXES = {
37
40
  XbrlConst.xbrli: ("xbrli",),
@@ -672,6 +675,168 @@ def rule_gfm_1_3_8(
672
675
  )
673
676
 
674
677
 
678
+ @validation(
679
+ hook=ValidationHook.XBRL_FINALLY,
680
+ disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
681
+ )
682
+ def rule_gfm_1_3_20(
683
+ pluginData: PluginValidationDataExtension,
684
+ val: ValidateXbrl,
685
+ *args: Any,
686
+ **kwargs: Any,
687
+ ) -> Iterable[Validation]:
688
+ """
689
+ EDINET.EC5700W: [GFM 1.3.20] Set the nillable attribute value to "true".
690
+
691
+ GFM 1.3.20 The nillable attribute value of an xsd:element must equal "true".
692
+ """
693
+ nonNillableElements = set()
694
+ for concept in val.modelXbrl.qnameConcepts.values():
695
+ if concept.namespaceURI == XbrlConst.xsd:
696
+ if concept.get("nillable") == "false":
697
+ nonNillableElements.add(concept)
698
+ if len(nonNillableElements) > 0:
699
+ yield Validation.warning(
700
+ codes='EDINET.EC5700W.GFM.1.3.20',
701
+ msg=_("Set the nillable attribute value to 'true'."),
702
+ modelObject=nonNillableElements
703
+ )
704
+
705
+
706
+ @validation(
707
+ hook=ValidationHook.XBRL_FINALLY,
708
+ disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
709
+ )
710
+ def rule_gfm_1_3_21(
711
+ pluginData: PluginValidationDataExtension,
712
+ val: ValidateXbrl,
713
+ *args: Any,
714
+ **kwargs: Any,
715
+ ) -> Iterable[Validation]:
716
+ """
717
+ EDINET.EC5700W: [GFM 1.3.21] Remove the tuple definition.
718
+ """
719
+ tupleConcepts = [
720
+ concept for concept in pluginData.getExtensionConcepts(val.modelXbrl)
721
+ if concept.isTuple
722
+ ]
723
+ if len(tupleConcepts) > 0:
724
+ yield Validation.warning(
725
+ codes='EDINET.EC5700W.GFM.1.3.21',
726
+ msg=_("Remove the tuple definition."),
727
+ modelObject=tupleConcepts
728
+ )
729
+
730
+
731
+ @validation(
732
+ hook=ValidationHook.XBRL_FINALLY,
733
+ disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
734
+ )
735
+ def rule_gfm_1_3_22(
736
+ pluginData: PluginValidationDataExtension,
737
+ val: ValidateXbrl,
738
+ *args: Any,
739
+ **kwargs: Any,
740
+ ) -> Iterable[Validation]:
741
+ """
742
+ EDINET.EC5700W: [GFM 1.3.22] Do not set the xbrldt:typedDomainRef attribute on elements defined in submitter-specific taxonomies.
743
+ """
744
+ typedDomainConcepts = [
745
+ concept for concept in pluginData.getExtensionConcepts(val.modelXbrl)
746
+ if concept.isTypedDimension
747
+ ]
748
+
749
+ if len(typedDomainConcepts) > 0:
750
+ yield Validation.warning(
751
+ codes='EDINET.EC5700W.GFM.1.3.22',
752
+ msg=_("Do not set the xbrldt:typedDomainRef attribute on elements defined in submitter-specific taxonomies."),
753
+ modelObject=typedDomainConcepts
754
+ )
755
+
756
+
757
+ @validation(
758
+ hook=ValidationHook.XBRL_FINALLY,
759
+ disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
760
+ )
761
+ def rule_gfm_1_3_23(
762
+ pluginData: PluginValidationDataExtension,
763
+ val: ValidateXbrl,
764
+ *args: Any,
765
+ **kwargs: Any,
766
+ ) -> Iterable[Validation]:
767
+ """
768
+ EDINET.EC5700W: [GFM 1.3.23] Set the periodType attribute to "duration".
769
+
770
+ GFM 1.3.23 If the abstract attribute of xsd:element is "true", then the
771
+ xbrli:periodType attribute must be "duration".
772
+ """
773
+ instantAbstractElements = set()
774
+ for concept in val.modelXbrl.qnameConcepts.values():
775
+ if concept.abstract == "true" and concept.periodType == "instant":
776
+ instantAbstractElements.add(concept)
777
+ if len(instantAbstractElements) > 0:
778
+ yield Validation.warning(
779
+ codes='EDINET.EC5700W.GFM.1.3.23',
780
+ msg=_("Set the periodType attribute to 'duration'."),
781
+ modelObject=instantAbstractElements
782
+ )
783
+
784
+
785
+ @validation(
786
+ hook=ValidationHook.XBRL_FINALLY,
787
+ disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
788
+ )
789
+ def rule_gfm_1_3_30(
790
+ pluginData: PluginValidationDataExtension,
791
+ val: ValidateXbrl,
792
+ *args: Any,
793
+ **kwargs: Any,
794
+ ) -> Iterable[Validation]:
795
+ """
796
+ EDINET.EC5700W: [GFM 1.3.30] Set the periodType attribute to "duration".
797
+
798
+ GFM 1.3.30 If xsd:element type attribute equals "nonnum:domainItemType" then
799
+ the xbrli:periodType attribute must equal "duration".
800
+ """
801
+ instantDomainElements = set()
802
+ for concept in val.modelXbrl.qnameConcepts.values():
803
+ if concept.type is not None and concept.type.isDomainItemType and concept.periodType == "instant":
804
+ instantDomainElements.add(concept)
805
+ if len(instantDomainElements) > 0:
806
+ yield Validation.warning(
807
+ codes='EDINET.EC5700W.GFM.1.3.30',
808
+ msg=_("Set the periodType attribute to 'duration'."),
809
+ modelObject=instantDomainElements
810
+ )
811
+
812
+ @validation(
813
+ hook=ValidationHook.XBRL_FINALLY,
814
+ disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
815
+ )
816
+ def rule_gfm_1_3_31(
817
+ pluginData: PluginValidationDataExtension,
818
+ val: ValidateXbrl,
819
+ *args: Any,
820
+ **kwargs: Any,
821
+ ) -> Iterable[Validation]:
822
+ """
823
+ EDINET.EC5700W: [GFM 1.3.31] Set the abstract attribute to "true".
824
+
825
+ GFM 1.3.31: If xsd:element type attribute equals "nonnum:domainItemType" then
826
+ the abstract attribute must equal to "true".
827
+ """
828
+ nonAbstractDomainElements = set()
829
+ for concept in val.modelXbrl.qnameConcepts.values():
830
+ if concept.type is not None and concept.type.isDomainItemType and concept.abstract != "true":
831
+ nonAbstractDomainElements.add(concept)
832
+ if len(nonAbstractDomainElements) > 0:
833
+ yield Validation.warning(
834
+ codes='EDINET.EC5700W.GFM.1.3.31',
835
+ msg=_("Set the abstract attribute to 'true'."),
836
+ modelObject=nonAbstractDomainElements
837
+ )
838
+
839
+
675
840
  @validation(
676
841
  hook=ValidationHook.XBRL_FINALLY,
677
842
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
@@ -683,7 +848,7 @@ def rule_gfm_1_5_6(
683
848
  **kwargs: Any,
684
849
  ) -> Iterable[Validation]:
685
850
  """
686
- EDINET.EC5700W: [GFM 1.5.6] The length of a label must be less than 511 characters unless it its role is documentation.
851
+ EDINET.EC5700W: [GFM 1.5.6] The length of a label must be less than 511 characters unless its role is documentation.
687
852
  """
688
853
  labelRelationshipSet = val.modelXbrl.relationshipSet(XbrlConst.conceptLabel)
689
854
  if labelRelationshipSet is None:
@@ -692,7 +857,7 @@ def rule_gfm_1_5_6(
692
857
  labelRels = labelRelationshipSet.fromModelObject(concept)
693
858
  for rel in labelRels:
694
859
  label = rel.toModelObject
695
- if label.role != XbrlConst.documentationLabel and label.viewText() is not None and len(label.viewText()) > 511:
860
+ if label.role != XbrlConst.documentationLabel and label.viewText() is not None and len(label.viewText()) >= 511:
696
861
  yield Validation.warning(
697
862
  codes='EDINET.EC5700W.GFM.1.5.6',
698
863
  msg=_("The concept of '%(concept)s' has a label classified as '%(role)s' that is longer than 511 characters: %(label)s"),
@@ -701,3 +866,107 @@ def rule_gfm_1_5_6(
701
866
  label=label.viewText(),
702
867
  modelObject=label
703
868
  )
869
+
870
+
871
+ @validation(
872
+ hook=ValidationHook.XBRL_FINALLY,
873
+ disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
874
+ )
875
+ def rule_gfm_1_5_7(
876
+ pluginData: PluginValidationDataExtension,
877
+ val: ValidateXbrl,
878
+ *args: Any,
879
+ **kwargs: Any,
880
+ ) -> Iterable[Validation]:
881
+ """
882
+ EDINET.EC5700W: [GFM 1.5.7] A label cannot contain the "<" character or consecutive white space characters including
883
+ but not limited to: space, carriage return, line feed or tab.
884
+ """
885
+ labelRelationshipSet = val.modelXbrl.relationshipSet(XbrlConst.conceptLabel)
886
+ if labelRelationshipSet is None:
887
+ return
888
+ for concept in val.modelXbrl.qnameConcepts.values():
889
+ labelRels = labelRelationshipSet.fromModelObject(concept)
890
+ for rel in labelRels:
891
+ label = rel.toModelObject
892
+ if label.role != XbrlConst.documentationLabel and label.textValue is not None:
893
+ if '<' in label.textValue:
894
+ yield Validation.warning(
895
+ codes='EDINET.EC5700W.GFM.1.5.7',
896
+ msg=_("The concept of '%(concept)s' has a label classified as '%(role)s that contains the '<' character: %(label)s"),
897
+ concept=concept.qname,
898
+ role=label.role,
899
+ label=label.textValue,
900
+ modelObject=label
901
+ )
902
+ elif DISALLOWED_LABEL_WHITE_SPACE_CHARACTERS.search(label.textValue):
903
+ yield Validation.warning(
904
+ codes='EDINET.EC5700W.GFM.1.5.7',
905
+ msg=_("The concept of '%(concept)s' has a label classified as '%(role)s' that contains consecutive white space characters: %(label)s"),
906
+ concept=concept.qname,
907
+ role=label.role,
908
+ label=label.textValue,
909
+ modelObject=label
910
+ )
911
+
912
+
913
+ @validation(
914
+ hook=ValidationHook.XBRL_FINALLY,
915
+ disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
916
+ )
917
+ def rule_gfm_1_5_8(
918
+ pluginData: PluginValidationDataExtension,
919
+ val: ValidateXbrl,
920
+ *args: Any,
921
+ **kwargs: Any,
922
+ ) -> Iterable[Validation]:
923
+ """
924
+ EDINET.EC5700W: [GFM 1.5.8] A label should not begin or end with a white space character
925
+ """
926
+ labelRelationshipSet = val.modelXbrl.relationshipSet(XbrlConst.conceptLabel)
927
+ if labelRelationshipSet is None:
928
+ return
929
+ for concept in val.modelXbrl.qnameConcepts.values():
930
+ labelRels = labelRelationshipSet.fromModelObject(concept)
931
+ for rel in labelRels:
932
+ label = rel.toModelObject
933
+ if label.textValue is not None and label.textValue != label.textValue.strip():
934
+ yield Validation.warning(
935
+ codes='EDINET.EC5700W.GFM.1.5.8',
936
+ msg=_("The concept of '%(concept)s' has a label that contains disallowed white space either at the begining or the end: '%(label)s'"),
937
+ concept=concept.qname,
938
+ label=label.textValue,
939
+ modelObject=label
940
+ )
941
+
942
+
943
+ @validation(
944
+ hook=ValidationHook.XBRL_FINALLY,
945
+ disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
946
+ )
947
+ def rule_gfm_1_5_10(
948
+ pluginData: PluginValidationDataExtension,
949
+ val: ValidateXbrl,
950
+ *args: Any,
951
+ **kwargs: Any,
952
+ ) -> Iterable[Validation]:
953
+ """
954
+ EDINET.EC5700W: [GFM 1.5.10] A non-numeric concept should not have a label with a numeric role
955
+ """
956
+ labelRelationshipSet = val.modelXbrl.relationshipSet(XbrlConst.conceptLabel)
957
+ if labelRelationshipSet is None:
958
+ return
959
+ for concept in val.modelXbrl.qnameConcepts.values():
960
+ if concept.isNumeric:
961
+ continue
962
+ labelRels = labelRelationshipSet.fromModelObject(concept)
963
+ for rel in labelRels:
964
+ label = rel.toModelObject
965
+ if not pluginData.isStandardTaxonomyUrl(label.modelDocument.uri, val.modelXbrl) and label.role in NUMERIC_LABEL_ROLES:
966
+ yield Validation.warning(
967
+ codes='EDINET.EC5700W.GFM.1.5.10',
968
+ msg=_("The non-numeric concept of '%(concept)s' has a label with a numeric role of '%(labelrole)s'"),
969
+ concept=concept.qname,
970
+ labelrole=label.role,
971
+ modelObject=label
972
+ )
@@ -6,20 +6,24 @@ from __future__ import annotations
6
6
  import re
7
7
  from collections import defaultdict
8
8
  from pathlib import Path
9
- from typing import Any, Iterable, TYPE_CHECKING
9
+ from typing import Any, Iterable, TYPE_CHECKING, cast
10
10
 
11
11
  import regex
12
12
 
13
- from arelle import UrlUtil
13
+ from arelle import UrlUtil, XbrlConst
14
14
  from arelle.Cntlr import Cntlr
15
15
  from arelle.FileSource import FileSource
16
+ from arelle.ModelInstanceObject import ModelFact
16
17
  from arelle.ValidateXbrl import ValidateXbrl
18
+ from arelle.XmlValidateConst import VALID
17
19
  from arelle.typing import TypeGetText
18
20
  from arelle.utils.PluginHooks import ValidationHook
19
21
  from arelle.utils.validate.Decorator import validation
20
22
  from arelle.utils.validate.Validation import Validation
21
23
  from .. import Constants
24
+ from ..CoverPageRequirements import CoverPageItemStatus
22
25
  from ..DisclosureSystems import (DISCLOSURE_SYSTEM_EDINET)
26
+ from ..FilingFormat import FILING_FORMATS
23
27
  from ..ReportFolderType import ReportFolderType, HTML_EXTENSIONS, IMAGE_EXTENSIONS
24
28
  from ..PluginValidationDataExtension import PluginValidationDataExtension
25
29
 
@@ -631,6 +635,11 @@ def rules_cover_page(
631
635
  ) -> Iterable[Validation]:
632
636
  """
633
637
  EDINET.EC1000E: Cover page must contain "【表紙】".
638
+ EDINET.EC1001E: A required item is missing from the cover page.
639
+ EDINET.EC1002E: A duplicate item is included on the cover page.
640
+ EDINET.EC1003E: An unnecessary item is included on the cover page.
641
+ EDINET.EC1004E: An item on the cover page is out of order.
642
+ EDINET.EC1005E: A required item on the cover page is missing a valid value.
634
643
  """
635
644
  uploadContents = pluginData.getUploadContents(val.modelXbrl)
636
645
  if uploadContents is None:
@@ -645,7 +654,7 @@ def rules_cover_page(
645
654
  for elt in rootElt.iterdescendants():
646
655
  if not coverPageTextFound and elt.text and '【表紙】' in elt.text:
647
656
  coverPageTextFound = True
648
- # TODO: Other checks related to the cover page will be implemented here.
657
+ break
649
658
  if not coverPageTextFound:
650
659
  yield Validation.error(
651
660
  codes='EDINET.EC1000E',
@@ -654,6 +663,85 @@ def rules_cover_page(
654
663
  "Please add '【表紙】' to the relevant file."),
655
664
  file=doc.basename,
656
665
  )
666
+ filingFormat = pluginData.getFilingFormat(val.modelXbrl)
667
+ if filingFormat is None:
668
+ return
669
+ coverPageRequirements = pluginData.getCoverPageRequirements(val.modelXbrl)
670
+ currentLineNumber = 0
671
+ for qname in pluginData.coverPageItems:
672
+ foundFacts = []
673
+ validNonNilFacts = []
674
+ for fact in pluginData.iterFacts(val.modelXbrl, qname):
675
+ if fact.modelDocument != doc:
676
+ continue
677
+ if fact.qname.prefix is not None and filingFormat.includesTaxonomyPrefix(fact.qname.prefix):
678
+ foundFacts.append(fact)
679
+ if fact.xValid >= VALID and not fact.isNil:
680
+ validNonNilFacts.append(fact)
681
+
682
+ for fact in sorted(foundFacts, key=lambda f: cast(int, f.sourceline)):
683
+ if (sourceLine := cast(int, fact.sourceline)) <= currentLineNumber:
684
+ yield Validation.error(
685
+ codes='EDINET.EC1004E',
686
+ msg=_("Cover item %(localName)s is not in the correct order. "
687
+ "File name: '%(file)s'. "
688
+ "Please correct the order of cover items in the appropriate file."),
689
+ localName=qname.localName,
690
+ file=doc.basename,
691
+ modelObject=fact,
692
+ )
693
+ else:
694
+ currentLineNumber = sourceLine
695
+
696
+ if len(foundFacts) > 1:
697
+ yield Validation.error(
698
+ codes='EDINET.EC1002E',
699
+ msg=_("Cover item %(localName)s is duplicated. "
700
+ "File name: '%(file)s'. "
701
+ "Please check the cover item %(localName)s of the relevant file "
702
+ "and make sure there are no duplicates."),
703
+ localName=qname.localName,
704
+ file=doc.basename,
705
+ modelObject=foundFacts,
706
+ )
707
+
708
+ status = coverPageRequirements.get(qname, filingFormat)
709
+ if status is None:
710
+ continue
711
+ if status == CoverPageItemStatus.REQUIRED:
712
+ if len(foundFacts) == 0:
713
+ yield Validation.error(
714
+ codes='EDINET.EC1001E',
715
+ msg=_("Cover item %(localName)s is missing. "
716
+ "File name: '%(file)s'. "
717
+ "Please add the cover item %(localName)s to the relevant file."),
718
+ localName=qname.localName,
719
+ file=doc.basename,
720
+ )
721
+ elif len(validNonNilFacts) == 0:
722
+ yield Validation.error(
723
+ codes='EDINET.EC1005E',
724
+ msg=_("Cover item %(localName)s is missing a valid value. "
725
+ "File name: '%(file)s'. "
726
+ "Please enter a valid value for %(localName)s in the relevant file."),
727
+ localName=qname.localName,
728
+ file=doc.basename,
729
+ modelObject=foundFacts,
730
+ )
731
+ elif status == CoverPageItemStatus.PROHIBITED:
732
+ for fact in foundFacts:
733
+ if fact.isNil:
734
+ continue # Prohibited cover pages facts are allowed, only if nil.
735
+ yield Validation.error(
736
+ codes='EDINET.EC1003E',
737
+ msg=_("Cover item %(localName)s is not necessary. "
738
+ "File name: '%(file)s' (line %(line)s). "
739
+ "Please add the cover item %(localName)s to the relevant file."),
740
+ localName=qname.localName,
741
+ file=doc.basename,
742
+ line=fact.sourceline,
743
+ modelObject=fact,
744
+ )
657
745
 
658
746
 
659
747
  @validation(
@@ -766,6 +854,77 @@ def rule_uri_references(
766
854
  continue
767
855
 
768
856
 
857
+ @validation(
858
+ hook=ValidationHook.FILESOURCE,
859
+ disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
860
+ )
861
+ def rule_EC1009R(
862
+ pluginData: ControllerPluginData,
863
+ cntlr: Cntlr,
864
+ fileSource: FileSource,
865
+ *args: Any,
866
+ **kwargs: Any,
867
+ ) -> Iterable[Validation]:
868
+ """
869
+ EDINET.EC1009R: The HTML file size must be 2.5MB (megabytes) or less.
870
+ """
871
+ for path, size in pluginData.getUploadFileSizes(fileSource).items():
872
+ if path.suffix not in HTML_EXTENSIONS:
873
+ continue
874
+ if size > 2_500_000:
875
+ yield Validation.warning(
876
+ codes='EDINET.EC1009R',
877
+ msg=_("The HTML file size exceeds the maximum limit. "
878
+ "File name: '%(path)s'. "
879
+ "Please split the file so that the file size is 2.5MB or less."),
880
+ path=str(path),
881
+ )
882
+
883
+
884
+
885
+ @validation(
886
+ hook=ValidationHook.XBRL_FINALLY,
887
+ disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
888
+ )
889
+ def rule_EC1010E(
890
+ pluginData: PluginValidationDataExtension,
891
+ val: ValidateXbrl,
892
+ *args: Any,
893
+ **kwargs: Any,
894
+ ) -> Iterable[Validation]:
895
+ """
896
+ EDINET.EC1010E: The charset specification in the content attribute of the HTML <meta> tag must be UTF-8.
897
+ """
898
+ for modelDocument in val.modelXbrl.urlDocs.values():
899
+ path = Path(modelDocument.uri)
900
+ if path.suffix not in HTML_EXTENSIONS:
901
+ continue
902
+ rootElt = modelDocument.xmlRootElement
903
+ matchingElt = None
904
+ missingElts = []
905
+ for metaElt in rootElt.iterdescendants(tag=XbrlConst.qnXhtmlMeta.clarkNotation):
906
+ if metaElt.qname.localName != 'meta':
907
+ continue
908
+ content = metaElt.get('content')
909
+ if content is None:
910
+ continue
911
+ charset = content.split('charset=')[-1].strip().lower()
912
+ if charset == 'utf-8':
913
+ matchingElt = metaElt
914
+ else:
915
+ missingElts.append(metaElt)
916
+
917
+ if matchingElt is None or len(missingElts) > 0:
918
+ yield Validation.error(
919
+ codes='EDINET.EC1010E',
920
+ msg=_("The charset specification in the content attribute of the HTML <meta> tag is not UTF-8. "
921
+ "File name: '%(path)s'. "
922
+ "Please change the character code of the file to UTF-8."),
923
+ path=str(path),
924
+ modelObject=missingElts
925
+ )
926
+
927
+
769
928
  @validation(
770
929
  hook=ValidationHook.FILESOURCE,
771
930
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
@@ -833,20 +992,22 @@ def rule_EC1017E(
833
992
  hook=ValidationHook.XBRL_FINALLY,
834
993
  disclosureSystems=[DISCLOSURE_SYSTEM_EDINET],
835
994
  )
836
- def rule_EC1020E(
995
+ def rule_html_elements(
837
996
  pluginData: PluginValidationDataExtension,
838
997
  val: ValidateXbrl,
839
998
  *args: Any,
840
999
  **kwargs: Any,
841
1000
  ) -> Iterable[Validation]:
842
1001
  """
1002
+ EDINET.EC1011E: The HTML lang attribute is not Japanese.
843
1003
  EDINET.EC1020E: When writing a DOCTYPE declaration, do not define it multiple times.
844
- Also, please modify the relevant file so that there is only one html tag, one head tag, and one body tag each.
1004
+ Also, please modify the relevant file so that there is only one html tag, one head tag, and one body tag each.
845
1005
 
846
- Note: Some violations of this rule (such as multiple DOCTYPE declarations) prevent Arelle from parsing
1006
+ Note: Some violations of EC1020E (such as multiple DOCTYPE declarations) prevent Arelle from parsing
847
1007
  the XML at all, and thus an XML schema error will be triggered rather than this validation error.
848
1008
  """
849
1009
  checkNames = frozenset({'body', 'head', 'html'})
1010
+ langAttributeValues = frozenset({'ja', 'jp', 'ja-jp', 'JA', 'JP', 'JA-JP'})
850
1011
  for modelDocument in val.modelXbrl.urlDocs.values():
851
1012
  path = Path(modelDocument.uri)
852
1013
  if path.suffix not in HTML_EXTENSIONS:
@@ -857,10 +1018,22 @@ def rule_EC1020E(
857
1018
  }
858
1019
  for elt in rootElt.iterdescendants():
859
1020
  name = elt.qname.localName
860
- if name not in checkNames:
861
- continue
862
- eltCounts[name] = eltCounts.get(name, 0) + 1
863
- pass
1021
+ if name in checkNames:
1022
+ eltCounts[name] = eltCounts.get(name, 0) + 1
1023
+ if not isinstance(elt, ModelFact):
1024
+ lang = elt.get(XbrlConst.qnXmlLang.clarkNotation)
1025
+ if lang is not None and lang not in langAttributeValues:
1026
+ yield Validation.error(
1027
+ codes='EDINET.EC1011E',
1028
+ msg=_("The language setting is not Japanese. "
1029
+ "File name: %(file)s (line %(line)s). "
1030
+ "Please set the lang attribute on the given line of the "
1031
+ "relevant file to one of the following: %(langValues)s."),
1032
+ file=modelDocument.basename,
1033
+ line=elt.sourceline,
1034
+ langValues=', '.join(langAttributeValues),
1035
+ )
1036
+
864
1037
  if any(count > 1 for count in eltCounts.values()):
865
1038
  yield Validation.error(
866
1039
  codes='EDINET.EC1020E',
@@ -35,6 +35,8 @@ SCHEMA_PATTERNS = {
35
35
  "http://www.cro.ie/": re.compile(r"^\d{1,6}$")
36
36
  }
37
37
 
38
+ UK_REF_NS_PATTERN = re.compile(r"^http://xbrl.frc.org.uk/general/\d{4,}-\d{2,}-\d{2,}/ref$")
39
+
38
40
  TR_NAMESPACES = {
39
41
  "http://www.xbrl.org/inlineXBRL/transformation/2010-04-20",
40
42
  "http://www.xbrl.org/inlineXBRL/transformation/2011-07-31",
@@ -12,6 +12,7 @@ from .PluginValidationDataExtension import PluginValidationDataExtension
12
12
 
13
13
  _: TypeGetText
14
14
 
15
+ CURRENCIES_DIMENSION = 'CurrenciesDimension'
15
16
  EQUITY = 'Equity'
16
17
  IE_PROFIT_LOSS = 'ProfitLossBeforeTax'
17
18
  IE_PROFIT_LOSS_ORDINARY = 'ProfitLossOnOrdinaryActivitiesBeforeTax'