Skip to content

API documentation

ixbrlparse.IXBRL

Parse an iXBRL file.

Source code in src/ixbrlparse/core.py
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
class IXBRL:
    """
    Parse an iXBRL file.
    """

    def __init__(self, f: IO, raise_on_error: bool = True) -> None:  # noqa: FBT001, FBT002
        """Constructor for the IXBRL class.

        Parameters:
            f:  File-like object to parse.
            raise_on_error:  Whether to raise an exception on error
        """
        self.soup = BeautifulSoup(f.read(), "xml", multi_valued_attributes=None)
        self.raise_on_error = raise_on_error
        self._get_parser()
        self.parser._get_schema()
        self.parser._get_contexts()
        self.parser._get_units()
        self.parser._get_nonnumeric()
        self.parser._get_numeric()

    @classmethod
    def open(cls, filename: Union[str, Path], raise_on_error: bool = True):  # noqa: FBT001, FBT002, A003
        """Open an iXBRL file.

        Parameters:
            filename:  Path to file to parse.
            raise_on_error:  Whether to raise an exception on error
        """
        with open(filename, "rb") as a:
            return cls(a, raise_on_error=raise_on_error)

    def _get_parser(self) -> None:
        if self.soup.find("html"):
            self.filetype = FILETYPE_IXBRL
            parser = IXBRLParser
        elif self.soup.find("xbrl"):
            self.filetype = FILETYPE_XBRL
            parser = XBRLParser
        else:
            msg = "Filetype not recognised"
            raise IXBRLParseError(msg)
        self.parser: BaseParser = parser(self.soup, raise_on_error=self.raise_on_error)

    def __getattr__(self, name: str):
        return getattr(self.parser, name)

    def to_json(self) -> Dict:
        """Return a JSON representation of the iXBRL file.

        Returns:
            A dictionary containing the following keys:

                - schema:  The schema used in the iXBRL file.
                - namespaces:  The namespaces used in the iXBRL file.
                - contexts:  The contexts used in the iXBRL file.
                - units:  The units used in the iXBRL file.
                - nonnumeric:  The non-numeric elements in the iXBRL file.
                - numeric:  The numeric elements in the iXBRL file.
                - errors:  The number of errors encountered when parsing the iXBRL file.
        """
        return {
            "schema": self.schema,
            "namespaces": self.namespaces,
            "contexts": {c: ct.to_json() for c, ct in self.contexts.items()},
            "units": self.units,
            "nonnumeric": [a.to_json() for a in self.nonnumeric],
            "numeric": [a.to_json() for a in self.numeric],
            "errors": len(self.errors),
        }

    def to_table(self, fields: str = "numeric") -> List[Dict]:
        """Return a list of dictionaries representing the iXBRL file.

        This is suitable for passing to pandas.DataFrame.from_records().

        Parameters:
            fields:  Which fields to include in the output.  Can be "numeric", "nonnumeric" or "all".

        Returns:
            A list of dictionaries representing the iXBRL file.

        The fields included are:

        - schema (str)
        - name (str) -- the name of the element
        - value -- the value of the element. Can be number, str, None, or boolean
        - unit (str) -- the unit of the element if present
        - instant (date) -- the instant date of the element context if present
        - startdate (date) -- the start date of the element context if present
        - enddate (date) -- the end date of the element context if present
        - segment:N (str) -- the Nth segment of the element context if present (can be repeated)

        Examples:
            >>> import pandas as pd
            >>> i = IXBRL.open("tests/fixtures/ixbrl/uk-gaap/2009-12-31/Company-Accounts-Data.xml")
            >>> df = pd.DataFrame.from_records(i.to_table(fields="numeric"))
            >>> df.head()
        """
        if fields == "nonnumeric":
            values = self.nonnumeric
        elif fields == "numeric":
            values = self.numeric
        else:
            values = self.nonnumeric + self.numeric

        ret = []
        for v in values:
            if isinstance(v.context, ixbrlContext) and v.context.segments:
                segments = {
                    f"segment:{i}": "{} {} {}".format(s.get("tag", ""), s.get("dimension"), s.get("value")).strip()
                    for i, s in enumerate(v.context.segments)
                }
            else:
                segments = {"segment:0": ""}

            ret.append(
                {
                    "schema": " ".join(self.namespaces.get(f"xmlns:{v.schema}", [v.schema])),
                    "name": v.name,
                    "value": v.value,
                    "unit": v.unit if hasattr(v, "unit") else None,
                    "instant": str(v.context.instant)
                    if isinstance(v.context, ixbrlContext) and v.context.instant
                    else None,
                    "startdate": str(v.context.startdate)
                    if isinstance(v.context, ixbrlContext) and v.context.startdate
                    else None,
                    "enddate": str(v.context.enddate)
                    if isinstance(v.context, ixbrlContext) and v.context.enddate
                    else None,
                    **segments,
                }
            )
        return ret

