Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
__pluginInfo__ = {
'name': 'EDGAR',
'version': '3.26.1',
'description': "This plug-in implements U.S. SEC Edgar Renderer. Arelle version at SEC: 2.38.9 ",
'version': '3.26.2',
'description': "This plug-in implements U.S. SEC Edgar Renderer. Arelle version at SEC: 2.40.1 ",
'license': 'Apache-2',
'author': 'U.S. SEC Employees and Mark V Systems Limited',
'copyright': '(c) Portions by SEC Employees not subject to domestic copyright, otherwise (c) Copyright 2015 Mark V Systems Limited, All rights reserved.',
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
The EDGAR plugin, developed and maintained by the staff of the U.S. Securities and Exchange Commission (SEC), is designed to provide traditional and inline XBRL viewers for SEC filings. It also integrates with and extends the EFM Validation plugin, offering EFM validation for SEC filings. For end-user support, please contact the SEC directly at: StructuredData@sec.gov.

## Arelle Version
The current version of Arelle in use at the SEC is: **2.38.9**
The current version of Arelle in use at the SEC is: **2.40.1**

## Installation
The EDGAR plugin requires the xule plugin to be present under the Arelle plugin directory. You can clone the xule repository into the plugin directory.
Expand Down
5 changes: 3 additions & 2 deletions render/Filing.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ def __init__(self, controller, report, outputFolderName, transform, suplSuffix,
self.builtinEquityRowAxes = [('us-gaap', self.usgaapNamespace, 'CreationDateAxis'), # us-gaap deprecated 2019 absent after 2021.
('ifrs-full', self.ifrsNamespace, 'CreationDateAxis'),
('us-gaap', self.usgaapNamespace, 'StatementScenarioAxis'),
('us-gaap', self.usgaapNamespace, 'RestatementAxis'),
('us-gaap', self.usgaapNamespace, 'AdjustmentsForNewAccountingPronouncementsAxis'),
('us-gaap', self.usgaapNamespace, 'AdjustmentsForChangeInAccountingPrincipleAxis'),
('us-gaap', self.usgaapNamespace, 'ErrorCorrectionsAndPriorPeriodAdjustmentsRestatementByRestatementPeriodAndAmountAxis'),
Expand Down Expand Up @@ -427,7 +428,7 @@ def factSortKey (fact):
return ("", "", 0)
if fact.isNumeric:
if fact.isNil: discriminator = float("INF") # Null values always last
elif fact.decimals is None: discriminator = 0 # Can happen with invalid xbrl
elif fact.decimals is None or not Utils.is_number(fact.decimals): discriminator = 0 # Can happen with invalid xbrl
else: discriminator = 0 - float(fact.decimals) # Larger decimal values come first
else: # non-numeric
if fact.isNil: discriminator = '\uffff' # Null values always last (highest 2-byte unicode character)
Expand Down Expand Up @@ -656,7 +657,7 @@ def factSortKey (fact):
_("Context %(contextID)s explicit dimension %(dimension)s member %(value)s is not a global member item"),
modelObject=(arelleDimension, fact), contextID=fact.context.id,
dimension=arelleDimension.dimensionQname, value=arelleDimension.memberQname)
elif arelleDimension.isTyped and arelleDimension.typedMember.xValid < VALID:
elif arelleDimension.isTyped and arelleDimension.typedMember is not None and arelleDimension.typedMember.xValid < VALID:
self.modelXbrl.debug("debug",
_("Context %(contextID)s typed dimension %(dimension)s member %(value)s is not an xml schema validated value"),
modelObject=(arelleDimension, fact), contextID=fact.context.id,
Expand Down
2 changes: 1 addition & 1 deletion render/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ domestic copyright protection. 17 U.S.C. 105.
End user support is by e-mail direct to SEC at: [StructuredData@sec.gov]
(mailto:StructuredData@sec.gov).

This is EDGAR release 26.1, planned for production March, 2026.
This is EDGAR release 26.2, planned for production June, 2026.

Developer issue management is by the Jira Edgar Renderer project: https://arelle.atlassian.net/projects/ER

Expand Down
2 changes: 1 addition & 1 deletion render/Report.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ def scaleUnitGlobally(self): # so far currencies and shares.
exampleFact = fact
if symbol is None:
symbol = Utils.getSymbolStr(fact) or unitID
if fact.decimals.casefold() == 'inf' or maxSoFar > -3:
if fact.decimals.casefold() == 'inf' or maxSoFar > -3 or not Utils.is_number(fact.decimals):
maxSoFar = 0
break # to be scaled, every fact must have a decimals value of -3 or less. inf inhibits scaling.
else:
Expand Down
8 changes: 8 additions & 0 deletions render/Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,14 @@ def embeddingGarbageCollect(embedding):
embedding.__dict__.clear()


def is_number(val):
try:
n = float(val)
return math.isfinite(n) # Returns False for NaN and Inf
except ValueError:
return False


class RenderingException(Exception):

def __init__(self, code, message):
Expand Down
4 changes: 2 additions & 2 deletions render/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
GUI may use tools->language labels setting to override system language for labels

"""
VERSION = '3.26.1'
VERSION = '3.26.2'

from collections import defaultdict
from arelle import PythonUtil
Expand Down Expand Up @@ -2232,7 +2232,7 @@ def removeElementsWithDocumentReference(modelXbrl, document):
__pluginInfo__ = {
'name': 'Edgar Renderer',
'version': VERSION,
'description': "This plug-in implements U.S. SEC Edgar Renderer. Arelle version at SEC: 2.38.9 ",
'description': "This plug-in implements U.S. SEC Edgar Renderer. Arelle version at SEC: 2.39.8 ",
'license': 'Apache-2',
'author': 'U.S. SEC Employees and Mark V Systems Limited',
'copyright': '(c) Portions by SEC Employees not subject to domestic copyright, otherwise (c) Copyright 2015 Mark V Systems Limited, All rights reserved.',
Expand Down
7 changes: 4 additions & 3 deletions validate/Consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@
}
docTypesSubType = {
"2.01 SD": "SD",
"EX-99.4R HISTORIC": "N-4"
"EX-99.4R HISTORIC": "N-4",
"COMPL RPT": "SBSE-CCO-RPT"
# default is submissionType parameter is the same as dei:DocumentType
}

Expand All @@ -69,11 +70,11 @@
)
supplementalAttachmentDocumentTypesPattern = re.compile(r"EX-FILING FEES.*|EX-99\.[C-S]\.SBSEF.*|EX-98.*|EX-99.4R HISTORIC|EX-26")
exhibitTypesStrippingOnErrorPattern = re.compile(r"EX-26.*|EX-99\.[C-S]\.SBSEF.*|EX-98.*")
exhibitTypesPrivateNotDisseminated = re.compile(r"EX-99\.[DEFHIJKNOPQRS]\.SBSEF")
exhibitTypesPrivateNotDisseminated = re.compile(r"EX-99\.[DEFHIJKNOPQRS]\.SBSEF|COMPL RPT")
primaryAttachmentDocumentTypesPattern = re.compile(r"(?!EX-)")
# for the below, group the attachmentDocumentType so that we can extract the correct value.
# Example EX-98.1 can become EX-98 based on the group
attachmentDocumentTypeReqSubDocTypePattern = re.compile(r"(EX-98).*")
attachmentDocumentTypeReqSubDocTypePattern = re.compile(r"(EX-98|EX-99\.4R HISTORIC).*")
nsPatternNotAllowedinxBRLXML = re.compile(r".*sec.gov/spac/.*")
subTypesWarningforxBRLXml = [
"S-1", "S-1/A", "S-1MEF", "S-4", "S-4/A", "S-4MEF", "S-4EF", "S-4POS", "F-1", "F-1/A", "F-1MEF", "F-4", "F-4/A", "F-4MEF",
Expand Down
41 changes: 31 additions & 10 deletions validate/Filing.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def validateFiling(val, modelXbrl, isEFM=False, isGFM=False):
styleIxHiddenPattern = re.compile(r"(.*[^\w]|^)-sec-ix-hidden\s*:\s*([\w.-]+).*")
styleIxRedactPattern = re.compile(r"(.*;)?\s*-sec-ix-redact\s*:\s*true(?:\s*;)?\s*([\w.-].*)?$")
efmRoleDefinitionPattern = re.compile(r"([0-9]+) - (Statement|Disclosure|Schedule|Document) - (.+)")
messageKeySectionPattern = re.compile(r"(.*[{]efmSection[}]|[a-z]{2}-[0-9]{4})(.*)")
messageKeySectionPattern = re.compile(r"(.*[{]efmSection[}]|[a-z]{2}-[0-9]{4}|dq-)(.*)")
secDomainPattern = re.compile(r"(fasb\.org|xbrl\.sec\.gov)")

val._isStandardUri = {}
Expand Down Expand Up @@ -649,9 +649,17 @@ def hasDeiFact(deiName):
val.entityRegistrantName = deiItems.get("EntityRegistrantName") # used for name check in 6.8.6

# 6.05..23,24 check (after dei facts read)
if not (isEFM and deiDocumentType == "L SDR"): # allow entityIdentifierValue == "0000000000" or any other CIK value
if not (isEFM and deiDocumentType in ("L SDR", "K SDR")): # allow entityIdentifierValue == "0000000000" or any other CIK value
if disclosureSystem.deiFilerIdentifierElement in deiItems:
value = deiItems.get(disclosureSystem.deiFilerIdentifierElement)
if value == "0000000000":
# XBRL Guide 3.1.3 Central Index Key
# A dei:EntityCentralIndexKey fact with value a full ten-digit CIK other than 0000000000 from among the co-registrants in the submission header.
val.modelXbrl.error("EFM.6.05.02",
_("The %(elementName)s, %(value)s, must be a full 10-digit CIK other than 0000000000."),
edgarCode="cp-0502-Non-Matching-Cik",
modelObject=deiFilerIdentifierFact, elementName=disclosureSystem.deiFilerIdentifierElement,
value=value)
if entityIdentifierValue != value:
val.modelXbrl.error(("EFM.6.05.23", "GFM.3.02.02"),
_("The EntityCentralIndexKey, %(value)s, does not match the context identifier CIK %(entityIdentifier)s. "
Expand Down Expand Up @@ -1125,15 +1133,20 @@ def sevMessage(sev, messageKey=None, **kwargs):
# replacement for efmSection. Based on sev msgSection
if sev.get("msgSection"):
msgPrefix, _sep, msgSectionNumber = sev["msgSection"].partition(":")
logArgs[f"{msgPrefix.lower()}Section"] = msgPrefix
logArgs["arelleCode"] = msgPrefix
section = f"{msgPrefix.lower()}Section"
logArgs[section] = ""
for i, e in enumerate(msgSectionNumber.split(".")):
if i > 0 :
if e.isnumeric(): # e.g. [6,5,2] -> "6.05.02"
e = e.zfill(2)
logArgs["arelleCode"] += "." + e
logArgs[section] += e

logArgs["edgarCode"] = messageKey # edgar code is the un-expanded key for message with {...}'s
if "-{efmSection}" in logArgs["edgarCode"] and not logArgs.get("efmSection") and logArgs.get("exgSection"):
logArgs["edgarCode"] = logArgs["edgarCode"].replace("-{efmSection}", "")

try:
m = messageKeySectionPattern.match(messageKey or "")
if m:
Expand Down Expand Up @@ -2094,7 +2107,13 @@ def find_fact_in_context(contextID, name=None):
elif validation == "not-in-future":
for name in names:
for f in sevFacts(sev, name):
if deiDocumentType and f.context.endDatetime > documentTypeFact.context.endDatetime:
if (
deiDocumentType
# invalid context may not have endDatetime
and f.context.endDatetime
and documentTypeFact.context.endDatetime
and f.context.endDatetime > documentTypeFact.context.endDatetime
):
sevMessage(sev, subType=submissionType, modelObject=f, efmSection=efmSection, tag=name, context="context " + f.contextID)

elif validation in ("ru", "ou"):
Expand Down Expand Up @@ -2145,10 +2164,12 @@ def find_fact_in_context(contextID, name=None):
if fr is None and f is not None:
sevMessage(sev, subType=submissionType, modelObject=sevFacts(sev), tag=name, otherTag=referenceTag, value=fr.xValue, contextID=fr.contextID)
elif validation == "required-context-duration":
monthsDuration = (val.requiredContext.endDatetime - val.requiredContext.startDatetime).days / 30.4375 # 30.4375 specified by DERA to use in the transforms for days to months
if not value - 1 < monthsDuration < value + 1: # fractional months likely due to days per month
sevMessage(sev, subType=submissionType, modelObject=val.requiredContext, tag="Required Context Period Duration",
value=f"{monthsDuration:.1f} months", expectedValue=f"{value} months", contextID=val.requiredContext.id)
# ensure a valid context is provided with endDatetime and startDatetime
if val.requiredContext.endDatetime and val.requiredContext.startDatetime:
monthsDuration = (val.requiredContext.endDatetime - val.requiredContext.startDatetime).days / 30.4375 # 30.4375 specified by DERA to use in the transforms for days to months
if not value - 1 < monthsDuration < value + 1: # fractional months likely due to days per month
sevMessage(sev, subType=submissionType, modelObject=val.requiredContext, tag="Required Context Period Duration",
value=f"{monthsDuration:.1f} months", expectedValue=f"{value} months", contextID=val.requiredContext.id)
# fee tagging
elif validation in ("fe", "fw","fo"):
instDurNames = defaultdict(list)
Expand Down Expand Up @@ -2554,7 +2575,7 @@ def getEvalFunctionStringAndArgs(sev, functionName, argumentsKey="function-argum
perEnd = fr.xValue + ONE_DAY
for name in names:
f = sevFact(sev, name)
if f is not None:
if f is not None and f.context.endDatetime and f.context.startDatetime:
monthsDuration = (f.context.endDatetime - f.context.startDatetime).days / 30.4375 # 30.4375 specified by DERA to use in the transforms for days to months
if f.context.endDatetime != perEnd or not 11 < monthsDuration < 13:
sevMessage(sev, subType=submissionType, modelObject=sevFacts(sev), tag=name, otherTag=referenceTag, contextID=f.contextID)
Expand All @@ -2567,7 +2588,7 @@ def getEvalFunctionStringAndArgs(sev, functionName, argumentsKey="function-argum
factsInMonth = [0 for i in range(12)] # count per month
ns = fr.qname.namespaceURI
for f in modelXbrl.facts:
if f.qname.namespaceURI == ns:
if f.qname.namespaceURI == ns and f.context.endDatetime and f.context.startDatetime:
isMonthDuration = 0.8 < (f.context.endDatetime - f.context.startDatetime).days / 30.4375 < 1.2
monthNbr = 12 - (perEnd - f.context.startDatetime).days / 30.4375
monthInt = int(monthNbr + .2)
Expand Down
8 changes: 5 additions & 3 deletions validate/XuleInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,11 @@ def init(cntlr):
user_defined_xule_rule_set = True
if getattr(xuleOptions, "xule_args_file", None):
user_defined_xule_args_file = True
# add EDGAR mapping for resource files to disclosureSystem.mappings
if cntlr.modelManager.disclosureSystem:
mappedPath = f"{os.sep}__xule_resources_dir__"
if xuleValidateFinally is not None: # xule is loaded
# add EDGAR mapping for resource files to disclosureSystem.mappings (re-register each call; DisclosureSystem.select() clears mappedPaths)
if cntlr.modelManager.disclosureSystem:
mappedPath = f"{os.sep}__xule_resources_dir__"
if (mappedPath, _xule_resources_dir) not in cntlr.modelManager.disclosureSystem.mappedPaths:
cntlr.modelManager.disclosureSystem.mappedPaths.append((mappedPath, _xule_resources_dir))
normalizedMappedPath = cntlr.webCache.normalizeUrl(mappedPath,None) # normalization occurs within ModelDocument.load()
if normalizedMappedPath != mappedPath: # python 3.13 on Windows also needs to map with drive letter added
Expand Down
2 changes: 1 addition & 1 deletion validate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ def json(self): # stringify un-jsonable attributes
__pluginInfo__ = {
# Do not use _( ) in pluginInfo itself (it is applied later, after loading
'name': 'Validate EFM',
'version': '1.26.1', # SEC EDGAR release 26.1
'version': '1.26.2', # SEC EDGAR release 26.2
'description': '''EFM Validation.''',
'license': 'Apache-2',
'import': ('EDGAR/transform', 'xule'), # SEC inline can use SEC transformations
Expand Down
16 changes: 8 additions & 8 deletions validate/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<DisclosureSystem
names="US SEC (Edgar Filing Manual, Strict)|efm|efm-strict"
description="US SEC Edgar Filing Manual v77 Release 26.1\n
description="US SEC Edgar Filing Manual v78 Release 26.2\n
Default language en-US (en allowed in some cases per EFM)\n
CIK identifier patterns\n
Disallowed references are blocked and not loaded (same as SEC production system)\n
Expand All @@ -16,7 +16,7 @@
blockDisallowedReferences="true"
defaultXmlLang="en-US"
defaultLanguage="English"
standardTaxonomiesUrl="resources/edgartaxonomies/edgartaxonomies-26-1.xml"
standardTaxonomiesUrl="resources/edgartaxonomies/edgartaxonomies-26-2.xml"
utrUrl="http://www.xbrl.org/utr/2025-03-18/utr.xml"
validateFileText="true"
validateEntryText="true"
Expand Down Expand Up @@ -44,7 +44,7 @@
/>
<DisclosureSystem
names="US SEC (Edgar Filing Manual, Pragmatic)|efm-blocking|efm-pragmatic"
description="US SEC Edgar Filing Manual v77 Release 26.1\n
description="US SEC Edgar Filing Manual v78 Release 26.2\n
Default language en-US (en allowed in some cases per EFM)\n
CIK identifier patterns\n
Allowed references http://www.sec.gov/info/edgar/edgartaxonomies.shtml\n
Expand All @@ -55,7 +55,7 @@
blockDisallowedReferences="true"
defaultXmlLang="en-US"
defaultLanguage="English"
standardTaxonomiesUrl="resources/edgartaxonomies/edgartaxonomies-26-1.xml"
standardTaxonomiesUrl="resources/edgartaxonomies/edgartaxonomies-26-2.xml"
utrUrl="http://www.xbrl.org/utr/2025-03-18/utr.xml"
validateFileText="true"
validateEntryText="true"
Expand Down Expand Up @@ -87,7 +87,7 @@
/>
<DisclosureSystem
names="US SEC (Edgar Filing Manual, Pragmatic, NonBlocking for testing)|efm-pragmatic-nonblocking"
description="US SEC Edgar Filing Manual v77 Release 26.1\n
description="US SEC Edgar Filing Manual v78 Release 26.2\n
Default language en-US (en allowed in some cases per EFM)\n
CIK identifier patterns\n
Allowed references http://www.sec.gov/info/edgar/edgartaxonomies.shtml\n
Expand All @@ -98,7 +98,7 @@
blockDisallowedReferences="true"
defaultXmlLang="en-US"
defaultLanguage="English"
standardTaxonomiesUrl="resources/edgartaxonomies/edgartaxonomies-26-1.xml"
standardTaxonomiesUrl="resources/edgartaxonomies/edgartaxonomies-26-2.xml"
utrUrl="http://www.xbrl.org/utr/2022-02-16/utr.xml"
validateFileText="true"
validateEntryText="true"
Expand Down Expand Up @@ -130,7 +130,7 @@
/>
<DisclosureSystem
names="US SEC (Edgar Filing Manual, Liberal)|efm-nonblocking|efm-liberal"
description="US SEC Edgar Filing Manual v77 Release 26.1\n
description="US SEC Edgar Filing Manual v78 Release 26.2\n
Default language en-US (en allowed in some cases per EFM)\n
CIK identifier patterns\n
Allowed references http://www.sec.gov/info/edgar/edgartaxonomies.shtml\n
Expand Down Expand Up @@ -267,7 +267,7 @@
defaultXmlLang="en-US"
defaultLanguage="English"
standardTaxonomiesUrl="resources/edgartaxonomies/edgartaxonomies-all-years.xml"
validTaxonomiesUrl="resources/edgartaxonomies/edgartaxonomies-26-1.xml"
validTaxonomiesUrl="resources/edgartaxonomies/edgartaxonomies-26-2.xml"
utrUrl="http://www.xbrl.org/utr/2025-03-18/utr.xml"
validateFileText="true"
validateEntryText="true"
Expand Down
Loading