From 70094feae230680823eb821816ff5ceb0842e5e0 Mon Sep 17 00:00:00 2001 From: Ghislain Fourny Date: Mon, 23 Mar 2026 15:30:06 +0100 Subject: [PATCH 01/11] Make fact API lean. --- brel/brel_fact.py | 57 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/brel/brel_fact.py b/brel/brel_fact.py index 5917e913..4e02c6cd 100644 --- a/brel/brel_fact.py +++ b/brel/brel_fact.py @@ -54,21 +54,25 @@ def __init__( self.__context: Context = context self.__value: str = value - # first class citizens - # TODO think about this. is the id attribute an implementation detail? def _get_id(self) -> str | None: - """ - :returns str|None: The id of the fact. Returns None if the fact does not have an id. - """ - return self.__id + """[DEPRECATED] Use id() instead.""" + return self.id() def get_id(self) -> str | None: + """[DEPRECATED] Use id() instead.""" + return self.id() + + def id(self) -> str | None: """ :returns str|None: The id of the fact. Returns None if the fact does not have an id. """ return self.__id def get_context(self) -> Context: + """[DEPRECATED] Use context() instead.""" + return self.context() + + def context(self) -> Context: """ :returns Context: The context of the fact as a Context object. """ @@ -81,6 +85,10 @@ def get_value_as_str(self) -> str: return self.__value def get_value_as_int(self) -> int: + """[DEPRECATED] Use int() instead.""" + return int(self) + + def __int__(self) -> int: """ :returns int: The value of the fact as an int :raises ValueError: If the value of the fact does not resolve to an int @@ -93,6 +101,10 @@ def get_value_as_int(self) -> int: ) def get_value_as_float(self) -> float: + """[DEPRECATED] Use float() instead.""" + return + + def __float__(self) -> float: """ :returns float: The value of the fact as a float :raises ValueError: If the value of the fact does not resolve to a float @@ -105,6 +117,10 @@ def get_value_as_float(self) -> float: ) def get_value_as_bool(self) -> bool: + """[DEPRECATED] Use bool() instead.""" + return bool + + def __bool__(self) -> bool: """ :returns bool: The value of the fact as a bool :raises ValueError: If the value of the fact does not resolve to a bool @@ -125,9 +141,23 @@ def get_value(self) -> str: return self.__value def get_precision(self) -> float | None: + """[DEPRECATED] Use precision() instead.""" + return self.__precision + + def precision(self) -> float | None: + """ + :returns Any: The precision of the fact. Only applies to numeric facts. + """ return self.__precision def get_decimals(self) -> float | None: + """[DEPRECATED] Use decimals() instead.""" + return self.__decimals + + def decimals(self) -> float | None: + """ + :returns Any: The decimals property of the fact. Only applies to numeric facts. + """ return self.__decimals def __str__(self) -> str: @@ -202,11 +232,24 @@ def get_characteristic(self, aspect: Aspect) -> ICharacteristic | None: """ return self.__context.get_characteristic(aspect) + def __iter__( + self + ): + return iter(self.convert_to_dict().items()) + def convert_to_dict( self, languages: Optional[List[str]] = None, translation_service: Optional[TranslationService] = None, - ) -> dict[str, Any]: + ) -> dict[str, Any]: + """[DEPRECATED] Use as_dict() instead.""" + return self.as_dict(languages, translation_service) + + def as_dict( + self, + languages: Optional[List[str]] = None, + translation_service: Optional[TranslationService] = None, + ) -> dict[str, Any]: """ :returns dict[str, Any]: The fact represented as a dictionary. The dictionary has the following keys: - "id": The id of the fact. Returns None if the fact does not have an id. From 3dde9c7b182a1c1ccb6c50e38361f14fdd78d9d8 Mon Sep 17 00:00:00 2001 From: Ghislain Fourny Date: Mon, 23 Mar 2026 15:45:19 +0100 Subject: [PATCH 02/11] Clean up. --- brel/brel_fact.py | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/brel/brel_fact.py b/brel/brel_fact.py index 4e02c6cd..87f12398 100644 --- a/brel/brel_fact.py +++ b/brel/brel_fact.py @@ -55,24 +55,16 @@ def __init__( self.__value: str = value def _get_id(self) -> str | None: - """[DEPRECATED] Use id() instead.""" + """[DEPRECATED] Use get_id() instead.""" return self.id() def get_id(self) -> str | None: - """[DEPRECATED] Use id() instead.""" - return self.id() - - def id(self) -> str | None: """ :returns str|None: The id of the fact. Returns None if the fact does not have an id. """ return self.__id def get_context(self) -> Context: - """[DEPRECATED] Use context() instead.""" - return self.context() - - def context(self) -> Context: """ :returns Context: The context of the fact as a Context object. """ @@ -141,20 +133,12 @@ def get_value(self) -> str: return self.__value def get_precision(self) -> float | None: - """[DEPRECATED] Use precision() instead.""" - return self.__precision - - def precision(self) -> float | None: """ :returns Any: The precision of the fact. Only applies to numeric facts. """ return self.__precision def get_decimals(self) -> float | None: - """[DEPRECATED] Use decimals() instead.""" - return self.__decimals - - def decimals(self) -> float | None: """ :returns Any: The decimals property of the fact. Only applies to numeric facts. """ @@ -238,14 +222,6 @@ def __iter__( return iter(self.convert_to_dict().items()) def convert_to_dict( - self, - languages: Optional[List[str]] = None, - translation_service: Optional[TranslationService] = None, - ) -> dict[str, Any]: - """[DEPRECATED] Use as_dict() instead.""" - return self.as_dict(languages, translation_service) - - def as_dict( self, languages: Optional[List[str]] = None, translation_service: Optional[TranslationService] = None, From 18075bcc5dcc0dc5db4c12ea7c3ad88d464d9218 Mon Sep 17 00:00:00 2001 From: Ghislain Fourny Date: Mon, 23 Mar 2026 15:47:04 +0100 Subject: [PATCH 03/11] Fix setuptools value. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d3355ed7..35dd61c0 100644 --- a/setup.py +++ b/setup.py @@ -177,7 +177,7 @@ def read_requirements(path): "pyyaml_env_tag==0.1", "requests==2.31.0", "rich==13.7.1", - "setuptools==75.8.2", + "setuptools==81.0.0", "six==1.16.0", "tomli==2.0.1", "tomli_w==1.0.0", From f2d6994be2abc44d3fda8cd12039de15188c2da1 Mon Sep 17 00:00:00 2001 From: Ghislain Fourny Date: Mon, 23 Mar 2026 15:50:13 +0100 Subject: [PATCH 04/11] Reformat. --- brel/brel_component.py | 34 +++++++++---------- brel/brel_context.py | 2 +- brel/brel_fact.py | 10 +++--- brel/brel_filing.py | 2 +- brel/data/aspect/aspect_repository.py | 1 + .../aspect/in_memory_aspect_repository.py | 1 + .../characteristic_repository.py | 6 ++-- brel/data/errors/error_repository.py | 1 + brel/data/file/file_repository.py | 1 - brel/data/file/pyfs_file_repository.py | 2 +- .../in_memory_namespace_repository.py | 1 - .../report_element_repository.py | 12 +++---- brel/networks/calculation_network_node.py | 2 +- brel/parsers/XHMTL/xhtml_parse_facts.py | 1 + .../xhtml_parse_transformation_registry.py | 3 +- .../XML/characteristics/xml_parse_entity.py | 1 - .../XML/characteristics/xml_parse_period.py | 1 - .../xml_parse_typed_dimension.py | 1 - .../XML/characteristics/xml_parse_unit.py | 1 - .../XML/networks/xml_extended_link_parser.py | 6 ++-- .../xml_table_linkbase_parser.py | 6 ++-- brel/parsers/XML/xml_context_parser.py | 1 - brel/parsers/XML/xml_facts_parser.py | 1 + brel/parsers/XML/xml_namespace_normalizer.py | 8 ++--- brel/parsers/utils/error_utils.py | 7 ++-- brel/parsers/utils/iterable_utils.py | 4 +-- brel/parsers/xhtml_filing_parser.py | 1 - brel/parsers/xml_filing_parser.py | 1 - brel/reportelements/dimension.py | 8 +++-- brel/services/file/file_service.py | 1 - .../report_element/report_element_service.py | 8 +++-- 31 files changed, 65 insertions(+), 70 deletions(-) diff --git a/brel/brel_component.py b/brel/brel_component.py index 3e8fa2d5..7ada3459 100644 --- a/brel/brel_component.py +++ b/brel/brel_component.py @@ -2,7 +2,7 @@ This module contains the Component class. Components are used to define the presentation, calculation and definition networks of a filing. -Intuitively, they function as the chapters of a report or filing. Note that XBRL sometimes calls +Intuitively, they function as the chapters of a report or filing. Note that XBRL sometimes calls components 'roles'. Given a report, you can get all the components using the `Filing.get_all_components()` method. @@ -19,14 +19,14 @@ my_component = filing.get_component(my_component_name) ``` -Components act as wrappers for the [`Network`s](#.networks/index.md) of a filing. +Components act as wrappers for the [`Network`s](#.networks/index.md) of a filing. The most notable kind of networks are the presentation, calculation and definition networks. -- get the [`PresentationNetwork`](#./networks/presentation_network.md) using the +- get the [`PresentationNetwork`](#./networks/presentation_network.md) using the `Component.get_presentation_network()` method. -- get the [`CalculationNetwork`](#./networks/calculation_network.md) using the +- get the [`CalculationNetwork`](#./networks/calculation_network.md) using the `Component.get_calculation_network()` method. -- get the [`DefinitionNetwork`](#./networks/definition_network.md) using the +- get the [`DefinitionNetwork`](#./networks/definition_network.md) using the `Component.get_definition_network()` method. You can print them using the `pprint_network` function in the `brel` module: @@ -84,9 +84,9 @@ def __init__( ) -> None: self.__uri: str = uri self.__info: str = info - self.__presentation_network: Optional[ - PresentationNetwork - ] = presentation_network + self.__presentation_network: Optional[PresentationNetwork] = ( + presentation_network + ) self.__calculation_network: Optional[CalculationNetwork] = calculation_network self.__definition_network: Optional[DefinitionNetwork] = definition_network @@ -183,15 +183,15 @@ def convert_to_dict( return { "network-identifier": self.__uri, "info": self.__info, - "presentation-network": True - if self.__presentation_network is not None - else False, - "calculation-network": True - if self.__calculation_network is not None - else False, - "definintion-network": True - if self.__definition_network is not None - else False, + "presentation-network": ( + True if self.__presentation_network is not None else False + ), + "calculation-network": ( + True if self.__calculation_network is not None else False + ), + "definintion-network": ( + True if self.__definition_network is not None else False + ), } network_identifier_literal = translation_service.get( diff --git a/brel/brel_context.py b/brel/brel_context.py index f96334a5..66eab06f 100644 --- a/brel/brel_context.py +++ b/brel/brel_context.py @@ -20,7 +20,7 @@ Characteristics are aspect-value pairs. So for example, the characteristic of the Entity aspect would be "Foo Corporation". -Read more about Aspects and Characteristics in +Read more about Aspects and Characteristics in ==================== diff --git a/brel/brel_fact.py b/brel/brel_fact.py index 87f12398..0fa762fa 100644 --- a/brel/brel_fact.py +++ b/brel/brel_fact.py @@ -79,7 +79,7 @@ def get_value_as_str(self) -> str: def get_value_as_int(self) -> int: """[DEPRECATED] Use int() instead.""" return int(self) - + def __int__(self) -> int: """ :returns int: The value of the fact as an int @@ -216,16 +216,14 @@ def get_characteristic(self, aspect: Aspect) -> ICharacteristic | None: """ return self.__context.get_characteristic(aspect) - def __iter__( - self - ): + def __iter__(self): return iter(self.convert_to_dict().items()) - + def convert_to_dict( self, languages: Optional[List[str]] = None, translation_service: Optional[TranslationService] = None, - ) -> dict[str, Any]: + ) -> dict[str, Any]: """ :returns dict[str, Any]: The fact represented as a dictionary. The dictionary has the following keys: - "id": The id of the fact. Returns None if the fact does not have an id. diff --git a/brel/brel_filing.py b/brel/brel_filing.py index 9f5d0962..b48a5ce6 100644 --- a/brel/brel_filing.py +++ b/brel/brel_filing.py @@ -6,7 +6,7 @@ Filings can be loaded from a folder, a zip file, or one or multiple xml files. - If a folder is given, then all xml files in the folder are loaded. -- If a zip file is given, then the zip file is extracted to a folder +- If a zip file is given, then the zip file is extracted to a folder and then all xml files in the folder are loaded. - If one or more xml files are given, then only those xml files are loaded. - A URI can also be given. In this case, the file is downloaded and cached in a folder. diff --git a/brel/data/aspect/aspect_repository.py b/brel/data/aspect/aspect_repository.py index 1b188658..97fcdb7e 100644 --- a/brel/data/aspect/aspect_repository.py +++ b/brel/data/aspect/aspect_repository.py @@ -7,6 +7,7 @@ ==================== """ + from abc import abstractmethod, ABC from brel.characteristics.brel_aspect import Aspect diff --git a/brel/data/aspect/in_memory_aspect_repository.py b/brel/data/aspect/in_memory_aspect_repository.py index 76124f2d..10029d50 100644 --- a/brel/data/aspect/in_memory_aspect_repository.py +++ b/brel/data/aspect/in_memory_aspect_repository.py @@ -7,6 +7,7 @@ ==================== """ + from brel.characteristics.brel_aspect import Aspect from brel.data.aspect.aspect_repository import AspectRepository diff --git a/brel/data/characteristic/characteristic_repository.py b/brel/data/characteristic/characteristic_repository.py index bf53aa52..c8c9db61 100644 --- a/brel/data/characteristic/characteristic_repository.py +++ b/brel/data/characteristic/characteristic_repository.py @@ -26,9 +26,9 @@ def has(self, id: str, type: type[ICharacteristic]) -> bool: def upsert(self, id: str, characteristic: ICharacteristic) -> None: pass - def get_or_create[ - T: ICharacteristic - ](self, id: str, characteristic_type: Type[T], factory: Callable[[], T]) -> T: + def get_or_create[T: ICharacteristic]( + self, id: str, characteristic_type: Type[T], factory: Callable[[], T] + ) -> T: if not self.has(id, characteristic_type): characteristic = factory() self.upsert(id, characteristic) diff --git a/brel/data/errors/error_repository.py b/brel/data/errors/error_repository.py index e669d48f..956ddc90 100644 --- a/brel/data/errors/error_repository.py +++ b/brel/data/errors/error_repository.py @@ -7,6 +7,7 @@ ==================== """ + from lxml import etree from abc import ABC, abstractmethod from typing import Callable, Optional, final diff --git a/brel/data/file/file_repository.py b/brel/data/file/file_repository.py index c4429486..c6214e31 100644 --- a/brel/data/file/file_repository.py +++ b/brel/data/file/file_repository.py @@ -8,7 +8,6 @@ ==================== """ - from abc import ABC, abstractmethod from typing import IO diff --git a/brel/data/file/pyfs_file_repository.py b/brel/data/file/pyfs_file_repository.py index 9e15ed8b..5c40743a 100644 --- a/brel/data/file/pyfs_file_repository.py +++ b/brel/data/file/pyfs_file_repository.py @@ -1,5 +1,5 @@ """ -This module is responsible for abstracting the file system. +This module is responsible for abstracting the file system. It downloads and caches files from the internet and the local file system. ================= diff --git a/brel/data/namespace/in_memory_namespace_repository.py b/brel/data/namespace/in_memory_namespace_repository.py index dc31aee8..04e2ba64 100644 --- a/brel/data/namespace/in_memory_namespace_repository.py +++ b/brel/data/namespace/in_memory_namespace_repository.py @@ -8,7 +8,6 @@ ==================== """ - from collections import defaultdict from brel.data.namespace.namespace_repository import NamespaceRepository diff --git a/brel/data/report_element/report_element_repository.py b/brel/data/report_element/report_element_repository.py index 736fb873..e5e49ae2 100644 --- a/brel/data/report_element/report_element_repository.py +++ b/brel/data/report_element/report_element_repository.py @@ -38,9 +38,9 @@ def upsert(self, report_element: IReportElement) -> None: def get_all(self) -> list[IReportElement]: pass - def get_typed_by_qname[ - T: IReportElement - ](self, qname: QName, report_element_type: type[T]) -> T: + def get_typed_by_qname[T: IReportElement]( + self, qname: QName, report_element_type: type[T] + ) -> T: report_element = self.get_by_qname(qname) if not isinstance(report_element, report_element_type): raise ValueError( @@ -48,9 +48,9 @@ def get_typed_by_qname[ ) return report_element - def get_typed_by_id[ - T: IReportElement - ](self, id: str, report_element_type: type[T]) -> T: + def get_typed_by_id[T: IReportElement]( + self, id: str, report_element_type: type[T] + ) -> T: report_element = self.get_by_id(id) if not isinstance(report_element, report_element_type): raise ValueError( diff --git a/brel/networks/calculation_network_node.py b/brel/networks/calculation_network_node.py index fe988638..8f2d44b2 100644 --- a/brel/networks/calculation_network_node.py +++ b/brel/networks/calculation_network_node.py @@ -6,7 +6,7 @@ CalculationNetworkNodes implement the INetworkNode interface, but they add the methods `get_concept()` and `get_weight()`. Note that this documentation omits the methods inherited from the INetworkNode interface. -For more on the methods inherited from the INetworkNode interface, see the [INetworkNode documentation](./network-nodes.md). +For more on the methods inherited from the INetworkNode interface, see the [INetworkNode documentation](./network-nodes.md). ================= diff --git a/brel/parsers/XHMTL/xhtml_parse_facts.py b/brel/parsers/XHMTL/xhtml_parse_facts.py index 7c900a86..60de3c19 100644 --- a/brel/parsers/XHMTL/xhtml_parse_facts.py +++ b/brel/parsers/XHMTL/xhtml_parse_facts.py @@ -7,6 +7,7 @@ ==================== """ + import re import datetime diff --git a/brel/parsers/XHMTL/xhtml_parse_transformation_registry.py b/brel/parsers/XHMTL/xhtml_parse_transformation_registry.py index f9d092ad..c268cd79 100644 --- a/brel/parsers/XHMTL/xhtml_parse_transformation_registry.py +++ b/brel/parsers/XHMTL/xhtml_parse_transformation_registry.py @@ -8,7 +8,6 @@ from brel.data.errors.error_repository import ErrorRepository from brel.errors.error_code import ErrorCode - number_format_to_regex = { "ixt:num-comma-decimal-apos": r"^([\.\'`´’′ 0-9]*)(,[ 0-9]+)?$", "ixt:num-dot-decimal-apos": r"^([,\'`´’′ 0-9]*)(\.[ 0-9]+)?$", @@ -663,7 +662,7 @@ def convert_japanese_imperial_date_to_gregorian( def convert_national_indian_date_to_gregorian( - date_parts: dict[str, str] + date_parts: dict[str, str], ) -> dict[str, str]: if len("year") == 2: date_parts["year"] = "19" + date_parts["year"] diff --git a/brel/parsers/XML/characteristics/xml_parse_entity.py b/brel/parsers/XML/characteristics/xml_parse_entity.py index 2f3bda78..cc4b5da8 100644 --- a/brel/parsers/XML/characteristics/xml_parse_entity.py +++ b/brel/parsers/XML/characteristics/xml_parse_entity.py @@ -11,7 +11,6 @@ ==================== """ - from typing import Optional import lxml.etree diff --git a/brel/parsers/XML/characteristics/xml_parse_period.py b/brel/parsers/XML/characteristics/xml_parse_period.py index 60b620f7..127a04cc 100644 --- a/brel/parsers/XML/characteristics/xml_parse_period.py +++ b/brel/parsers/XML/characteristics/xml_parse_period.py @@ -11,7 +11,6 @@ ==================== """ - from typing import Optional, cast import lxml.etree diff --git a/brel/parsers/XML/characteristics/xml_parse_typed_dimension.py b/brel/parsers/XML/characteristics/xml_parse_typed_dimension.py index 9bec532c..b06f67c8 100644 --- a/brel/parsers/XML/characteristics/xml_parse_typed_dimension.py +++ b/brel/parsers/XML/characteristics/xml_parse_typed_dimension.py @@ -11,7 +11,6 @@ ==================== """ - from typing import Optional import lxml.etree diff --git a/brel/parsers/XML/characteristics/xml_parse_unit.py b/brel/parsers/XML/characteristics/xml_parse_unit.py index 6b46a834..21fe6a98 100644 --- a/brel/parsers/XML/characteristics/xml_parse_unit.py +++ b/brel/parsers/XML/characteristics/xml_parse_unit.py @@ -10,7 +10,6 @@ ==================== """ - from typing import Optional from lxml.etree import _Element # type: ignore diff --git a/brel/parsers/XML/networks/xml_extended_link_parser.py b/brel/parsers/XML/networks/xml_extended_link_parser.py index 206089d3..c783cca6 100644 --- a/brel/parsers/XML/networks/xml_extended_link_parser.py +++ b/brel/parsers/XML/networks/xml_extended_link_parser.py @@ -142,9 +142,9 @@ def parse_xml_link( xml_link_element, ".//*[@xlink:type='resource' or @xlink:type='locator']" ): label = get_str_attribute(link_element, "xlink:label") - to_object: Optional[ - IResource | IReportElement | Fact - ] = get_object_from_reference(link_element, context) + to_object: Optional[IResource | IReportElement | Fact] = ( + get_object_from_reference(link_element, context) + ) if not to_object: continue diff --git a/brel/parsers/XML/table_linkbase/xml_table_linkbase_parser.py b/brel/parsers/XML/table_linkbase/xml_table_linkbase_parser.py index 9ecc68f3..5198d949 100644 --- a/brel/parsers/XML/table_linkbase/xml_table_linkbase_parser.py +++ b/brel/parsers/XML/table_linkbase/xml_table_linkbase_parser.py @@ -680,9 +680,9 @@ def parse_table_linkbase_element( # TODO: error pass - def add_unique_to_dict[ - T - ](id: Optional[str], element: Optional[T], dict: Dict[str, T]): + def add_unique_to_dict[T]( + id: Optional[str], element: Optional[T], dict: Dict[str, T] + ): if not element: return diff --git a/brel/parsers/XML/xml_context_parser.py b/brel/parsers/XML/xml_context_parser.py index 6d563c14..afb42bbc 100644 --- a/brel/parsers/XML/xml_context_parser.py +++ b/brel/parsers/XML/xml_context_parser.py @@ -12,7 +12,6 @@ ==================== """ - from typing import Optional import lxml.etree diff --git a/brel/parsers/XML/xml_facts_parser.py b/brel/parsers/XML/xml_facts_parser.py index a67d9da0..73cf669d 100644 --- a/brel/parsers/XML/xml_facts_parser.py +++ b/brel/parsers/XML/xml_facts_parser.py @@ -10,6 +10,7 @@ ==================== """ + from typing import cast import lxml import lxml.etree diff --git a/brel/parsers/XML/xml_namespace_normalizer.py b/brel/parsers/XML/xml_namespace_normalizer.py index 4aea8736..5d71221a 100644 --- a/brel/parsers/XML/xml_namespace_normalizer.py +++ b/brel/parsers/XML/xml_namespace_normalizer.py @@ -4,8 +4,8 @@ It is not intended to be used by the user directly. Rather, it is used by the XML parser to normalize the namespace mappings. In XML, namespaces can be defined per element. Therefore, the same prefix can map to different urls and the same url can map to different prefixes. -It all depends on the context in which the prefix is used. From a user perspective, this is very confusing. -When a user looks for e.g. us-gaap:Assets, he usually doesn't care if it is us-gaap's 2022 or 2023 version. +It all depends on the context in which the prefix is used. From a user perspective, this is very confusing. +When a user looks for e.g. us-gaap:Assets, he usually doesn't care if it is us-gaap's 2022 or 2023 version. Also, if the filing calls the prefix us-gaap1 instead of us-gaap for some contexts, then the user will have to know this and use the correct prefix. Namespace normalizing turns the nested namespace mappings into a flat namespace mapping. It also generates redirects and renames for the prefixes. @@ -22,7 +22,7 @@ Renames are generated if two completely different urls are mapped to the same prefix. In that case, the name of the prefix is changed to a new prefix. -A rename has the following form: +A rename has the following form: - old_url -> (old_prefix, new_prefix) @@ -263,7 +263,7 @@ def __component_to_nsmap( def normalize_nsmap( - namespace_mappings: list[dict[str, str]] + namespace_mappings: list[dict[str, str]], ) -> dict[str, dict[str, str]]: """ Given a list of namespace mappings, normalize the namespace mappings and returns the normalized namespace mapping and the redirects. diff --git a/brel/parsers/utils/error_utils.py b/brel/parsers/utils/error_utils.py index 1307335b..facfaa52 100644 --- a/brel/parsers/utils/error_utils.py +++ b/brel/parsers/utils/error_utils.py @@ -9,9 +9,10 @@ """ -def error_on_none[ - T -](value: T | None, error_message: str,) -> T: +def error_on_none[T]( + value: T | None, + error_message: str, +) -> T: """ Raise a ValueError if the value is None. :param value: The value to check. diff --git a/brel/parsers/utils/iterable_utils.py b/brel/parsers/utils/iterable_utils.py index 9e44e87c..9ad235cd 100644 --- a/brel/parsers/utils/iterable_utils.py +++ b/brel/parsers/utils/iterable_utils.py @@ -25,9 +25,7 @@ def get_first[T](collection: Iterable[T], error_message: str) -> T: return next(iter(collection)) -def exactly_one[ - T -]( +def exactly_one[T]( collection: Iterable[T], error_message: str = "Collection must contain exactly one element", ) -> T: diff --git a/brel/parsers/xhtml_filing_parser.py b/brel/parsers/xhtml_filing_parser.py index 1cec89eb..746d8532 100644 --- a/brel/parsers/xhtml_filing_parser.py +++ b/brel/parsers/xhtml_filing_parser.py @@ -8,7 +8,6 @@ ==================== """ - from brel.contexts.filing_context import FilingContext from brel.parsers.XHMTL.networks.xhtml_footnote_network_elements import ( XHTMLFootnoteNetworkElements, diff --git a/brel/parsers/xml_filing_parser.py b/brel/parsers/xml_filing_parser.py index 6e3a1a62..4f320544 100644 --- a/brel/parsers/xml_filing_parser.py +++ b/brel/parsers/xml_filing_parser.py @@ -11,7 +11,6 @@ ==================== """ - from brel.parsers.XML.xml_component_parser import parse_components_xml from brel.parsers.XML.xml_facts_parser import parse_facts_xml from brel.parsers.XML.xml_report_element_parser import parse_report_elements_xml diff --git a/brel/reportelements/dimension.py b/brel/reportelements/dimension.py index 6853224a..6ac50304 100644 --- a/brel/reportelements/dimension.py +++ b/brel/reportelements/dimension.py @@ -108,9 +108,11 @@ def convert_to_dict( "label": self.select_main_label().__str__(), "report-element-type": "dimension", "is-explicit": self.is_explicit(), - "dimension_type": self.__type.prefix_local_name_notation() - if self.__type is not None - else None, + "dimension_type": ( + self.__type.prefix_local_name_notation() + if self.__type is not None + else None + ), } name_literal = translation_service.get("literal:name", languages) diff --git a/brel/services/file/file_service.py b/brel/services/file/file_service.py index fd06b623..9f521180 100644 --- a/brel/services/file/file_service.py +++ b/brel/services/file/file_service.py @@ -8,7 +8,6 @@ ==================== """ - import time from io import BytesIO from typing import IO diff --git a/brel/services/report_element/report_element_service.py b/brel/services/report_element/report_element_service.py index 23d6155f..1673c674 100644 --- a/brel/services/report_element/report_element_service.py +++ b/brel/services/report_element/report_element_service.py @@ -24,9 +24,11 @@ def __init__( self.__namespace_repository = namespace_repository self.__report_element_repository = report_element_repository - def get_fuzzy_typed[ - T: IReportElement - ](self, search_params: QNameSearchParams, report_element_type: type[T],) -> list[T]: + def get_fuzzy_typed[T: IReportElement]( + self, + search_params: QNameSearchParams, + report_element_type: type[T], + ) -> list[T]: uri_candidates: set[str] = set() if search_params.uri: uri_candidates.add(search_params.uri) From 84eb57249659cf7cdbcdda527292258009ada5dc Mon Sep 17 00:00:00 2001 From: Ghislain Fourny Date: Mon, 23 Mar 2026 16:35:06 +0100 Subject: [PATCH 05/11] Reformat. --- brel/brel_component.py | 6 +++--- .../data/characteristic/characteristic_repository.py | 6 +++--- .../data/report_element/report_element_repository.py | 12 ++++++------ .../parsers/XML/networks/xml_extended_link_parser.py | 6 +++--- .../XML/table_linkbase/xml_table_linkbase_parser.py | 6 +++--- brel/parsers/utils/error_utils.py | 7 +++---- brel/parsers/utils/iterable_utils.py | 4 +++- .../report_element/report_element_service.py | 8 +++----- setup.py | 2 +- 9 files changed, 28 insertions(+), 29 deletions(-) diff --git a/brel/brel_component.py b/brel/brel_component.py index 7ada3459..67013916 100644 --- a/brel/brel_component.py +++ b/brel/brel_component.py @@ -84,9 +84,9 @@ def __init__( ) -> None: self.__uri: str = uri self.__info: str = info - self.__presentation_network: Optional[PresentationNetwork] = ( - presentation_network - ) + self.__presentation_network: Optional[ + PresentationNetwork + ] = presentation_network self.__calculation_network: Optional[CalculationNetwork] = calculation_network self.__definition_network: Optional[DefinitionNetwork] = definition_network diff --git a/brel/data/characteristic/characteristic_repository.py b/brel/data/characteristic/characteristic_repository.py index c8c9db61..bf53aa52 100644 --- a/brel/data/characteristic/characteristic_repository.py +++ b/brel/data/characteristic/characteristic_repository.py @@ -26,9 +26,9 @@ def has(self, id: str, type: type[ICharacteristic]) -> bool: def upsert(self, id: str, characteristic: ICharacteristic) -> None: pass - def get_or_create[T: ICharacteristic]( - self, id: str, characteristic_type: Type[T], factory: Callable[[], T] - ) -> T: + def get_or_create[ + T: ICharacteristic + ](self, id: str, characteristic_type: Type[T], factory: Callable[[], T]) -> T: if not self.has(id, characteristic_type): characteristic = factory() self.upsert(id, characteristic) diff --git a/brel/data/report_element/report_element_repository.py b/brel/data/report_element/report_element_repository.py index e5e49ae2..736fb873 100644 --- a/brel/data/report_element/report_element_repository.py +++ b/brel/data/report_element/report_element_repository.py @@ -38,9 +38,9 @@ def upsert(self, report_element: IReportElement) -> None: def get_all(self) -> list[IReportElement]: pass - def get_typed_by_qname[T: IReportElement]( - self, qname: QName, report_element_type: type[T] - ) -> T: + def get_typed_by_qname[ + T: IReportElement + ](self, qname: QName, report_element_type: type[T]) -> T: report_element = self.get_by_qname(qname) if not isinstance(report_element, report_element_type): raise ValueError( @@ -48,9 +48,9 @@ def get_typed_by_qname[T: IReportElement]( ) return report_element - def get_typed_by_id[T: IReportElement]( - self, id: str, report_element_type: type[T] - ) -> T: + def get_typed_by_id[ + T: IReportElement + ](self, id: str, report_element_type: type[T]) -> T: report_element = self.get_by_id(id) if not isinstance(report_element, report_element_type): raise ValueError( diff --git a/brel/parsers/XML/networks/xml_extended_link_parser.py b/brel/parsers/XML/networks/xml_extended_link_parser.py index c783cca6..206089d3 100644 --- a/brel/parsers/XML/networks/xml_extended_link_parser.py +++ b/brel/parsers/XML/networks/xml_extended_link_parser.py @@ -142,9 +142,9 @@ def parse_xml_link( xml_link_element, ".//*[@xlink:type='resource' or @xlink:type='locator']" ): label = get_str_attribute(link_element, "xlink:label") - to_object: Optional[IResource | IReportElement | Fact] = ( - get_object_from_reference(link_element, context) - ) + to_object: Optional[ + IResource | IReportElement | Fact + ] = get_object_from_reference(link_element, context) if not to_object: continue diff --git a/brel/parsers/XML/table_linkbase/xml_table_linkbase_parser.py b/brel/parsers/XML/table_linkbase/xml_table_linkbase_parser.py index 5198d949..9ecc68f3 100644 --- a/brel/parsers/XML/table_linkbase/xml_table_linkbase_parser.py +++ b/brel/parsers/XML/table_linkbase/xml_table_linkbase_parser.py @@ -680,9 +680,9 @@ def parse_table_linkbase_element( # TODO: error pass - def add_unique_to_dict[T]( - id: Optional[str], element: Optional[T], dict: Dict[str, T] - ): + def add_unique_to_dict[ + T + ](id: Optional[str], element: Optional[T], dict: Dict[str, T]): if not element: return diff --git a/brel/parsers/utils/error_utils.py b/brel/parsers/utils/error_utils.py index facfaa52..1307335b 100644 --- a/brel/parsers/utils/error_utils.py +++ b/brel/parsers/utils/error_utils.py @@ -9,10 +9,9 @@ """ -def error_on_none[T]( - value: T | None, - error_message: str, -) -> T: +def error_on_none[ + T +](value: T | None, error_message: str,) -> T: """ Raise a ValueError if the value is None. :param value: The value to check. diff --git a/brel/parsers/utils/iterable_utils.py b/brel/parsers/utils/iterable_utils.py index 9ad235cd..9e44e87c 100644 --- a/brel/parsers/utils/iterable_utils.py +++ b/brel/parsers/utils/iterable_utils.py @@ -25,7 +25,9 @@ def get_first[T](collection: Iterable[T], error_message: str) -> T: return next(iter(collection)) -def exactly_one[T]( +def exactly_one[ + T +]( collection: Iterable[T], error_message: str = "Collection must contain exactly one element", ) -> T: diff --git a/brel/services/report_element/report_element_service.py b/brel/services/report_element/report_element_service.py index 1673c674..23d6155f 100644 --- a/brel/services/report_element/report_element_service.py +++ b/brel/services/report_element/report_element_service.py @@ -24,11 +24,9 @@ def __init__( self.__namespace_repository = namespace_repository self.__report_element_repository = report_element_repository - def get_fuzzy_typed[T: IReportElement]( - self, - search_params: QNameSearchParams, - report_element_type: type[T], - ) -> list[T]: + def get_fuzzy_typed[ + T: IReportElement + ](self, search_params: QNameSearchParams, report_element_type: type[T],) -> list[T]: uri_candidates: set[str] = set() if search_params.uri: uri_candidates.add(search_params.uri) diff --git a/setup.py b/setup.py index 35dd61c0..8a29cf32 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ def read_requirements(path): package_data={"": ["*.json"]}, install_requires=[ "appdirs>=1.4.4", - "black>=23.12.1", + "black==23.12.1", "certifi>=2023.11.17", "charset-normalizer>=3.3.2", "click>=8.1.7", From dda3812a1350bf951287a45d39fe91b6f165ef64 Mon Sep 17 00:00:00 2001 From: Ghislain Fourny Date: Mon, 23 Mar 2026 17:06:11 +0100 Subject: [PATCH 06/11] Fix linting. --- brel/brel_fact.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/brel/brel_fact.py b/brel/brel_fact.py index 0fa762fa..49b2d00c 100644 --- a/brel/brel_fact.py +++ b/brel/brel_fact.py @@ -56,7 +56,7 @@ def __init__( def _get_id(self) -> str | None: """[DEPRECATED] Use get_id() instead.""" - return self.id() + return self.get_id() def get_id(self) -> str | None: """ @@ -94,7 +94,7 @@ def __int__(self) -> int: def get_value_as_float(self) -> float: """[DEPRECATED] Use float() instead.""" - return + return float(self) def __float__(self) -> float: """ @@ -110,7 +110,7 @@ def __float__(self) -> float: def get_value_as_bool(self) -> bool: """[DEPRECATED] Use bool() instead.""" - return bool + return bool(self) def __bool__(self) -> bool: """ From 7164cfe4d4b39ddeee6ddab4d9525058148130cf Mon Sep 17 00:00:00 2001 From: Ghislain Fourny Date: Tue, 24 Mar 2026 10:49:55 +0100 Subject: [PATCH 07/11] Add printing stacktrace. --- brel/brel_fact.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/brel/brel_fact.py b/brel/brel_fact.py index 49b2d00c..0fd0f9ff 100644 --- a/brel/brel_fact.py +++ b/brel/brel_fact.py @@ -15,6 +15,7 @@ ==================== """ +import traceback from typing import Any, List, Optional, cast from brel import Context @@ -117,6 +118,8 @@ def __bool__(self) -> bool: :returns bool: The value of the fact as a bool :raises ValueError: If the value of the fact does not resolve to a bool """ + print("Bool cast called!") + traceback.print_stack() if self.__value.upper() == "TRUE": return True elif self.__value.upper() == "FALSE": From 1fff2190dd0f55a5ca20a73606370d206ab1b8f0 Mon Sep 17 00:00:00 2001 From: Ghislain Fourny Date: Tue, 24 Mar 2026 10:56:08 +0100 Subject: [PATCH 08/11] Include stack trace in error message. --- brel/brel_fact.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/brel/brel_fact.py b/brel/brel_fact.py index 0fd0f9ff..8170e421 100644 --- a/brel/brel_fact.py +++ b/brel/brel_fact.py @@ -120,13 +120,15 @@ def __bool__(self) -> bool: """ print("Bool cast called!") traceback.print_stack() + stack_str = ''.join(traceback.format_stack()) + print(stack_str) if self.__value.upper() == "TRUE": return True elif self.__value.upper() == "FALSE": return False else: raise ValueError( - f"Fact {self.__id} does not have a bool value. It has value {self.__value}, which does not resolve to a bool" + f"Fact {self.__id} does not have a bool value. It has value {self.__value}, which does not resolve to a bool. Stacktrace: {stack_str}" ) def get_value(self) -> str: From 92470f0aa714613df48328baff5674a8b8f0ec61 Mon Sep 17 00:00:00 2001 From: Ghislain Fourny Date: Tue, 24 Mar 2026 10:58:38 +0100 Subject: [PATCH 09/11] Reformat. --- brel/brel_fact.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/brel/brel_fact.py b/brel/brel_fact.py index 8170e421..2a3c553d 100644 --- a/brel/brel_fact.py +++ b/brel/brel_fact.py @@ -120,7 +120,7 @@ def __bool__(self) -> bool: """ print("Bool cast called!") traceback.print_stack() - stack_str = ''.join(traceback.format_stack()) + stack_str = "".join(traceback.format_stack()) print(stack_str) if self.__value.upper() == "TRUE": return True From 1326c472e462d9d7d70ca914093ee49c39066c04 Mon Sep 17 00:00:00 2001 From: Ghislain Fourny Date: Tue, 24 Mar 2026 11:30:44 +0100 Subject: [PATCH 10/11] Fix tests. --- brel/brel_fact.py | 6 +----- brel/parsers/XML/networks/xml_extended_link_parser.py | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/brel/brel_fact.py b/brel/brel_fact.py index 2a3c553d..65c7694a 100644 --- a/brel/brel_fact.py +++ b/brel/brel_fact.py @@ -118,17 +118,13 @@ def __bool__(self) -> bool: :returns bool: The value of the fact as a bool :raises ValueError: If the value of the fact does not resolve to a bool """ - print("Bool cast called!") - traceback.print_stack() - stack_str = "".join(traceback.format_stack()) - print(stack_str) if self.__value.upper() == "TRUE": return True elif self.__value.upper() == "FALSE": return False else: raise ValueError( - f"Fact {self.__id} does not have a bool value. It has value {self.__value}, which does not resolve to a bool. Stacktrace: {stack_str}" + f"Fact {self.__id} does not have a bool value. It has value {self.__value}, which does not resolve to a bool." ) def get_value(self) -> str: diff --git a/brel/parsers/XML/networks/xml_extended_link_parser.py b/brel/parsers/XML/networks/xml_extended_link_parser.py index 206089d3..579f7a03 100644 --- a/brel/parsers/XML/networks/xml_extended_link_parser.py +++ b/brel/parsers/XML/networks/xml_extended_link_parser.py @@ -146,7 +146,7 @@ def parse_xml_link( IResource | IReportElement | Fact ] = get_object_from_reference(link_element, context) - if not to_object: + if to_object is None: continue node_arcs = node_to_arcs[label] From 1ec8d2ed66be4f24bbe237fdf330d3e0fbe7e8bf Mon Sep 17 00:00:00 2001 From: Ghislain Fourny Date: Tue, 24 Mar 2026 11:33:43 +0100 Subject: [PATCH 11/11] Remove unused import. --- brel/brel_fact.py | 1 - 1 file changed, 1 deletion(-) diff --git a/brel/brel_fact.py b/brel/brel_fact.py index 65c7694a..8f64727d 100644 --- a/brel/brel_fact.py +++ b/brel/brel_fact.py @@ -15,7 +15,6 @@ ==================== """ -import traceback from typing import Any, List, Optional, cast from brel import Context