__init__(f, raise_on_error=True)

Constructor for the IXBRL class.

Parameters:

Name Type Description Default
f IO

File-like object to parse.

required
raise_on_error bool

Whether to raise an exception on error

True
Source code in src/ixbrlparse/core.py
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
def __init__(self, f: IO, raise_on_error: bool = True) -> None:  # noqa: FBT001, FBT002
    """Constructor for the IXBRL class.

    Parameters:
        f:  File-like object to parse.
        raise_on_error:  Whether to raise an exception on error
    """
    self.soup = BeautifulSoup(f.read(), "xml", multi_valued_attributes=None)
    self.raise_on_error = raise_on_error
    self._get_parser()
    self.parser._get_schema()
    self.parser._get_contexts()
    self.parser._get_units()
    self.parser._get_nonnumeric()
    self.parser._get_numeric()

open(filename, raise_on_error=True) classmethod

Open an iXBRL file.

Parameters:

Name Type Description Default
filename Union[str, Path]

Path to file to parse.

required
raise_on_error bool

Whether to raise an exception on error

True
Source code in src/ixbrlparse/core.py
320
321
322
323
324
325
326
327
328
329
@classmethod
def open(cls, filename: Union[str, Path], raise_on_error: bool = True):  # noqa: FBT001, FBT002, A003
    """Open an iXBRL file.

    Parameters:
        filename:  Path to file to parse.
        raise_on_error:  Whether to raise an exception on error
    """
    with open(filename, "rb") as a:
        return cls(a, raise_on_error=raise_on_error)

to_json()

Return a JSON representation of the iXBRL file.

Returns:

Type Description
Dict

A dictionary containing the following keys:

  • schema: The schema used in the iXBRL file.
  • namespaces: The namespaces used in the iXBRL file.
  • contexts: The contexts used in the iXBRL file.
  • units: The units used in the iXBRL file.
  • nonnumeric: The non-numeric elements in the iXBRL file.
  • numeric: The numeric elements in the iXBRL file.
  • errors: The number of errors encountered when parsing the iXBRL file.
Source code in src/ixbrlparse/core.py
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
def to_json(self) -> Dict:
    """Return a JSON representation of the iXBRL file.

    Returns:
        A dictionary containing the following keys:

            - schema:  The schema used in the iXBRL file.
            - namespaces:  The namespaces used in the iXBRL file.
            - contexts:  The contexts used in the iXBRL file.
            - units:  The units used in the iXBRL file.
            - nonnumeric:  The non-numeric elements in the iXBRL file.
            - numeric:  The numeric elements in the iXBRL file.
            - errors:  The number of errors encountered when parsing the iXBRL file.
    """
    return {
        "schema": self.schema,
        "namespaces": self.namespaces,
        "contexts": {c: ct.to_json() for c, ct in self.contexts.items()},
        "units": self.units,
        "nonnumeric": [a.to_json() for a in self.nonnumeric],
        "numeric": [a.to_json() for a in self.numeric],
        "errors": len(self.errors),
    }

to_table(fields='numeric')

Return a list of dictionaries representing the iXBRL file.

This is suitable for passing to pandas.DataFrame.from_records().

Parameters:

Name Type Description Default
fields str

Which fields to include in the output. Can be "numeric", "nonnumeric" or "all".

'numeric'

