boarddata 6.5.1__tar.gz → 6.6.2__tar.gz

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.
Files changed (66) hide show
  1. {boarddata-6.5.1 → boarddata-6.6.2}/PKG-INFO +1 -1
  2. {boarddata-6.5.1 → boarddata-6.6.2}/__init__.py +1 -1
  3. boarddata-6.6.2/_committees.py +16 -0
  4. boarddata-6.6.2/_risks.py +35 -0
  5. {boarddata-6.5.1 → boarddata-6.6.2}/boarddata.egg-info/PKG-INFO +1 -1
  6. {boarddata-6.5.1 → boarddata-6.6.2}/boarddata.egg-info/SOURCES.txt +8 -0
  7. {boarddata-6.5.1 → boarddata-6.6.2}/client.py +4 -0
  8. {boarddata-6.5.1 → boarddata-6.6.2}/pyproject.toml +1 -1
  9. boarddata-6.6.2/tests/test_committees.py +32 -0
  10. boarddata-6.6.2/tests/test_risks.py +59 -0
  11. {boarddata-6.5.1 → boarddata-6.6.2}/types/__init__.py +7 -0
  12. boarddata-6.6.2/types/committees.py +27 -0
  13. boarddata-6.6.2/types/risks.py +53 -0
  14. {boarddata-6.5.1 → boarddata-6.6.2}/CLAUDE.md +0 -0
  15. {boarddata-6.5.1 → boarddata-6.6.2}/README.md +0 -0
  16. {boarddata-6.5.1 → boarddata-6.6.2}/_assemblies.py +0 -0
  17. {boarddata-6.5.1 → boarddata-6.6.2}/_auditors.py +0 -0
  18. {boarddata-6.5.1 → boarddata-6.6.2}/_base.py +0 -0
  19. {boarddata-6.5.1 → boarddata-6.6.2}/_comex.py +0 -0
  20. {boarddata-6.5.1 → boarddata-6.6.2}/_companies.py +0 -0
  21. {boarddata-6.5.1 → boarddata-6.6.2}/_criteria.py +0 -0
  22. {boarddata-6.5.1 → boarddata-6.6.2}/_directors.py +0 -0
  23. {boarddata-6.5.1 → boarddata-6.6.2}/_documents.py +0 -0
  24. {boarddata-6.5.1 → boarddata-6.6.2}/_esg.py +0 -0
  25. {boarddata-6.5.1 → boarddata-6.6.2}/_indexes.py +0 -0
  26. {boarddata-6.5.1 → boarddata-6.6.2}/_persons.py +0 -0
  27. {boarddata-6.5.1 → boarddata-6.6.2}/_sentinel.py +0 -0
  28. {boarddata-6.5.1 → boarddata-6.6.2}/_utilities.py +0 -0
  29. {boarddata-6.5.1 → boarddata-6.6.2}/boarddata.egg-info/dependency_links.txt +0 -0
  30. {boarddata-6.5.1 → boarddata-6.6.2}/boarddata.egg-info/requires.txt +0 -0
  31. {boarddata-6.5.1 → boarddata-6.6.2}/boarddata.egg-info/top_level.txt +0 -0
  32. {boarddata-6.5.1 → boarddata-6.6.2}/cache.py +0 -0
  33. {boarddata-6.5.1 → boarddata-6.6.2}/errors.py +0 -0
  34. {boarddata-6.5.1 → boarddata-6.6.2}/py.typed +0 -0
  35. {boarddata-6.5.1 → boarddata-6.6.2}/setup.cfg +0 -0
  36. {boarddata-6.5.1 → boarddata-6.6.2}/tests/__init__.py +0 -0
  37. {boarddata-6.5.1 → boarddata-6.6.2}/tests/conftest.py +0 -0
  38. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_assemblies.py +0 -0
  39. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_auditors.py +0 -0
  40. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_base.py +0 -0
  41. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_build_payload.py +0 -0
  42. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_cache.py +0 -0
  43. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_comex.py +0 -0
  44. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_companies.py +0 -0
  45. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_config.py +0 -0
  46. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_criteria.py +0 -0
  47. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_directors.py +0 -0
  48. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_documents.py +0 -0
  49. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_esg.py +0 -0
  50. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_exports.py +0 -0
  51. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_indexes.py +0 -0
  52. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_persons.py +0 -0
  53. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_sentinel.py +0 -0
  54. {boarddata-6.5.1 → boarddata-6.6.2}/tests/test_utilities.py +0 -0
  55. {boarddata-6.5.1 → boarddata-6.6.2}/types/assemblies.py +0 -0
  56. {boarddata-6.5.1 → boarddata-6.6.2}/types/auditors.py +0 -0
  57. {boarddata-6.5.1 → boarddata-6.6.2}/types/comex.py +0 -0
  58. {boarddata-6.5.1 → boarddata-6.6.2}/types/companies.py +0 -0
  59. {boarddata-6.5.1 → boarddata-6.6.2}/types/core.py +0 -0
  60. {boarddata-6.5.1 → boarddata-6.6.2}/types/criteria.py +0 -0
  61. {boarddata-6.5.1 → boarddata-6.6.2}/types/directors.py +0 -0
  62. {boarddata-6.5.1 → boarddata-6.6.2}/types/documents.py +0 -0
  63. {boarddata-6.5.1 → boarddata-6.6.2}/types/esg.py +0 -0
  64. {boarddata-6.5.1 → boarddata-6.6.2}/types/indexes.py +0 -0
  65. {boarddata-6.5.1 → boarddata-6.6.2}/types/persons.py +0 -0
  66. {boarddata-6.5.1 → boarddata-6.6.2}/types/sentinel.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boarddata
