arelle-release 2.37.43__py3-none-any.whl → 2.37.45__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.
- arelle/Cntlr.py +35 -0
- arelle/ErrorManager.py +306 -0
- arelle/ModelRelationshipSet.py +1 -1
- arelle/ModelXbrl.py +45 -233
- arelle/Validate.py +2 -0
- arelle/XbrlConst.py +1 -0
- arelle/_version.py +2 -2
- arelle/plugin/validate/EDINET/Constants.py +12 -0
- arelle/plugin/validate/EDINET/ControllerPluginData.py +80 -0
- arelle/plugin/validate/EDINET/{FormType.py → InstanceType.py} +8 -8
- arelle/plugin/validate/EDINET/{Manifest.py → ManifestInstance.py} +78 -33
- arelle/plugin/validate/EDINET/PluginValidationDataExtension.py +35 -10
- arelle/plugin/validate/EDINET/ValidationPluginExtension.py +20 -3
- arelle/plugin/validate/EDINET/__init__.py +4 -22
- arelle/plugin/validate/EDINET/rules/edinet.py +26 -7
- arelle/plugin/validate/EDINET/rules/manifests.py +88 -0
- arelle/plugin/validate/EDINET/rules/upload.py +51 -53
- arelle/plugin/validate/ROS/PluginValidationDataExtension.py +6 -0
- arelle/utils/validate/ESEFImage.py +7 -7
- {arelle_release-2.37.43.dist-info → arelle_release-2.37.45.dist-info}/METADATA +1 -1
- {arelle_release-2.37.43.dist-info → arelle_release-2.37.45.dist-info}/RECORD +25 -22
- {arelle_release-2.37.43.dist-info → arelle_release-2.37.45.dist-info}/WHEEL +0 -0
- {arelle_release-2.37.43.dist-info → arelle_release-2.37.45.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.37.43.dist-info → arelle_release-2.37.45.dist-info}/licenses/LICENSE.md +0 -0
- {arelle_release-2.37.43.dist-info → arelle_release-2.37.45.dist-info}/top_level.txt +0 -0
arelle/ModelXbrl.py
CHANGED
|
@@ -3,23 +3,25 @@ See COPYRIGHT.md for copyright information.
|
|
|
3
3
|
'''
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
import
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
import traceback
|
|
10
|
+
import uuid
|
|
8
11
|
from collections import defaultdict
|
|
9
|
-
from collections.abc import Iterable
|
|
10
12
|
from typing import TYPE_CHECKING, Any, TypeVar, Union, cast, Optional
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
|
|
14
|
+
import regex as re
|
|
15
|
+
from collections.abc import Iterable
|
|
13
16
|
|
|
14
17
|
import arelle
|
|
15
|
-
from arelle import FileSource, ModelRelationshipSet,
|
|
16
|
-
from arelle.
|
|
17
|
-
from arelle.ModelObject import ModelObject, ObjectPropertyViewWrapper
|
|
18
|
-
from arelle.ModelValue import dateUnionEqual
|
|
18
|
+
from arelle import FileSource, ModelRelationshipSet, XmlUtil, ModelValue, XbrlConst, XmlValidate
|
|
19
|
+
from arelle.ErrorManager import ErrorManager
|
|
19
20
|
from arelle.Locale import format_string
|
|
21
|
+
from arelle.ModelObject import ModelObject
|
|
22
|
+
from arelle.ModelValue import dateUnionEqual
|
|
20
23
|
from arelle.PluginManager import pluginClassMethods
|
|
21
24
|
from arelle.PrototypeInstanceObject import FactPrototype, DimValuePrototype
|
|
22
|
-
from arelle.PythonUtil import flattenSequence
|
|
23
25
|
from arelle.UrlUtil import isHttpUrl
|
|
24
26
|
from arelle.ValidateXbrlDimensions import isFactDimensionallyValid
|
|
25
27
|
from arelle.XbrlConst import standardLabel
|
|
@@ -37,7 +39,7 @@ if TYPE_CHECKING:
|
|
|
37
39
|
from arelle.ModelRelationshipSet import ModelRelationshipSet as ModelRelationshipSetClass
|
|
38
40
|
from arelle.ModelValue import QName
|
|
39
41
|
from arelle.PrototypeDtsObject import LinkPrototype
|
|
40
|
-
from arelle.typing import
|
|
42
|
+
from arelle.typing import TypeGetText, LocaleDict
|
|
41
43
|
from arelle.ValidateUtr import UtrEntry
|
|
42
44
|
|
|
43
45
|
_: TypeGetText # Handle gettext
|
|
@@ -52,13 +54,10 @@ AUTO_LOCATE_ELEMENT = '771407c0-1d0c-11e1-be5e-028037ec0200' # singleton meaning
|
|
|
52
54
|
DEFAULT = sys.intern("default")
|
|
53
55
|
NONDEFAULT = sys.intern("non-default")
|
|
54
56
|
DEFAULTorNONDEFAULT = sys.intern("default-or-non-default")
|
|
55
|
-
EMPTY_TUPLE: EmptyTuple = ()
|
|
56
57
|
_NOT_FOUND = object()
|
|
57
58
|
|
|
58
|
-
LoggableValue = Union[str, dict[Any, Any], list[Any], set[Any], tuple[Any, ...]]
|
|
59
|
-
|
|
60
59
|
|
|
61
|
-
def load(modelManager: ModelManager, url: str | FileSourceClass, nextaction: str | None = None, base: str | None = None, useFileSource: FileSourceClass | None = None, errorCaptureLevel:
|
|
60
|
+
def load(modelManager: ModelManager, url: str | FileSourceClass, nextaction: str | None = None, base: str | None = None, useFileSource: FileSourceClass | None = None, errorCaptureLevel: int | None = None, **kwargs: Any) -> ModelXbrl:
|
|
62
61
|
"""Each loaded instance, DTS, testcase, testsuite, versioning report, or RSS feed, is represented by an
|
|
63
62
|
instance of a ModelXbrl object. The ModelXbrl object has a collection of ModelDocument objects, each
|
|
64
63
|
representing an XML document (for now, with SQL whenever its time comes). One of the modelDocuments of
|
|
@@ -111,7 +110,7 @@ def load(modelManager: ModelManager, url: str | FileSourceClass, nextaction: str
|
|
|
111
110
|
|
|
112
111
|
def create(
|
|
113
112
|
modelManager: ModelManager, newDocumentType: int | None = None, url: str | None = None, schemaRefs: str|None = None, createModelDocument: bool = True, isEntry: bool = False,
|
|
114
|
-
errorCaptureLevel:
|
|
113
|
+
errorCaptureLevel: int | None = None, initialXml: str | None = None, initialComment: str | None = None, base: str | None = None, discover: bool = True, xbrliNamespacePrefix: str | None = None
|
|
115
114
|
) -> ModelXbrl:
|
|
116
115
|
modelXbrl = ModelXbrl(modelManager, errorCaptureLevel=errorCaptureLevel)
|
|
117
116
|
modelXbrl.locale = modelManager.locale
|
|
@@ -310,19 +309,18 @@ class ModelXbrl:
|
|
|
310
309
|
_startedTimeStat: float
|
|
311
310
|
_qnameUtrUnits: dict[QName, UtrEntry]
|
|
312
311
|
|
|
313
|
-
def __init__(self, modelManager: ModelManager, errorCaptureLevel:
|
|
312
|
+
def __init__(self, modelManager: ModelManager, errorCaptureLevel: int | None = None) -> None:
|
|
314
313
|
self.modelManager = modelManager
|
|
315
314
|
self.skipDTS: bool = modelManager.skipDTS
|
|
316
315
|
self.init(errorCaptureLevel=errorCaptureLevel)
|
|
317
316
|
|
|
318
|
-
def init(self, keepViews: bool = False, errorCaptureLevel:
|
|
317
|
+
def init(self, keepViews: bool = False, errorCaptureLevel: int | None = None) -> None:
|
|
319
318
|
self.uuid: str = uuid.uuid1().urn
|
|
320
319
|
self.namespaceDocs: defaultdict[str, list[ModelDocumentClass]] = defaultdict(list)
|
|
321
320
|
self.urlDocs: dict[str, ModelDocumentClass] = {}
|
|
322
321
|
self.urlUnloadableDocs: dict[bool, str] = {} # if entry is True, entry is blocked and unloadable, False means loadable but warned
|
|
323
|
-
self.errorCaptureLevel:
|
|
324
|
-
self.
|
|
325
|
-
self.logCount: dict[str, int] = {}
|
|
322
|
+
self.errorCaptureLevel: int = (errorCaptureLevel or logging._checkLevel("INCONSISTENCY")) # type: ignore[attr-defined]
|
|
323
|
+
self.errorManager = ErrorManager(self.modelManager, self.errorCaptureLevel)
|
|
326
324
|
self.arcroleTypes: defaultdict[str, list[ModelRoleType]] = defaultdict(list)
|
|
327
325
|
self.roleTypes: defaultdict[str, list[ModelRoleType]] = defaultdict(list)
|
|
328
326
|
self.qnameConcepts: dict[QName, ModelConcept] = {} # indexed by qname of element
|
|
@@ -361,8 +359,6 @@ class ModelXbrl:
|
|
|
361
359
|
self.logRefObjectProperties: bool = getattr(self.logger, "logRefObjectProperties", False)
|
|
362
360
|
self.logRefHasPluginAttrs: bool = any(True for m in pluginClassMethods("Logging.Ref.Attributes"))
|
|
363
361
|
self.logRefHasPluginProperties: bool = any(True for m in pluginClassMethods("Logging.Ref.Properties"))
|
|
364
|
-
self.logHasRelevelerPlugin: bool = any(True for m in pluginClassMethods("Logging.Severity.Releveler"))
|
|
365
|
-
self.logRefFileRelUris: defaultdict[Any, dict[str, str]] = defaultdict(dict)
|
|
366
362
|
self.profileStats: dict[str, tuple[int, float, float | int]] = {}
|
|
367
363
|
self.schemaDocsToValidate: set[ModelDocumentClass] = set()
|
|
368
364
|
self.modelXbrl = self # for consistency in addressing modelXbrl
|
|
@@ -1011,195 +1007,12 @@ class ModelXbrl:
|
|
|
1011
1007
|
modelObject,
|
|
1012
1008
|
err, traceback.format_tb(sys.exc_info()[2])))
|
|
1013
1009
|
|
|
1014
|
-
def effectiveMessageCode(self, messageCodes: tuple[Any] | str) -> str | None:
|
|
1015
|
-
"""
|
|
1016
|
-
If codes includes EFM, GFM, HMRC, or SBR-coded error then the code chosen (if a sequence)
|
|
1017
|
-
corresponds to whether EFM, GFM, HMRC, or SBR validation is in effect.
|
|
1018
|
-
"""
|
|
1019
|
-
effectiveMessageCode = None
|
|
1020
|
-
_validationType = self.modelManager.disclosureSystem.validationType
|
|
1021
|
-
_exclusiveTypesPattern = self.modelManager.disclosureSystem.exclusiveTypesPattern
|
|
1022
|
-
|
|
1023
|
-
for argCode in messageCodes if isinstance(messageCodes,tuple) else (messageCodes,):
|
|
1024
|
-
if (isinstance(argCode, ModelValue.QName) or
|
|
1025
|
-
(_validationType and argCode and argCode.startswith(_validationType)) or
|
|
1026
|
-
(not _exclusiveTypesPattern or _exclusiveTypesPattern.match(argCode or "") == None)):
|
|
1027
|
-
effectiveMessageCode = argCode
|
|
1028
|
-
break
|
|
1029
|
-
return effectiveMessageCode
|
|
1030
|
-
|
|
1031
1010
|
# isLoggingEffectiveFor( messageCodes= messageCode= level= )
|
|
1032
1011
|
def isLoggingEffectiveFor(self, **kwargs: Any) -> bool: # args can be messageCode(s) and level
|
|
1033
1012
|
logger = self.logger
|
|
1034
1013
|
if logger is None:
|
|
1035
1014
|
return False
|
|
1036
|
-
|
|
1037
|
-
assert hasattr(logger, 'messageLevelFilter'), 'messageLevelFilter not set on controller logger.'
|
|
1038
|
-
if "messageCodes" in kwargs or "messageCode" in kwargs:
|
|
1039
|
-
if "messageCodes" in kwargs:
|
|
1040
|
-
messageCodes = kwargs["messageCodes"]
|
|
1041
|
-
else:
|
|
1042
|
-
messageCodes = kwargs["messageCode"]
|
|
1043
|
-
messageCode = self.effectiveMessageCode(messageCodes)
|
|
1044
|
-
codeEffective = (messageCode and
|
|
1045
|
-
(not logger.messageCodeFilter or logger.messageCodeFilter.match(messageCode)))
|
|
1046
|
-
else:
|
|
1047
|
-
codeEffective = True
|
|
1048
|
-
if "level" in kwargs and logger.messageLevelFilter:
|
|
1049
|
-
levelEffective = logger.messageLevelFilter.match(kwargs["level"].lower())
|
|
1050
|
-
else:
|
|
1051
|
-
levelEffective = True
|
|
1052
|
-
return bool(codeEffective and levelEffective)
|
|
1053
|
-
|
|
1054
|
-
def logArguments(self, messageCode: str, msg: str, codedArgs: dict[str, str]) -> Any:
|
|
1055
|
-
# Prepares arguments for logger function as per info() below.
|
|
1056
|
-
|
|
1057
|
-
def propValues(properties: Any) -> Any:
|
|
1058
|
-
# deref objects in properties
|
|
1059
|
-
return [(p[0], str(p[1])) if len(p) == 2 else (p[0], str(p[1]), propValues(p[2]))
|
|
1060
|
-
for p in properties if 2 <= len(p) <= 3]
|
|
1061
|
-
# determine message and extra arguments
|
|
1062
|
-
fmtArgs: dict[str, LoggableValue] = {}
|
|
1063
|
-
extras: dict[str, Any] = {"messageCode":messageCode}
|
|
1064
|
-
modelObjectArgs: tuple[Any, ...] | list[Any] = ()
|
|
1065
|
-
|
|
1066
|
-
for argName, argValue in codedArgs.items():
|
|
1067
|
-
if argName in ("modelObject", "modelXbrl", "modelDocument"):
|
|
1068
|
-
try:
|
|
1069
|
-
entryUrl = self.modelDocument.uri # type: ignore[union-attr]
|
|
1070
|
-
except AttributeError:
|
|
1071
|
-
try:
|
|
1072
|
-
entryUrl = self.entryLoadingUrl
|
|
1073
|
-
except AttributeError:
|
|
1074
|
-
entryUrl = self.fileSource.url
|
|
1075
|
-
refs: list[dict[str, Any]] = []
|
|
1076
|
-
modelObjectArgs_complex = argValue if isinstance(argValue, (tuple,list,set)) else (argValue,)
|
|
1077
|
-
modelObjectArgs = flattenSequence(modelObjectArgs_complex)
|
|
1078
|
-
for arg in modelObjectArgs:
|
|
1079
|
-
if arg is not None:
|
|
1080
|
-
if isinstance(arg, str):
|
|
1081
|
-
objectUrl = arg
|
|
1082
|
-
else:
|
|
1083
|
-
try:
|
|
1084
|
-
objectUrl = arg.modelDocument.displayUri
|
|
1085
|
-
except AttributeError:
|
|
1086
|
-
try:
|
|
1087
|
-
objectUrl = arg.displayUri
|
|
1088
|
-
except AttributeError:
|
|
1089
|
-
try:
|
|
1090
|
-
objectUrl = self.modelDocument.displayUri # type: ignore[union-attr]
|
|
1091
|
-
except AttributeError:
|
|
1092
|
-
objectUrl = getattr(self, "entryLoadingUrl", "")
|
|
1093
|
-
try:
|
|
1094
|
-
if objectUrl.endswith("/_IXDS"):
|
|
1095
|
-
file = objectUrl[:-6] # inline document set or report package
|
|
1096
|
-
elif objectUrl in self.logRefFileRelUris.get(entryUrl, EMPTY_TUPLE):
|
|
1097
|
-
file = self.logRefFileRelUris[entryUrl][objectUrl]
|
|
1098
|
-
else:
|
|
1099
|
-
file = UrlUtil.relativeUri(entryUrl, objectUrl)
|
|
1100
|
-
self.logRefFileRelUris[entryUrl][objectUrl] = file
|
|
1101
|
-
except:
|
|
1102
|
-
file = ""
|
|
1103
|
-
ref: dict[str, Any] = {}
|
|
1104
|
-
if isinstance(arg,(ModelObject, ObjectPropertyViewWrapper)):
|
|
1105
|
-
_arg:ModelObject = arg.modelObject if isinstance(arg, ObjectPropertyViewWrapper) else arg
|
|
1106
|
-
if len(modelObjectArgs) > 1 and getattr(arg,"tag",None) == "instance":
|
|
1107
|
-
continue # skip IXDS top level element
|
|
1108
|
-
ref["href"] = file + "#" + cast(str, XmlUtil.elementFragmentIdentifier(_arg))
|
|
1109
|
-
ref["sourceLine"] = _arg.sourceline
|
|
1110
|
-
ref["objectId"] = _arg.objectId()
|
|
1111
|
-
if self.logRefObjectProperties:
|
|
1112
|
-
try:
|
|
1113
|
-
ref["properties"] = propValues(arg.propertyView)
|
|
1114
|
-
except AttributeError:
|
|
1115
|
-
pass # is a default properties entry appropriate or needed?
|
|
1116
|
-
if self.logRefHasPluginProperties:
|
|
1117
|
-
refProperties: Any = ref.get("properties", {})
|
|
1118
|
-
for pluginXbrlMethod in pluginClassMethods("Logging.Ref.Properties"):
|
|
1119
|
-
pluginXbrlMethod(arg, refProperties, codedArgs)
|
|
1120
|
-
if refProperties:
|
|
1121
|
-
ref["properties"] = refProperties
|
|
1122
|
-
else:
|
|
1123
|
-
ref["href"] = file
|
|
1124
|
-
try:
|
|
1125
|
-
ref["sourceLine"] = arg.sourceline
|
|
1126
|
-
except AttributeError:
|
|
1127
|
-
pass # arg may not have sourceline, ignore if so
|
|
1128
|
-
if self.logRefHasPluginAttrs:
|
|
1129
|
-
refAttributes: dict[str, str] = {}
|
|
1130
|
-
for pluginXbrlMethod in pluginClassMethods("Logging.Ref.Attributes"):
|
|
1131
|
-
pluginXbrlMethod(arg, refAttributes, codedArgs)
|
|
1132
|
-
if refAttributes:
|
|
1133
|
-
ref["customAttributes"] = refAttributes
|
|
1134
|
-
refs.append(ref)
|
|
1135
|
-
extras["refs"] = refs
|
|
1136
|
-
elif argName == "sourceFileLine":
|
|
1137
|
-
# sourceFileLines is pairs of file and line numbers, e.g., ((file,line),(file2,line2),...)
|
|
1138
|
-
ref = {}
|
|
1139
|
-
if isinstance(argValue, (tuple,list)):
|
|
1140
|
-
ref["href"] = str(argValue[0])
|
|
1141
|
-
if len(argValue) > 1 and argValue[1]:
|
|
1142
|
-
ref["sourceLine"] = str(argValue[1])
|
|
1143
|
-
else:
|
|
1144
|
-
ref["href"] = str(argValue)
|
|
1145
|
-
extras["refs"] = [ref]
|
|
1146
|
-
elif argName == "sourceFileLines":
|
|
1147
|
-
# sourceFileLines is tuple/list of pairs of file and line numbers, e.g., ((file,line),(file2,line2),...)
|
|
1148
|
-
sf_refs: list[dict[str, str]] = []
|
|
1149
|
-
argvalues: tuple[Any, ...] | list[Any] = argValue if isinstance(argValue, (tuple, list)) else (argValue,)
|
|
1150
|
-
for arg in argvalues:
|
|
1151
|
-
ref = {}
|
|
1152
|
-
if isinstance(arg, (tuple, list)):
|
|
1153
|
-
arg_: tuple[Any, ...] | list[Any] = arg
|
|
1154
|
-
ref["href"] = str(arg_[0])
|
|
1155
|
-
if len(arg_) > 1 and arg_[1]:
|
|
1156
|
-
ref["sourceLine"] = str(arg_[1])
|
|
1157
|
-
else:
|
|
1158
|
-
ref["href"] = str(arg)
|
|
1159
|
-
sf_refs.append(ref)
|
|
1160
|
-
extras["refs"] = sf_refs
|
|
1161
|
-
elif argName == "sourceLine":
|
|
1162
|
-
if isinstance(argValue, int): # must be sortable with int's in logger
|
|
1163
|
-
extras["sourceLine"] = argValue
|
|
1164
|
-
elif argName not in ("exc_info", "messageCodes"):
|
|
1165
|
-
fmtArgs[argName] = self.loggableValue(argValue) # dereference anything not loggable
|
|
1166
|
-
|
|
1167
|
-
if "refs" not in extras:
|
|
1168
|
-
try:
|
|
1169
|
-
file = os.path.basename(cast('ModelDocumentClass', self.modelDocument).displayUri)
|
|
1170
|
-
except AttributeError:
|
|
1171
|
-
try:
|
|
1172
|
-
file = os.path.basename(self.entryLoadingUrl)
|
|
1173
|
-
except:
|
|
1174
|
-
file = ""
|
|
1175
|
-
extras["refs"] = [{"href": file}]
|
|
1176
|
-
for pluginXbrlMethod in pluginClassMethods("Logging.Message.Parameters"):
|
|
1177
|
-
# plug in can rewrite msg string or return msg if not altering msg
|
|
1178
|
-
msg = pluginXbrlMethod(messageCode, msg, modelObjectArgs, fmtArgs) or msg
|
|
1179
|
-
return (messageCode,
|
|
1180
|
-
(msg, fmtArgs) if fmtArgs else (msg,),
|
|
1181
|
-
extras)
|
|
1182
|
-
|
|
1183
|
-
def loggableValue(self, argValue: Any) -> LoggableValue: # must be dereferenced and not related to object lifetimes
|
|
1184
|
-
if argValue is None:
|
|
1185
|
-
return "(none)"
|
|
1186
|
-
if isinstance(argValue, bool):
|
|
1187
|
-
return str(argValue).lower() # show lower case true/false xml values
|
|
1188
|
-
if isinstance(argValue, int):
|
|
1189
|
-
# need locale-dependent formatting
|
|
1190
|
-
return format_string(self.modelManager.locale, '%i', argValue)
|
|
1191
|
-
if isinstance(argValue, (float, Decimal)):
|
|
1192
|
-
# need locale-dependent formatting
|
|
1193
|
-
return format_string(self.modelManager.locale, '%f', argValue)
|
|
1194
|
-
if isinstance(argValue, tuple):
|
|
1195
|
-
return tuple(self.loggableValue(x) for x in argValue)
|
|
1196
|
-
if isinstance(argValue, list):
|
|
1197
|
-
return [self.loggableValue(x) for x in argValue]
|
|
1198
|
-
if isinstance(argValue, set):
|
|
1199
|
-
return {self.loggableValue(x) for x in argValue}
|
|
1200
|
-
if isinstance(argValue, dict):
|
|
1201
|
-
return dict((self.loggableValue(k), self.loggableValue(v)) for k, v in argValue.items())
|
|
1202
|
-
return str(argValue)
|
|
1015
|
+
return self.errorManager.isLoggingEffectiveFor(logger, **kwargs)
|
|
1203
1016
|
|
|
1204
1017
|
def debug(self, codes: str | tuple[str, ...], msg: str, **args: Any) -> None:
|
|
1205
1018
|
"""Same as error(), but as info
|
|
@@ -1222,33 +1035,24 @@ class ModelXbrl:
|
|
|
1222
1035
|
def log(self, level: str, codes: Any, msg: str, **args: Any) -> None:
|
|
1223
1036
|
"""Same as error(), but level passed in as argument
|
|
1224
1037
|
"""
|
|
1225
|
-
|
|
1226
|
-
if logger is None:
|
|
1227
|
-
return
|
|
1228
|
-
assert hasattr(logger, 'messageCodeFilter'), 'messageCodeFilter not set on controller logger.'
|
|
1229
|
-
assert hasattr(logger, 'messageLevelFilter'), 'messageLevelFilter not set on controller logger.'
|
|
1230
|
-
# determine logCode
|
|
1231
|
-
messageCode = self.effectiveMessageCode(codes)
|
|
1232
|
-
if messageCode == "asrtNoLog":
|
|
1233
|
-
self.errors.append(args["assertionResults"])
|
|
1038
|
+
if self.logger is None:
|
|
1234
1039
|
return
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
logger.log(numericLevel, *logArgs, exc_info=args.get("exc_info"), extra=extras)
|
|
1040
|
+
entryLoadingUrl = None
|
|
1041
|
+
try:
|
|
1042
|
+
entryLoadingUrl = self.entryLoadingUrl
|
|
1043
|
+
except AttributeError:
|
|
1044
|
+
pass
|
|
1045
|
+
self.errorManager.log(
|
|
1046
|
+
self.logger,
|
|
1047
|
+
level,
|
|
1048
|
+
codes,
|
|
1049
|
+
msg,
|
|
1050
|
+
sourceModelXbrl=self,
|
|
1051
|
+
fileSource=self.fileSource,
|
|
1052
|
+
entryLoadingUrl=entryLoadingUrl,
|
|
1053
|
+
logRefObjectProperties=self.logRefObjectProperties,
|
|
1054
|
+
**args
|
|
1055
|
+
)
|
|
1252
1056
|
|
|
1253
1057
|
def error(self, codes: str | tuple[str, ...], msg: str, **args: Any) -> None:
|
|
1254
1058
|
"""Logs a message as info, by code, logging-system message text (using %(name)s named arguments
|
|
@@ -1373,3 +1177,11 @@ class ModelXbrl:
|
|
|
1373
1177
|
qnameUtrUnits[unitQName] = unit
|
|
1374
1178
|
self._qnameUtrUnits = qnameUtrUnits
|
|
1375
1179
|
return self._qnameUtrUnits
|
|
1180
|
+
|
|
1181
|
+
@property
|
|
1182
|
+
def errors(self) -> list[str | None]:
|
|
1183
|
+
return self.errorManager.errors
|
|
1184
|
+
|
|
1185
|
+
@property
|
|
1186
|
+
def logCount(self) -> dict[str, int]:
|
|
1187
|
+
return self.errorManager.logCount
|
arelle/Validate.py
CHANGED
|
@@ -298,6 +298,7 @@ class Validate:
|
|
|
298
298
|
self._testcaseValidateInputDTS(testcase, modelTestcaseVariation, errorCaptureLevel, parameters, inputDTSes, baseForElement, resultIsXbrlInstance)
|
|
299
299
|
# update ui thread via modelManager (running in background here)
|
|
300
300
|
self.modelXbrl.modelManager.viewModelObject(self.modelXbrl, modelTestcaseVariation.objectId())
|
|
301
|
+
self.modelXbrl.modelManager.cntlr.testcaseVariationReset()
|
|
301
302
|
modelTestcaseVariation.duration = time.perf_counter() - startTime
|
|
302
303
|
|
|
303
304
|
def _testcaseLoadReadMeFirstUri(self, testcase, modelTestcaseVariation, index, readMeFirstUri, resultIsVersioningReport, resultIsTaxonomyPackage, inputDTSes, errorCaptureLevel, baseForElement, parameters):
|
|
@@ -730,6 +731,7 @@ class Validate:
|
|
|
730
731
|
_errors = [e for e in errors if isinstance(e,str) and not _blockPattern.match(e)]
|
|
731
732
|
else:
|
|
732
733
|
_errors = errors
|
|
734
|
+
_errors.extend(self.modelXbrl.modelManager.cntlr.errors)
|
|
733
735
|
numErrors = sum(isinstance(e,(QName,str)) for e in _errors) # does not include asserton dict results
|
|
734
736
|
hasAssertionResult = any(isinstance(e,dict) for e in _errors)
|
|
735
737
|
expected = modelTestcaseVariation.expected
|
arelle/XbrlConst.py
CHANGED
|
@@ -40,6 +40,7 @@ builtinAttributes = {
|
|
|
40
40
|
}
|
|
41
41
|
ref2004 = "http://www.xbrl.org/2004/ref"
|
|
42
42
|
ref2006 = "http://www.xbrl.org/2006/ref"
|
|
43
|
+
svg = "http://www.w3.org/2000/svg"
|
|
43
44
|
xml = "http://www.w3.org/XML/1998/namespace"
|
|
44
45
|
xbrli = "http://www.xbrl.org/2003/instance"
|
|
45
46
|
xhtmlBaseIdentifier = "{http://www.w3.org/1999/xhtml}base"
|
arelle/_version.py
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
"""
|
|
2
2
|
See COPYRIGHT.md for copyright information.
|
|
3
3
|
"""
|
|
4
|
+
from enum import Enum
|
|
5
|
+
|
|
4
6
|
from arelle.ModelValue import qname
|
|
5
7
|
|
|
8
|
+
class FormType(Enum):
|
|
9
|
+
FORM_2_4 = '第二号の四様式'
|
|
10
|
+
FORM_2_7 = '第二号の七様式'
|
|
11
|
+
FORM_3 = '第三号様式'
|
|
12
|
+
|
|
13
|
+
CORPORATE_FORMS =frozenset([
|
|
14
|
+
FormType.FORM_2_4,
|
|
15
|
+
FormType.FORM_2_7,
|
|
16
|
+
FormType.FORM_3,
|
|
17
|
+
])
|
|
6
18
|
qnEdinetManifestInsert = qname("{http://disclosure.edinet-fsa.go.jp/2013/manifest}insert")
|
|
7
19
|
qnEdinetManifestInstance = qname("{http://disclosure.edinet-fsa.go.jp/2013/manifest}instance")
|
|
8
20
|
qnEdinetManifestItem = qname("{http://disclosure.edinet-fsa.go.jp/2013/manifest}item")
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""
|
|
2
|
+
See COPYRIGHT.md for copyright information.
|
|
3
|
+
"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from arelle.Cntlr import Cntlr
|
|
10
|
+
from arelle.typing import TypeGetText
|
|
11
|
+
from arelle.utils.PluginData import PluginData
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from .ManifestInstance import ManifestInstance
|
|
15
|
+
|
|
16
|
+
_: TypeGetText
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class ControllerPluginData(PluginData):
|
|
21
|
+
_manifestInstancesById: dict[str, ManifestInstance]
|
|
22
|
+
|
|
23
|
+
def __init__(self, name: str):
|
|
24
|
+
super().__init__(name)
|
|
25
|
+
self._manifestInstancesById = {}
|
|
26
|
+
|
|
27
|
+
def __hash__(self) -> int:
|
|
28
|
+
return id(self)
|
|
29
|
+
|
|
30
|
+
def addManifestInstance(self, manifestInstance: ManifestInstance) -> None:
|
|
31
|
+
"""
|
|
32
|
+
Add a manifest instance with unique ID to the plugin data.
|
|
33
|
+
"""
|
|
34
|
+
self._manifestInstancesById[manifestInstance.id] = manifestInstance
|
|
35
|
+
|
|
36
|
+
def getManifestInstances(self) -> list[ManifestInstance]:
|
|
37
|
+
"""
|
|
38
|
+
Retrieve all loaded manifest instances.
|
|
39
|
+
"""
|
|
40
|
+
return list(self._manifestInstancesById.values())
|
|
41
|
+
|
|
42
|
+
def matchManifestInstance(self, ixdsDocUrls: list[str]) -> ManifestInstance | None:
|
|
43
|
+
"""
|
|
44
|
+
Match a manifest instance based on the provided ixdsDocUrls.
|
|
45
|
+
A one-to-one mapping must exist between the model's IXDS document URLs and the manifest instance's IXBRL files.
|
|
46
|
+
:param ixdsDocUrls: A model's list of IXDS document URLs.
|
|
47
|
+
:return: A matching ManifestInstance if found, otherwise None.
|
|
48
|
+
"""
|
|
49
|
+
modelUrls = set(ixdsDocUrls)
|
|
50
|
+
matchedInstance = None
|
|
51
|
+
for instance in self._manifestInstancesById.values():
|
|
52
|
+
if len(instance.ixbrlFiles) != len(ixdsDocUrls):
|
|
53
|
+
continue
|
|
54
|
+
manifestUrls = {str(path) for path in instance.ixbrlFiles}
|
|
55
|
+
unmatchedModelUrls = set(modelUrls)
|
|
56
|
+
unmatchedManifestUrls = set(manifestUrls)
|
|
57
|
+
for modelUrl in modelUrls:
|
|
58
|
+
if modelUrl not in unmatchedModelUrls:
|
|
59
|
+
continue
|
|
60
|
+
for manifestUrl in manifestUrls:
|
|
61
|
+
if modelUrl.endswith(manifestUrl):
|
|
62
|
+
unmatchedModelUrls.remove(modelUrl)
|
|
63
|
+
unmatchedManifestUrls.remove(manifestUrl)
|
|
64
|
+
break
|
|
65
|
+
if len(unmatchedModelUrls) > 0:
|
|
66
|
+
continue
|
|
67
|
+
if len(unmatchedManifestUrls) > 0:
|
|
68
|
+
continue
|
|
69
|
+
matchedInstance = instance
|
|
70
|
+
break
|
|
71
|
+
return matchedInstance
|
|
72
|
+
|
|
73
|
+
@staticmethod
|
|
74
|
+
def get(cntlr: Cntlr, name: str) -> ControllerPluginData:
|
|
75
|
+
controllerPluginData = cntlr.getPluginData(name)
|
|
76
|
+
if controllerPluginData is None:
|
|
77
|
+
controllerPluginData = ControllerPluginData(name)
|
|
78
|
+
cntlr.setPluginData(controllerPluginData)
|
|
79
|
+
assert isinstance(controllerPluginData, ControllerPluginData), "Expected ControllerPluginData instance."
|
|
80
|
+
return controllerPluginData
|
|
@@ -8,7 +8,7 @@ from functools import cached_property, lru_cache
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
class
|
|
11
|
+
class InstanceType(Enum):
|
|
12
12
|
ATTACH_DOC = "AttachDoc"
|
|
13
13
|
AUDIT_DOC = "AuditDoc"
|
|
14
14
|
ENGLISH_DOC = "EnglishDoc"
|
|
@@ -17,7 +17,7 @@ class FormType(Enum):
|
|
|
17
17
|
PUBLIC_DOC = "PublicDoc"
|
|
18
18
|
|
|
19
19
|
@classmethod
|
|
20
|
-
def parse(cls, value: str) ->
|
|
20
|
+
def parse(cls, value: str) -> InstanceType | None:
|
|
21
21
|
try:
|
|
22
22
|
return cls(value)
|
|
23
23
|
except ValueError:
|
|
@@ -60,12 +60,12 @@ class ExtensionCategory(Enum):
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
FORM_TYPE_EXTENSION_CATEGORIES = {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
InstanceType.ATTACH_DOC: ExtensionCategory.ATTACH,
|
|
64
|
+
InstanceType.AUDIT_DOC: ExtensionCategory.DOC,
|
|
65
|
+
InstanceType.ENGLISH_DOC: ExtensionCategory.ENGLISH_DOC,
|
|
66
|
+
InstanceType.PRIVATE_ATTACH: ExtensionCategory.ATTACH,
|
|
67
|
+
InstanceType.PRIVATE_DOC: ExtensionCategory.DOC,
|
|
68
|
+
InstanceType.PUBLIC_DOC: ExtensionCategory.DOC,
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
|