Returns:

Type Description
List[Dict]

A list of dictionaries representing the iXBRL file.

The fields included are:

  • schema (str)
  • name (str) -- the name of the element
  • value -- the value of the element. Can be number, str, None, or boolean
  • unit (str) -- the unit of the element if present
  • instant (date) -- the instant date of the element context if present
  • startdate (date) -- the start date of the element context if present
  • enddate (date) -- the end date of the element context if present
  • segment:N (str) -- the Nth segment of the element context if present (can be repeated)

Examples:

>>> import pandas as pd
>>> i = IXBRL.open("tests/fixtures/ixbrl/uk-gaap/2009-12-31/Company-Accounts-Data.xml")
>>> df = pd.DataFrame.from_records(i.to_table(fields="numeric"))
>>> df.head()
Source code in src/ixbrlparse/core.py
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
def to_table(self, fields: str = "numeric") -> List[Dict]:
    """Return a list of dictionaries representing the iXBRL file.

    This is suitable for passing to pandas.DataFrame.from_records().

    Parameters:
        fields:  Which fields to include in the output.  Can be "numeric", "nonnumeric" or "all".

    Returns:
        A list of dictionaries representing the iXBRL file.

    The fields included are:

    - schema (str)
    - name (str) -- the name of the element
    - value -- the value of the element. Can be number, str, None, or boolean
    - unit (str) -- the unit of the element if present
    - instant (date) -- the instant date of the element context if present
    - startdate (date) -- the start date of the element context if present
    - enddate (date) -- the end date of the element context if present
    - segment:N (str) -- the Nth segment of the element context if present (can be repeated)

    Examples:
        >>> import pandas as pd
        >>> i = IXBRL.open("tests/fixtures/ixbrl/uk-gaap/2009-12-31/Company-Accounts-Data.xml")
        >>> df = pd.DataFrame.from_records(i.to_table(fields="numeric"))
        >>> df.head()
    """
    if fields == "nonnumeric":
        values = self.nonnumeric
    elif fields == "numeric":
        values = self.numeric
    else:
        values = self.nonnumeric + self.numeric

    ret = []
    for v in values:
        if isinstance(v.context, ixbrlContext) and v.context.segments:
            segments = {
                f"segment:{i}": "{} {} {}".format(s.get("tag", ""), s.get("dimension"), s.get("value")).strip()
                for i, s in enumerate(v.context.segments)
            }
        else:
            segments = {"segment:0": ""}

        ret.append(
            {
                "schema": " ".join(self.namespaces.get(f"xmlns:{v.schema}", [v.schema])),
                "name": v.name,
                "value": v.value,
                "unit": v.unit if hasattr(v, "unit") else None,
                "instant": str(v.context.instant)
                if isinstance(v.context, ixbrlContext) and v.context.instant
                else None,
                "startdate": str(v.context.startdate)
                if isinstance(v.context, ixbrlContext) and v.context.startdate
                else None,
                "enddate": str(v.context.enddate)
                if isinstance(v.context, ixbrlContext) and v.context.enddate
                else None,
                **segments,
            }
        )
    return ret

ixbrlparse.ixbrlFormat

Class to represent an ixbrl format.

This class should generally be subclassed to provide additional functionality.

Attributes:

Name Type Description
format_names Tuple[str, ...]

A tuple of format names that this class should be used for.