3
- Version: 6.5.1
3
+ Version: 6.6.2
4
4
  Summary: Python SDK for the BoardData V2 REST API
5
5
  License: MIT
6
6
  Classifier: Development Status :: 4 - Beta
@@ -6,7 +6,7 @@ from .cache import FileTokenCache, ScalewaySecretTokenCache
6
6
  from .client import BoardDataClient
7
7
  from .errors import BoardDataError, ExportTooLargeError
8
8
 
9
- __version__ = "6.5.1"
9
+ __version__ = "6.6.2"
10
10
  __all__ = [
11
11
  "Base",
12
12
  "BoardDataClient",
@@ -0,0 +1,16 @@
1
+ """Board-committee batch methods."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .types.committees import CommitteeBatchItemPayload, CommitteeBatchResultItem
6
+
7
+
8
+ class CommitteesMixin:
9
+ def batch_create_committees(
10
+ self, items: list[CommitteeBatchItemPayload]
11
+ ) -> list[CommitteeBatchResultItem]:
12
+ """Batch upsert board committees. Each item is keyed by issuer ISIN;
13
+ the backend resolves members to existing persons and idempotently
14
+ upserts Committee + CommitteeMembership. Returns one result per item
15
+ (action: loaded / skipped_unknown_company / error)."""
16
+ return self._post("committees/batch/", items) # type: ignore[attr-defined]
@@ -0,0 +1,35 @@
1
+ """Risk-Factors (Art. 16) methods."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .types.risks import RiskSectionBatchItemPayload, RiskSectionBatchResultItem
6
+
7
+
8
+ class RisksMixin:
9
+ """Risk-Factors API methods (Art. 16 'Risk Factors' disclosure)."""
10
+
11
+ def batch_create_risk_section(
12
+ self,
13
+ sections: list[RiskSectionBatchItemPayload],
14
+ ) -> list[RiskSectionBatchResultItem]:
15
+ """Batch upsert risk sections.
16
+
17
+ Each item is matched by the natural key ``(company, date_publication)``,
18
+ where ``company`` is the issuer ISIN; the backend does a delete-and-replace
19
+ of the section's categories and factors. A ``section_found: false`` envelope
20
+ is accepted (it records the negative finding).
21
+
22
+ Args:
23
+ sections: List of risk-section envelopes
24
+ (``company``, ``date_publication``, ``_risk_section``,
25
+ ``_risk_categories``, ``_risk_factor_items``).
26
+
27
+ Returns:
28
+ One result per item, each with ``company`` and ``action``
29
+ (``"loaded"`` / ``"skipped_unknown_company"`` / ``"error"``); a loaded
30
+ section also carries ``section_id`` and ``factor_count``.
31
+
32
+ Raises:
33
+ BoardDataError: On non-2xx API response.
34
+ """
35
+ return self._post("risks/batch/", sections) # type: ignore[attr-defined]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boarddata
3
- Version: 6.5.1
3
+ Version: 6.6.2
4
4
  Summary: Python SDK for the BoardData V2 REST API
5
5
  License: MIT
6
6
  Classifier: Development Status :: 4 - Beta
@@ -5,6 +5,7 @@ _assemblies.py
5
5
  _auditors.py
6
6
  _base.py
7
7
  _comex.py
8
+ _committees.py
8
9
  _companies.py
9
10
  _criteria.py
10
11
  _directors.py
@@ -12,6 +13,7 @@ _documents.py
12
13
  _esg.py
13
14
  _indexes.py
14
15
  _persons.py
16
+ _risks.py
15
17
  _sentinel.py
16
18
  _utilities.py
17
19
  cache.py
@@ -25,6 +27,7 @@ pyproject.toml
25
27
  ./_auditors.py
26
28
  ./_base.py
27
29
  ./_comex.py
30
+ ./_committees.py
28
31
  ./_companies.py
29
32
  ./_criteria.py
30
33
  ./_directors.py
@@ -32,6 +35,7 @@ pyproject.toml
32
35
  ./_esg.py
33
36
  ./_indexes.py
34
37
  ./_persons.py
38
+ ./_risks.py
35
39
  ./_sentinel.py
36
40
  ./_utilities.py
37
41
  ./cache.py
@@ -51,6 +55,7 @@ tests/test_base.py
51
55
  tests/test_build_payload.py
52
56
  tests/test_cache.py
53
57
  tests/test_comex.py
58
+ tests/test_committees.py
54
59
  tests/test_companies.py
55
60
  tests/test_config.py
56
61
  tests/test_criteria.py
@@ -60,12 +65,14 @@ tests/test_esg.py
60
65
  tests/test_exports.py
61
66
  tests/test_indexes.py
62
67
  tests/test_persons.py
68
+ tests/test_risks.py
63
69
  tests/test_sentinel.py
64
70
  tests/test_utilities.py
65
71
  types/__init__.py
66
72
  types/assemblies.py
67
73
  types/auditors.py
68
74
  types/comex.py
75
+ types/committees.py
69
76
  types/companies.py
70
77
  types/core.py
71
78
  types/criteria.py
@@ -74,4 +81,5 @@ types/documents.py
74
81
  types/esg.py
75
82
  types/indexes.py
76
83
  types/persons.py
84
+ types/risks.py
77
85
  types/sentinel.py
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  from ._assemblies import AssemblyMixin
6
6
  from ._auditors import AuditorMixin
7
7
  from ._base import Base
8
+ from ._committees import CommitteesMixin
8
9
  from ._comex import ComexMixin
9
10
  from ._companies import CompanyMixin
10
11
  from ._criteria import CriteriaMixin
@@ -13,6 +14,7 @@ from ._documents import DocumentMixin
13
14
  from ._esg import ESGMixin
14
15
  from ._indexes import IndexMixin
15
16
  from ._persons import PersonMixin
17
+ from ._risks import RisksMixin
16
18
  from ._sentinel import SentinelMixin
17
19
  from ._utilities import UtilitiesMixin
18
20
 
@@ -25,7 +27,9 @@ class BoardDataClient(
25
27
  AuditorMixin,
26
28
  DocumentMixin,
27
29
  AssemblyMixin,
30
+ CommitteesMixin,
28
31
  ESGMixin,
32
+ RisksMixin,
29
33
  SentinelMixin,
30
34
  CriteriaMixin,
31
35
  IndexMixin,
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "boarddata"
7
- version = "6.5.1"
7
+ version = "6.6.2"
8
8
  description = "Python SDK for the BoardData V2 REST API"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -0,0 +1,32 @@
1
+ """Tests for CommitteesMixin methods."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from unittest.mock import MagicMock
6
+
7
+
8
+ def make_client():
9
+ from boarddata._base import Base
10
+ from boarddata._committees import CommitteesMixin
11
+
12
+ class TestClient(CommitteesMixin, Base):
13
+ pass
14
+
15
+ client = TestClient.__new__(TestClient)
16
+ client._request = MagicMock()
17
+ client._get_token = MagicMock(return_value="fake-token")
18
+ client.base_url = "https://api.example.com"
19
+ client.timeout = 30
20
+ return client
21
+
22
+
23
+ class TestBatchCreateCommittees:
24
+ def test_batch_create_committees_posts_to_endpoint(self):
25
+ c = make_client()
26
+ c._request.return_value = [{"company": "FR0000000020", "action": "loaded"}]
27
+ items = [{"company": "FR0000000020", "year": 2025, "committees": []}]
28
+ out = c.batch_create_committees(items)
29
+ args, kwargs = c._request.call_args
30
+ assert args == ("POST", "committees/batch/")
31
+ assert kwargs["json"] is items
32
+ assert out[0]["action"] == "loaded"
@@ -0,0 +1,59 @@
1
+ """Tests for RisksMixin methods."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from unittest.mock import MagicMock
6
+
7
+
8
+ def make_client():
9
+ from boarddata._base import Base
10
+ from boarddata._risks import RisksMixin
11
+
12
+ class TestClient(RisksMixin, Base):
13
+ pass
14
+
15
+ client = TestClient.__new__(TestClient)
16
+ client._request = MagicMock()
17
+ client._get_token = MagicMock(return_value="fake-token")
18
+ client.base_url = "https://api.example.com"
19
+ client.timeout = 30
20
+ return client
21
+
22
+
23
+ class TestBatchCreateRiskSection:
24
+ def test_posts_envelopes_to_batch_path(self):
25
+ c = make_client()
26
+ c._request.return_value = [
27
+ {"company": "FR0000120271", "section_id": "s1", "factor_count": 12, "action": "loaded"}
28
+ ]
29
+ envelopes = [
30
+ {
31
+ "company": "FR0000120271",
32
+ "date_publication": "2025-01-01",
33
+ "_risk_section": {"section_found": True, "scale_type": "numeric"},
34
+ "_risk_categories": [{"label_native": "Risques financiers"}],
35
+ "_risk_factor_items": [{"title_native": "Risque de change"}],
36
+ }
37
+ ]
38
+ result = c.batch_create_risk_section(envelopes)
39
+ args, kwargs = c._request.call_args
40
+ assert args == ("POST", "risks/batch/")
41
+ assert kwargs["json"] is envelopes
42
+ assert result[0]["action"] == "loaded"
43
+ assert result[0]["factor_count"] == 12
44
+
45
+ def test_passes_section_not_found_envelope_through(self):
46
+ c = make_client()
47
+ c._request.return_value = [{"company": "FR0000131104", "action": "loaded"}]
48
+ envelopes = [
49
+ {
50
+ "company": "FR0000131104",
51
+ "date_publication": "2025-01-01",
52
+ "_risk_section": {"section_found": False},
53
+ "_risk_categories": [],
54
+ "_risk_factor_items": [],
55
+ }
56
+ ]
57
+ c.batch_create_risk_section(envelopes)
58
+ _, kwargs = c._request.call_args
59
+ assert kwargs["json"][0]["_risk_section"]["section_found"] is False
@@ -113,6 +113,10 @@ from .persons import (
113
113
  SchoolItem,
114
114
  UpdatePersonPayload,
115
115
  )
116
+ from .risks import (
117
+ RiskSectionBatchItemPayload,
118
+ RiskSectionBatchResultItem,
119
+ )
116
120
  from .sentinel import (
117
121
  AnalysisDetail,
118
122
  AnalysisListItem,
@@ -227,6 +231,9 @@ __all__ = [
227
231
  "PersonSimilarityItem",
228
232
  "SchoolItem",
229
233
  "UpdatePersonPayload",
234
+ # risks
235
+ "RiskSectionBatchItemPayload",
236
+ "RiskSectionBatchResultItem",
230
237
  # sentinel
231
238
  "AnalysisDetail",
232
239
  "AnalysisListItem",
@@ -0,0 +1,27 @@
1
+ """Committee batch types. The nested committee/member dicts are issuer-shaped;
2
+ the authoritative schema lives in the extractor + apps/committees loader."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import sys
7
+ from typing import Any
8
+
9
+ if sys.version_info >= (3, 11):
10
+ from typing import NotRequired, TypedDict
11
+ else:
12
+ from typing_extensions import NotRequired, TypedDict
13
+
14
+
15
+ class CommitteeBatchItemPayload(TypedDict):
16
+ company: str # issuer ISIN
17
+ year: int
18
+ committees: list[dict[str, Any]]
19
+
20
+
21
+ class CommitteeBatchResultItem(TypedDict):
22
+ company: str
23
+ action: str # "loaded" | "skipped_unknown_company" | "error"
24
+ committees_loaded: NotRequired[int]
25
+ memberships_loaded: NotRequired[int]
26
+ members_unmatched: NotRequired[list[str]]
27
+ detail: NotRequired[str]
@@ -0,0 +1,53 @@
1
+ """Risk-Factors (Art. 16) batch types.
2
+
3
+ The risk-section batch envelope is built by the URD extraction pipeline's
4
+ ``risk_factors`` adapter. Its nested members (``_risk_section``,
5
+ ``_risk_categories``, ``_risk_factor_items``) are issuer-shaped and carry
6
+ free-form fields (e.g. ``quant_metrics``), so they are typed loosely as
7
+ ``dict[str, Any]`` rather than fully enumerated here — the authoritative schema
8
+ lives in the extractor contract and the backend loader (``apps/risks``).
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import sys
14
+ from typing import Any
15
+
16
+ if sys.version_info >= (3, 11):
17
+ from typing import NotRequired, TypedDict
18
+ else:
19
+ from typing_extensions import NotRequired, TypedDict
20
+
21
+
22
+ class RiskSectionBatchItemPayload(TypedDict):
23
+ """One envelope in a ``batch_create_risk_section`` request.
24
+
25
+ Matched by the natural key ``(company, date_publication)``; the backend
26
+ does a delete-and-replace of the section's categories/factors.
27
+ """
28
+
29
+ company: str
30
+ """Issuer ISIN (the batch endpoint matches Company by isin, not UUID)."""
31
+ date_publication: str
32
+ """Publication date, ``"YYYY-MM-DD"``."""
33
+ _risk_section: dict[str, Any]
34
+ """Section-level scale/methodology metadata (incl. ``section_found``)."""
35
+ _risk_categories: list[dict[str, Any]]
36
+ """Category headings (native + English label)."""
37
+ _risk_factor_items: list[dict[str, Any]]
38
+ """Individual risk factors with their native ratings / field sources."""
39
+
40
+
41
+ class RiskSectionBatchResultItem(TypedDict):
42
+ """One result in a ``batch_create_risk_section`` response.
43
+
44
+ ``action`` is one of ``"loaded"`` (section upserted),
45
+ ``"skipped_unknown_company"`` (no Company for the ISIN — seed it first), or
46
+ ``"error"`` (malformed item; ``detail`` carries the message).
47
+ """
48
+
49
+ company: str
50
+ action: str
51
+ section_id: NotRequired[str]
52
+ factor_count: NotRequired[int]
53
+ detail: NotRequired[str]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes