arelle-release 2.37.20__py3-none-any.whl → 2.37.22__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/CntlrCmdLine.py CHANGED
@@ -537,6 +537,14 @@ def parseArgs(args):
537
537
  runtimeOptions = RuntimeOptions(pluginOptions=pluginOptions, **baseOptions)
538
538
  except RuntimeOptionsException as e:
539
539
  parser.error(f"{e}, please try\n python CntlrCmdLine.py --help")
540
+ if (
541
+ runtimeOptions.entrypointFile is None and
542
+ not runtimeOptions.proxy and
543
+ not runtimeOptions.plugins and
544
+ not pluginOptions and
545
+ not runtimeOptions.webserver
546
+ ):
547
+ parser.error("No entrypoint specified, please try\n python CntlrCmdLine.py --help")
540
548
  return runtimeOptions, arellePluginModules
541
549
 
542
550
 
arelle/RuntimeOptions.py CHANGED
@@ -183,12 +183,6 @@ class RuntimeOptions:
183
183
  raise RuntimeOptionsException('Provided plugin options already exist as base options {}'.format(existingBaseOptions))
184
184
  for optionName, optionValue in pluginOptions.items():
185
185
  setattr(self, optionName, optionValue)
186
- if (self.entrypointFile is None and
187
- not self.proxy and
188
- not self.plugins and
189
- not pluginOptions and
190
- not self.webserver):
191
- raise RuntimeOptionsException('Incorrect arguments')
192
186
  if self.webserver and not hasWebServer():
193
187
  raise RuntimeOptionsException("Webserver option requires webserver module")