Source code in src/ixbrlparse/components/_base.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
class ixbrlFormat:  # noqa: N801
    """Class to represent an ixbrl format.

    This class should generally be subclassed to provide additional functionality.

    Attributes:
        format_names: A tuple of format names that this class should be used for."""

    format_names: Tuple[str, ...] = ()

    def __init__(
        self,
        format_: str,
        decimals: Optional[Union[int, str]] = None,
        scale: Union[int, str] = 0,
        sign: Optional[str] = None,
    ) -> None:
        """Initialise the ixbrl format object.

        Parameters:
            format_: The name of the format.
            decimals: The number of decimal places (only used for numeric formats).
            scale: The scale of the format (only for numeric formats).
                If more than 0 this value is used as the exponent for a value, so for example with a scale of
                4 and a value of 20, the parsed value is 20 * (10 ^ 4) == 200000.
            sign: The sign of the format (only for numeric formats). The sign given is usually "-" or empty.
        """
        if isinstance(decimals, str):
            if decimals.lower() == "inf":
                self.decimals = None
            else:
                self.decimals = int(decimals)

        self.format: Optional[str] = None
        self.namespace: Optional[str] = None
        if format_:
            format_array: List[str] = format_.split(":")
            if len(format_array) > 1:
                self.format = ":".join(format_array[1:])
                self.namespace = format_array[0]
            else:
                self.format = ":".join(format_array)
                self.namespace = None

        self.scale = int(scale)
        self.sign = sign

    def to_json(self):
        """Convert the object to a JSON serialisable dictionary."""
        return deepcopy(self.__dict__)

    def parse_value(self, value: Union[str, int, float]) -> Optional[Union[int, float, bool, date, str]]:
        """Parse a value using the format.

        Parameters:
            value: The value to parse.

        Returns:
            The parsed value in the appropriate python type.
        """
        if isinstance(value, (int, float)):
            return value

        if isinstance(value, str):
            if value in ("-", ""):
                return 0

            value_numeric: float = float(value.replace(" ", "").replace(",", ""))

            if self.sign == "-":
                value_numeric = value_numeric * -1

            if self.scale != 0:
                value_numeric = value_numeric * (10**self.scale)

            return value_numeric

__init__(format_, decimals=None, scale=0, sign=None)

Initialise the ixbrl format object.

Parameters:

Name Type Description Default
format_ str

The name of the format.

required
decimals Optional[Union[int, str]]

The number of decimal places (only used for numeric formats).

None
scale Union[int, str]

The scale of the format (only for numeric formats). If more than 0 this value is used as the exponent for a value, so for example with a scale of 4 and a value of 20, the parsed value is 20 * (10 ^ 4) == 200000.

0
sign Optional[str]

The sign of the format (only for numeric formats). The sign given is usually "-" or empty.

None
Source code in src/ixbrlparse/components/_base.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def __init__(
    self,
    format_: str,
    decimals: Optional[Union[int, str]] = None,
    scale: Union[int, str] = 0,
    sign: Optional[str] = None,
) -> None:
    """Initialise the ixbrl format object.

    Parameters:
        format_: The name of the format.
        decimals: The number of decimal places (only used for numeric formats).
        scale: The scale of the format (only for numeric formats).
            If more than 0 this value is used as the exponent for a value, so for example with a scale of
            4 and a value of 20, the parsed value is 20 * (10 ^ 4) == 200000.
        sign: The sign of the format (only for numeric formats). The sign given is usually "-" or empty.
    """
    if isinstance(decimals, str):
        if decimals.lower() == "inf":
            self.decimals = None
        else:
            self.decimals = int(decimals)

    self.format: Optional[str] = None
    self.namespace: Optional[str] = None
    if format_:
        format_array: List[str] = format_.split(":")
        if len(format_array) > 1:
            self.format = ":".join(format_array[1:])
            self.namespace = format_array[0]
        else:
            self.format = ":".join(format_array)
            self.namespace = None

    self.scale = int(scale)
    self.sign = sign

parse_value(value)

Parse a value using the format.

Parameters:

Name Type Description Default
value Union[str, int, float]

The value to parse.

required

Returns:

Type Description
Optional[Union[int, float, bool, date, str]]

The parsed value in the appropriate python type.

Source code in src/ixbrlparse/components/_base.py
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def parse_value(self, value: Union[str, int, float]) -> Optional[Union[int, float, bool, date, str]]:
    """Parse a value using the format.

    Parameters:
        value: The value to parse.

    Returns:
        The parsed value in the appropriate python type.
    """
    if isinstance(value, (int, float)):
        return value

    if isinstance(value, str):
        if value in ("-", ""):
            return 0

        value_numeric: float = float(value.replace(" ", "").replace(",", ""))

        if self.sign == "-":
            value_numeric = value_numeric * -1

        if self.scale != 0:
            value_numeric = value_numeric * (10**self.scale)

        return value_numeric

to_json()

Convert the object to a JSON serialisable dictionary.

Source code in src/ixbrlparse/components/_base.py
63
64
65
def to_json(self):
    """Convert the object to a JSON serialisable dictionary."""
    return deepcopy(self.__dict__)

ixbrlparse.ixbrlContext

Class to represent an ixbrl context.

The context should either have an instant date or a start and end date.

Attributes:

Name Type Description
id

The id of the context.

entity

A dictionary of the entity information.

segments

A list of dictionaries of the segment information.

instant Optional[date]

The instant date of the context.

startdate Optional[date]

The start date of the context.

enddate Optional[date]

The end date of the context.

Source code in src/ixbrlparse/components/context.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class ixbrlContext:  # noqa: N801
    """Class to represent an ixbrl context.

    The context should either have an instant date or a start and end date.

    Attributes:
        id: The id of the context.
        entity: A dictionary of the entity information.
        segments: A list of dictionaries of the segment information.
        instant: The instant date of the context.
        startdate: The start date of the context.
        enddate: The end date of the context."""

    def __init__(
        self,
        _id: str,
        entity: Dict[str, Optional[str]],
        segments: Optional[List[Dict]],
        instant: Optional[str],
        startdate: Optional[str],
        enddate: Optional[str],
    ):
        self.id = _id
        self.entity = entity
        self.segments = segments
        self.instant: Optional[datetime.date] = None
        self.startdate: Optional[datetime.date] = None
        self.enddate: Optional[datetime.date] = None

        date_fields = {
            "instant": instant,
            "startdate": startdate,
            "enddate": enddate,
        }
        for field, value in date_fields.items():
            if value:
                datevalue = datetime.datetime.strptime(value.strip(), "%Y-%m-%d").astimezone().date()
                setattr(self, field, datevalue)

    def __repr__(self) -> str:
        if self.startdate and self.enddate:
            datestr = f"{self.startdate} to {self.enddate}"
        else:
            datestr = str(self.instant)

        segmentstr = " (with segments)" if self.segments else ""

        return f"<IXBRLContext {self.id} [{datestr}]{segmentstr}>"

    def to_json(self) -> Dict[str, List[Dict[str, Any]]]:
        """Convert the object to a JSON serialisable dictionary."""
        values = deepcopy(self.__dict__)
        for i in ["startdate", "enddate", "instant"]:
            if isinstance(values[i], datetime.date):
                values[i] = str(values[i])
        return values

to_json()

Convert the object to a JSON serialisable dictionary.

Source code in src/ixbrlparse/components/context.py
55
56
57
58
59
60
61
def to_json(self) -> Dict[str, List[Dict[str, Any]]]:
    """Convert the object to a JSON serialisable dictionary."""
    values = deepcopy(self.__dict__)
    for i in ["startdate", "enddate", "instant"]:
        if isinstance(values[i], datetime.date):
            values[i] = str(values[i])
    return values

ixbrlparse.ixbrlNonNumeric

Models a non-numeric element in an iXBRL document

Non-numeric elements are used to store information such as the name of the entity, the name of the reporting period, etc. The value of non-numeric elements is always a string, so we don't need to worry about parsing the string.