194
188
  if self.webserver and any((
arelle/XbrlConst.py CHANGED
@@ -101,6 +101,7 @@ elementLabel = "http://xbrl.org/arcrole/2008/element-label"
101
101
  genLabel = "http://xbrl.org/2008/label"
102
102
  qnGenLabel = qname("{http://xbrl.org/2008/label}label")
103
103
  xbrldt = "http://xbrl.org/2005/xbrldt"
104
+ qnXbrldtClosed = qname("{http://xbrl.org/2005/xbrldt}xbrldt:closed")
104
105
  qnXbrldtHypercubeItem = qname("{http://xbrl.org/2005/xbrldt}xbrldt:hypercubeItem")
105
106
  qnXbrldtDimensionItem = qname("{http://xbrl.org/2005/xbrldt}xbrldt:dimensionItem")
106
107
  qnXbrldtContextElement = qname("{http://xbrl.org/2005/xbrldt}xbrldt:contextElement")
@@ -108,6 +109,9 @@ xbrldi = "http://xbrl.org/2006/xbrldi"
108
109
  qnXbrldiExplicitMember = qname("{http://xbrl.org/2006/xbrldi}xbrldi:explicitMember")
109
110
  qnXbrldiTypedMember = qname("{http://xbrl.org/2006/xbrldi}xbrldi:typedMember")
110
111
  xlink = "http://www.w3.org/1999/xlink"
112
+ qnXlinkArcRole = qname("{http://www.w3.org/1999/xlink}xlink:arcrole")
113
+ qnXlinkFrom = qname("{http://www.w3.org/1999/xlink}xlink:from")
114
+ qnXlinkType = qname("{http://www.w3.org/1999/xlink}xlink:type")
111
115
  xl = "http://www.xbrl.org/2003/XLink"
112
116
  qnXlExtended = qname("{http://www.xbrl.org/2003/XLink}xl:extended")
113
117
  qnXlLocator = qname("{http://www.xbrl.org/2003/XLink}xl:locator")
arelle/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '2.37.20'
21
- __version_tuple__ = version_tuple = (2, 37, 20)
20
+ __version__ = version = '2.37.22'
21
+ __version_tuple__ = version_tuple = (2, 37, 22)
arelle/api/Session.py CHANGED
@@ -1,26 +1,49 @@
1
1
  """
2
2
  See COPYRIGHT.md for copyright information.
3
3
 
4
- The Arelle Python Beta API (located in `arelle.api` module) is an in-progress API module.
5
- A roadmap for this API is in development.
6
-
7
- Users of this API should expect changes in future releases.
4
+ The `arelle.api` module is the supported method for integrating Arelle into other Python applications.
8
5
  """
9
6
  from __future__ import annotations
10
7
 
11
8
  import logging
9
+ import threading
12
10
  from types import TracebackType
13
11
  from typing import Any, BinaryIO
14
12
 
15
- from arelle import PluginManager, PackageManager
13
+ from arelle import PackageManager, PluginManager
16
14
  from arelle.CntlrCmdLine import CntlrCmdLine, createCntlrAndPreloadPlugins
17
15
  from arelle.ModelXbrl import ModelXbrl
18
16
  from arelle.RuntimeOptions import RuntimeOptions
19
17
 
18
+ _session_lock = threading.Lock()
19
+
20
20
 
21
21
  class Session:
22
+ """
23
+ CRITICAL THREAD SAFETY WARNING:
24
+
25
+ Arelle uses shared global state (PackageManager, PluginManager) which is NOT thread-safe.
26
+ Only ONE Session can run at a time across the entire process.
27
+
28
+ Safe usage:
29
+ - Use one Session at a time per process
30
+ - Use a process pool instead of thread pool for parallelism
31
+
32
+ Unsafe usage:
33
+ - Running multiple Sessions concurrently in any threads
34
+ - Threading.Thread with Session.run()
35
+ """
36
+
22
37
  def __init__(self) -> None:
23
38
  self._cntlr: CntlrCmdLine | None = None
39
+ self._thread_id = threading.get_ident()
40
+
41
+ def _check_thread(self) -> None:
42
+ """Ensure session is only used from the thread that created it."""
43
+ if threading.get_ident() != self._thread_id:
44
+ raise RuntimeError(
45
+ "Session objects cannot be shared between threads. Create a new Session instance in each thread."
46
+ )
24
47
 
25
48
  def __enter__(self) -> Any:
26
49
  return self
@@ -34,9 +57,11 @@ class Session:
34
57
  self.close()
35
58
 
36
59
  def close(self) -> None:
37
- if self._cntlr is not None:
38
- self._cntlr.close()
39
- PluginManager.close()
60
+ with _session_lock:
61
+ self._check_thread()
62
+ if self._cntlr is not None:
63
+ self._cntlr.close()
64
+ PluginManager.close()
40
65
 
41
66
  def get_log_messages(self) -> list[dict[str, Any]]:
42
67
  """
@@ -81,6 +106,7 @@ class Session:
81
106
  responseZipStream: BinaryIO | None = None,
82
107
  logHandler: logging.Handler | None = None,
83
108
  logFilters: list[logging.Filter] | None = None,
109
+ sourceZipStreamFileName: str | None = None,
84
110
  ) -> bool:
85
111
  """
86
112
  Perform a run using the given options.
@@ -88,59 +114,65 @@ class Session:
88
114
  :param sourceZipStream: Optional stream to read source data from.
89
115
  :param responseZipStream: Options stream to write response data to.
90
116
  :param logHandler: Optional log handler to use for logging.
117
+ :param sourceZipStreamFileName: Optional file name to use for the passed zip stream.
91
118
  :return: True if the run was successful, False otherwise.
92
119
  """
93
- PackageManager.reset()
94
- PluginManager.reset()
95
- if self._cntlr is None:
96
- # Certain options must be passed into the controller constructor to have the intended effect
97
- self._cntlr = createCntlrAndPreloadPlugins(
98
- uiLang=options.uiLang,
99
- disablePersistentConfig=options.disablePersistentConfig,
100
- arellePluginModules={},
101
- )
102
- else:
103
- # Certain options passed into the controller constructor need to be updated
104
- if self._cntlr.uiLang != options.uiLang:
105
- self._cntlr.setUiLanguage(options.uiLang)
106
- self._cntlr.disablePersistentConfig = options.disablePersistentConfig or False
107
- logRefObjectProperties = True
108
- if options.logRefObjectProperties is not None:
109
- logRefObjectProperties = options.logRefObjectProperties
110
- if options.webserver:
111
- assert sourceZipStream is None, "Source streaming is not supported with webserver"
112
- assert responseZipStream is None, "Response streaming is not supported with webserver"
113
- if not self._cntlr.logger:
114
- self._cntlr.startLogging(
115
- logFileName='logToBuffer',
116
- logFilters=logFilters,
117
- logHandler=logHandler,
118
- logTextMaxLength=options.logTextMaxLength,
119
- logRefObjectProperties=logRefObjectProperties,
120
- logPropagate=options.logPropagate,
120
+ with _session_lock:
121
+ self._check_thread()
122
+ if sourceZipStreamFileName is not None and sourceZipStream is None:
123
+ raise ValueError("sourceZipStreamFileName may only be provided if sourceZipStream is not None.")
124
+ PackageManager.reset()
125
+ PluginManager.reset()
126
+ if self._cntlr is None:
127
+ # Certain options must be passed into the controller constructor to have the intended effect
128
+ self._cntlr = createCntlrAndPreloadPlugins(
129
+ uiLang=options.uiLang,
130
+ disablePersistentConfig=options.disablePersistentConfig,
131
+ arellePluginModules={},
121
132
  )
122
- self._cntlr.postLoggingInit()
123
- from arelle import CntlrWebMain
124
- CntlrWebMain.startWebserver(self._cntlr, options)
125
- return True
126
- else:
127
- if not self._cntlr.logger:
128
- self._cntlr.startLogging(
129
- logFileName=(options.logFile or "logToPrint"),
130
- logFileMode=options.logFileMode,
131
- logFormat=(options.logFormat or "[%(messageCode)s] %(message)s - %(file)s"),
132
- logLevel=(options.logLevel or "DEBUG"),
133
- logFilters=logFilters,
134
- logHandler=logHandler,
135
- logToBuffer=options.logFile == 'logToBuffer',
136
- logTextMaxLength=options.logTextMaxLength, # e.g., used by EDGAR/render to require buffered logging
137
- logRefObjectProperties=logRefObjectProperties,
138
- logXmlMaxAttributeLength=options.logXmlMaxAttributeLength,
139
- logPropagate=options.logPropagate,
133
+ else:
134
+ # Certain options passed into the controller constructor need to be updated
135
+ if self._cntlr.uiLang != options.uiLang:
136
+ self._cntlr.setUiLanguage(options.uiLang)
137
+ self._cntlr.disablePersistentConfig = options.disablePersistentConfig or False
138
+ logRefObjectProperties = True
139
+ if options.logRefObjectProperties is not None:
140
+ logRefObjectProperties = options.logRefObjectProperties
141
+ if options.webserver:
142
+ assert sourceZipStream is None, "Source streaming is not supported with webserver"
143
+ assert responseZipStream is None, "Response streaming is not supported with webserver"
144
+ if not self._cntlr.logger:
145
+ self._cntlr.startLogging(
146
+ logFileName='logToBuffer',
147
+ logFilters=logFilters,
148
+ logHandler=logHandler,
149
+ logTextMaxLength=options.logTextMaxLength,
150
+ logRefObjectProperties=logRefObjectProperties,
151
+ logPropagate=options.logPropagate,
152
+ )
153
+ self._cntlr.postLoggingInit()
154
+ from arelle import CntlrWebMain
155
+ CntlrWebMain.startWebserver(self._cntlr, options)
156
+ return True
157
+ else:
158
+ if not self._cntlr.logger:
159
+ self._cntlr.startLogging(
160
+ logFileName=(options.logFile or "logToPrint"),
161
+ logFileMode=options.logFileMode,
162
+ logFormat=(options.logFormat or "[%(messageCode)s] %(message)s - %(file)s"),
163
+ logLevel=(options.logLevel or "DEBUG"),
164
+ logFilters=logFilters,
165
+ logHandler=logHandler,
166
+ logToBuffer=options.logFile == 'logToBuffer',
167
+ logTextMaxLength=options.logTextMaxLength, # e.g., used by EDGAR/render to require buffered logging
168
+ logRefObjectProperties=logRefObjectProperties,
169
+ logXmlMaxAttributeLength=options.logXmlMaxAttributeLength,
170
+ logPropagate=options.logPropagate,
171
+ )
172
+ self._cntlr.postLoggingInit() # Cntlr options after logging is started
173
+ return self._cntlr.run(
174
+ options,
175
+ sourceZipStream=sourceZipStream,
176
+ responseZipStream=responseZipStream,
177
+ sourceZipStreamFileName=sourceZipStreamFileName,
140
178
  )
141
- self._cntlr.postLoggingInit() # Cntlr options after logging is started
142
- return self._cntlr.run(
143
- options,
144
- sourceZipStream=sourceZipStream,
145
- responseZipStream=responseZipStream,
146
- )
@@ -3,3 +3,17 @@ DISCLOSURE_SYSTEM_NT17 = 'NT17'
3
3
  DISCLOSURE_SYSTEM_NT18 = 'NT18'
4
4
  DISCLOSURE_SYSTEM_NT19 = 'NT19'
5
5
  DISCLOSURE_SYSTEM_NL_INLINE_2024 = 'NL-INLINE-2024'
6
+ DISCLOSURE_SYSTEM_NL_INLINE_2024_GAAP_OTHER = 'NL-INLINE-2024-GAAP-OTHER'
7
+
8
+ ALL_NL_INLINE_DISCLOSURE_SYSTEMS = [
9
+ DISCLOSURE_SYSTEM_NL_INLINE_2024,
10
+ DISCLOSURE_SYSTEM_NL_INLINE_2024_GAAP_OTHER,
11
+ ]
12
+
13
+ NL_INLINE_GAAP_IFRS_DISCLOSURE_SYSTEMS = [
14
+ DISCLOSURE_SYSTEM_NL_INLINE_2024,
15
+ ]
16
+
17
+ NL_INLINE_GAAP_OTHER_DISCLOSURE_SYSTEMS = [
18
+ DISCLOSURE_SYSTEM_NL_INLINE_2024_GAAP_OTHER,
19
+ ]
@@ -0,0 +1,77 @@
1
+ '''
2
+ See COPYRIGHT.md for copyright information.
3
+ '''
4
+ from __future__ import annotations
5
+
6
+ from enum import Enum
7
+
8
+ from arelle import XbrlConst
9
+ from arelle.ModelValue import QName
10
+
11
+
12
+ class LinkbaseType(Enum):
13
+ CALCULATION = "calculation"
14
+ DEFINITION = "definition"
15
+ LABEL = "label"
16
+ PRESENTATION = "presentation"
17
+ REFERENCE = "reference"
18
+
19
+ @staticmethod
20
+ def fromRefUri(refUri: str | None) -> LinkbaseType | None:
21
+ """
22
+ Returns the LinkbaseType corresponding to the given ref URI.
23
+ If the URI does not match any known linkbase reference type, returns None.
24
+ """
25
+ if refUri is None:
26
+ return None
27
+ return LINKBASE_TYPE_BY_REF_URI.get(refUri, None)
28
+
29
+ def getArcQn(self) -> QName:
30
+ """
31
+ Returns the qname of the arc associated with this LinkbaseType.
32
+ """
33
+ return LINKBASE_ARC_QN[self]
34
+
35
+ def getLinkQn(self) -> QName:
36
+ """
37
+ Returns the qname of the link associated with this LinkbaseType.
38
+ """
39
+ return LINKBASE_LINK_QN[self]
40
+
41
+ def getLowerName(self) -> str:
42
+ """
43
+ Returns the lower-case name of this LinkbaseType.
44
+ """
45
+ return self.value.lower()
46
+
47
+ def getRefUri(self) -> str:
48
+ """
49
+ Returns the ref URI associated with this LinkbaseType.
50
+ """
51
+ return LINKBASE_REF_URIS[self]
52
+
53
+
54
+ LINKBASE_ARC_QN = {
55
+ LinkbaseType.CALCULATION: XbrlConst.qnLinkCalculationArc,
56
+ LinkbaseType.DEFINITION: XbrlConst.qnLinkDefinitionArc,
57
+ LinkbaseType.LABEL: XbrlConst.qnLinkLabelArc,
58
+ LinkbaseType.PRESENTATION: XbrlConst.qnLinkPresentationArc,
59
+ LinkbaseType.REFERENCE: XbrlConst.qnLinkReferenceArc,
60
+ }
61
+
62
+ LINKBASE_LINK_QN = {
63
+ LinkbaseType.CALCULATION: XbrlConst.qnLinkCalculationLink,
64
+ LinkbaseType.DEFINITION: XbrlConst.qnLinkDefinitionLink,
65
+ LinkbaseType.LABEL: XbrlConst.qnLinkLabelLink,
66
+ LinkbaseType.PRESENTATION: XbrlConst.qnLinkPresentationLink,
67
+ LinkbaseType.REFERENCE: XbrlConst.qnLinkReferenceLink,
68
+ }
69
+
70
+ LINKBASE_REF_URIS = {
71
+ LinkbaseType.CALCULATION: "http://www.xbrl.org/2003/role/calculationLinkbaseRef",
72
+ LinkbaseType.DEFINITION: "http://www.xbrl.org/2003/role/definitionLinkbaseRef",
73
+ LinkbaseType.LABEL: "http://www.xbrl.org/2003/role/labelLinkbaseRef",
74
+ LinkbaseType.PRESENTATION: "http://www.xbrl.org/2003/role/presentationLinkbaseRef",
75
+ LinkbaseType.REFERENCE: "http://www.xbrl.org/2003/role/referenceLinkbaseRef",
76
+ }
77
+ LINKBASE_TYPE_BY_REF_URI = {v: k for k, v in LINKBASE_REF_URIS.items()}