Source code in src/ixbrlparse/components/nonnumeric.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
class ixbrlNonNumeric:  # noqa: N801
    """Models a non-numeric element in an iXBRL document

    Non-numeric elements are used to store information such as the name of the
    entity, the name of the reporting period, etc.
    The value of non-numeric elements is always a string, so we don't need to
    worry about parsing the string."""

    def __init__(
        self,
        context: Optional[Union[ixbrlContext, str]] = None,
        name: Optional[str] = None,
        format_: Optional[str] = None,
        value: Optional[str] = None,
        soup_tag: Optional[Tag] = None,
    ) -> None:
        """Constructor for the ixbrlNonNumeric class.

        Parameters:
            context (ixbrlContext): The context of the non-numeric element
            name (str): The name of the non-numeric element
            format_ (str): The format of the non-numeric element
            value (str): The value of the non-numeric element
            soup_tag (Tag): The source tag in beautiful soup
        """
        if isinstance(name, str):
            name_split: List[str] = name.split(":", maxsplit=1)
            if len(name_split) == NAME_SPLIT_EXPECTED:
                self.schema = name_split[0]
                self.name = name_split[1]
            else:
                self.schema = "unknown"
                self.name = name_split[0]

        self.context = context
        self.format: Optional[ixbrlFormat] = None
        self.text: Optional[str] = value
        self.value: Optional[Union[str, int, float, None, date]] = value
        if isinstance(format_, str) and format_ != "" and self.text is not None:
            try:
                self.format = get_format(format_)(format_=format_)
                self.value = self.format.parse_value(self.text)
            except NotImplementedError:
                msg = f"Format {format_} not implemented - value '{value}' not parsed"
                warnings.warn(msg, stacklevel=2)
        self.soup_tag = soup_tag

    def to_json(self) -> Dict[str, Any]:
        values = {k: deepcopy(v) for k, v in self.__dict__.items() if k != "soup_tag"}
        if isinstance(self.value, date):
            values["value"] = self.value.isoformat()
        if isinstance(self.format, ixbrlFormat):
            values["format"] = self.format.to_json()
        if isinstance(self.context, ixbrlContext):
            values["context"] = self.context.to_json()
        return values

__init__(context=None, name=None, format_=None, value=None, soup_tag=None)

Constructor for the ixbrlNonNumeric class.

Parameters:

Name Type Description Default
context ixbrlContext

The context of the non-numeric element

None
name str

The name of the non-numeric element

None
format_ str

The format of the non-numeric element

None
value str

The value of the non-numeric element

None
soup_tag Tag

The source tag in beautiful soup

None
Source code in src/ixbrlparse/components/nonnumeric.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
def __init__(
    self,
    context: Optional[Union[ixbrlContext, str]] = None,
    name: Optional[str] = None,
    format_: Optional[str] = None,
    value: Optional[str] = None,
    soup_tag: Optional[Tag] = None,
) -> None:
    """Constructor for the ixbrlNonNumeric class.

    Parameters:
        context (ixbrlContext): The context of the non-numeric element
        name (str): The name of the non-numeric element
        format_ (str): The format of the non-numeric element
        value (str): The value of the non-numeric element
        soup_tag (Tag): The source tag in beautiful soup
    """
    if isinstance(name, str):
        name_split: List[str] = name.split(":", maxsplit=1)
        if len(name_split) == NAME_SPLIT_EXPECTED:
            self.schema = name_split[0]
            self.name = name_split[1]
        else:
            self.schema = "unknown"
            self.name = name_split[0]

    self.context = context
    self.format: Optional[ixbrlFormat] = None
    self.text: Optional[str] = value
    self.value: Optional[Union[str, int, float, None, date]] = value
    if isinstance(format_, str) and format_ != "" and self.text is not None:
        try:
            self.format = get_format(format_)(format_=format_)
            self.value = self.format.parse_value(self.text)
        except NotImplementedError:
            msg = f"Format {format_} not implemented - value '{value}' not parsed"
            warnings.warn(msg, stacklevel=2)
    self.soup_tag = soup_tag

ixbrlparse.ixbrlNumeric

Models a numeric element in an iXBRL document

Source code in src/ixbrlparse/components/numeric.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class ixbrlNumeric:  # noqa: N801
    """Models a numeric element in an iXBRL document"""

    def __init__(
        self,
        name: Optional[str] = None,
        unit: Optional[str] = None,
        value: Optional[Union[str, int, float]] = None,
        text: Optional[Union[str, int, float]] = None,
        context: Union[ixbrlContext, str, None] = None,
        soup_tag: Optional[Tag] = None,
        **attrs,
    ) -> None:
        """Constructor for the ixbrlNumeric class.

        Parameters:
            name (str): The name of the numeric element
            unit (str): The unit of the numeric element
            value (float): The value of the numeric element
            text (str): The text of the numeric element
            context (ixbrlContext): The context of the numeric element
            soup_tag (Tag): The source tag in beautiful soup
        """
        self.name: Optional[str] = name
        self.schema: str = "unknown"
        if isinstance(name, str):
            name_value = name.split(":", maxsplit=1)
            if len(name_value) == NAME_SPLIT_EXPECTED:
                self.schema = name_value[0]
                self.name = name_value[1]
            else:
                self.schema = "unknown"
                self.name = name_value[0]

        if not isinstance(value, (str, int, float)):
            value = text
        if not isinstance(value, (str, int, float)):
            msg = "Must provide either value or text"
            raise ValueError(msg)
        self.text: Union[str, int, float] = value
        self.context: Union[ixbrlContext, str, None] = context
        self.unit: Optional[str] = unit
        self.value: Optional[Union[int, float]] = None
        self.soup_tag = soup_tag

        format_ = {
            "format_": attrs.get("format"),
            "decimals": attrs.get("decimals", "0"),
            "scale": attrs.get("scale", 0),
            "sign": attrs.get("sign", ""),
        }
        self.format: Optional[ixbrlFormat] = get_format(format_["format_"])(**format_)

        try:
            if isinstance(self.format, ixbrlFormat):
                parsed_value = self.format.parse_value(self.text)
                if isinstance(parsed_value, (int, float)):
                    self.value = parsed_value
        except ValueError:
            logging.info(attrs)
            raise

    def to_json(self) -> Dict:
        values = {k: deepcopy(v) for k, v in self.__dict__.items() if k != "soup_tag"}
        if isinstance(self.format, ixbrlFormat):
            values["format"] = self.format.to_json()
        if isinstance(self.context, ixbrlContext):
            values["context"] = self.context.to_json()
        return values

__init__(name=None, unit=None, value=None, text=None, context=None, soup_tag=None, **attrs)

Constructor for the ixbrlNumeric class.

Parameters:

Name Type Description Default
name str

The name of the numeric element

None
unit str

The unit of the numeric element

None
value float

The value of the numeric element

None
text str

The text of the numeric element

None
context ixbrlContext

The context of the numeric element

None
soup_tag Tag

The source tag in beautiful soup

None
Source code in src/ixbrlparse/components/numeric.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
def __init__(
    self,
    name: Optional[str] = None,
    unit: Optional[str] = None,
    value: Optional[Union[str, int, float]] = None,
    text: Optional[Union[str, int, float]] = None,
    context: Union[ixbrlContext, str, None] = None,
    soup_tag: Optional[Tag] = None,
    **attrs,
) -> None:
    """Constructor for the ixbrlNumeric class.

    Parameters:
        name (str): The name of the numeric element
        unit (str): The unit of the numeric element
        value (float): The value of the numeric element
        text (str): The text of the numeric element
        context (ixbrlContext): The context of the numeric element
        soup_tag (Tag): The source tag in beautiful soup
    """
    self.name: Optional[str] = name
    self.schema: str = "unknown"
    if isinstance(name, str):
        name_value = name.split(":", maxsplit=1)
        if len(name_value) == NAME_SPLIT_EXPECTED:
            self.schema = name_value[0]
            self.name = name_value[1]
        else:
            self.schema = "unknown"
            self.name = name_value[0]

    if not isinstance(value, (str, int, float)):
        value = text
    if not isinstance(value, (str, int, float)):
        msg = "Must provide either value or text"
        raise ValueError(msg)
    self.text: Union[str, int, float] = value
    self.context: Union[ixbrlContext, str, None] = context
    self.unit: Optional[str] = unit
    self.value: Optional[Union[int, float]] = None
    self.soup_tag = soup_tag

    format_ = {
        "format_": attrs.get("format"),
        "decimals": attrs.get("decimals", "0"),
        "scale": attrs.get("scale", 0),
        "sign": attrs.get("sign", ""),
    }
    self.format: Optional[ixbrlFormat] = get_format(format_["format_"])(**format_)

    try:
        if isinstance(self.format, ixbrlFormat):
            parsed_value = self.format.parse_value(self.text)
            if isinstance(parsed_value, (int, float)):
                self.value = parsed_value
    except ValueError:
        logging.info(attrs)
        raise