boarddata 4.0.1__tar.gz → 4.0.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.
- {boarddata-4.0.1 → boarddata-4.0.2}/PKG-INFO +1 -1
- {boarddata-4.0.1 → boarddata-4.0.2}/__init__.py +1 -1
- {boarddata-4.0.1 → boarddata-4.0.2}/_comex.py +3 -0
- boarddata-4.0.2/_criteria.py +68 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/boarddata.egg-info/PKG-INFO +1 -1
- {boarddata-4.0.1 → boarddata-4.0.2}/boarddata.egg-info/SOURCES.txt +4 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/client.py +2 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/pyproject.toml +1 -1
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_comex.py +2 -0
- boarddata-4.0.2/tests/test_criteria.py +68 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/types/comex.py +4 -0
- boarddata-4.0.2/types/criteria.py +34 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/CLAUDE.md +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/README.md +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/_assemblies.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/_auditors.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/_base.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/_companies.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/_directors.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/_documents.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/_esg.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/_persons.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/_sentinel.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/_utilities.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/boarddata.egg-info/dependency_links.txt +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/boarddata.egg-info/requires.txt +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/boarddata.egg-info/top_level.txt +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/cache.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/errors.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/py.typed +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/setup.cfg +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/__init__.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/conftest.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_assemblies.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_auditors.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_base.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_build_payload.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_cache.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_companies.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_config.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_directors.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_documents.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_esg.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_persons.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_sentinel.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/tests/test_utilities.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/types/__init__.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/types/assemblies.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/types/auditors.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/types/companies.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/types/core.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/types/directors.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/types/documents.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/types/esg.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/types/persons.py +0 -0
- {boarddata-4.0.1 → boarddata-4.0.2}/types/sentinel.py +0 -0
|
@@ -288,6 +288,7 @@ class ComexMixin:
|
|
|
288
288
|
has_employment_contract: bool | None = None,
|
|
289
289
|
discretionary_grant: bool | None = None,
|
|
290
290
|
subsidiary_remuneration: str | None = None,
|
|
291
|
+
remuneration_via_holding: bool | None = None,
|
|
291
292
|
currency: str | None = None,
|
|
292
293
|
field_sources: list[FieldSourcePayload] | None = None,
|
|
293
294
|
criteria: list[dict[str, Any]] | None = None,
|
|
@@ -335,6 +336,7 @@ class ComexMixin:
|
|
|
335
336
|
has_employment_contract: Whether has employment contract.
|
|
336
337
|
discretionary_grant: Whether discretionary grant applies.
|
|
337
338
|
subsidiary_remuneration: Subsidiary remuneration (decimal).
|
|
339
|
+
remuneration_via_holding: Whether remuneration is provided via holding.
|
|
338
340
|
currency: Currency code (e.g. ``"EUR"``).
|
|
339
341
|
field_sources: Document provenance for fields.
|
|
340
342
|
criteria: List of compensation criteria dicts.
|
|
@@ -385,6 +387,7 @@ class ComexMixin:
|
|
|
385
387
|
has_employment_contract=has_employment_contract,
|
|
386
388
|
discretionary_grant=discretionary_grant,
|
|
387
389
|
subsidiary_remuneration=subsidiary_remuneration,
|
|
390
|
+
remuneration_via_holding=remuneration_via_holding,
|
|
388
391
|
currency=currency,
|
|
389
392
|
field_sources=field_sources,
|
|
390
393
|
criteria=criteria,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Criteria catalog and theme methods."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from .types.criteria import CriteriaCatalogItem, CriteriaThemeItem
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CriteriaMixin:
|
|
11
|
+
"""Criteria catalog and theme API methods.
|
|
12
|
+
|
|
13
|
+
Provides access to the shared criteria catalog used by compensation
|
|
14
|
+
records across all comex mandates.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def list_criteria_themes(self) -> list[CriteriaThemeItem]:
|
|
18
|
+
"""List all criteria themes.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
List of criteria themes (not paginated).
|
|
22
|
+
|
|
23
|
+
Raises:
|
|
24
|
+
BoardDataError: On non-2xx API response.
|
|
25
|
+
"""
|
|
26
|
+
return self._get("criteria-themes/") # type: ignore[attr-defined]
|
|
27
|
+
|
|
28
|
+
def list_criteria(
|
|
29
|
+
self,
|
|
30
|
+
theme: str | None = None,
|
|
31
|
+
) -> list[CriteriaCatalogItem]:
|
|
32
|
+
"""List all criteria catalog entries.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
theme: Filter by criteria theme UUID.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
List of criteria (not paginated).
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
BoardDataError: On non-2xx API response.
|
|
42
|
+
"""
|
|
43
|
+
params: dict[str, Any] = {}
|
|
44
|
+
if theme is not None:
|
|
45
|
+
params["theme"] = theme
|
|
46
|
+
return self._get("criteria/", **params) # type: ignore[attr-defined]
|
|
47
|
+
|
|
48
|
+
def create_criteria(
|
|
49
|
+
self,
|
|
50
|
+
name: str,
|
|
51
|
+
theme_id: str | None = None,
|
|
52
|
+
) -> CriteriaCatalogItem:
|
|
53
|
+
"""Create a criteria catalog entry.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
name: Standardized criterion name (e.g. ``"Revenue Growth"``).
|
|
57
|
+
theme_id: UUID of the criteria theme.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Created criteria entry.
|
|
61
|
+
|
|
62
|
+
Raises:
|
|
63
|
+
BoardDataError: On non-2xx API response.
|
|
64
|
+
"""
|
|
65
|
+
payload: dict[str, Any] = {"name": name}
|
|
66
|
+
if theme_id is not None:
|
|
67
|
+
payload["theme_id"] = theme_id
|
|
68
|
+
return self._post("criteria/", payload) # type: ignore[attr-defined]
|
|
@@ -6,6 +6,7 @@ _auditors.py
|
|
|
6
6
|
_base.py
|
|
7
7
|
_comex.py
|
|
8
8
|
_companies.py
|
|
9
|
+
_criteria.py
|
|
9
10
|
_directors.py
|
|
10
11
|
_documents.py
|
|
11
12
|
_esg.py
|
|
@@ -24,6 +25,7 @@ pyproject.toml
|
|
|
24
25
|
./_base.py
|
|
25
26
|
./_comex.py
|
|
26
27
|
./_companies.py
|
|
28
|
+
./_criteria.py
|
|
27
29
|
./_directors.py
|
|
28
30
|
./_documents.py
|
|
29
31
|
./_esg.py
|
|
@@ -49,6 +51,7 @@ tests/test_cache.py
|
|
|
49
51
|
tests/test_comex.py
|
|
50
52
|
tests/test_companies.py
|
|
51
53
|
tests/test_config.py
|
|
54
|
+
tests/test_criteria.py
|
|
52
55
|
tests/test_directors.py
|
|
53
56
|
tests/test_documents.py
|
|
54
57
|
tests/test_esg.py
|
|
@@ -61,6 +64,7 @@ types/auditors.py
|
|
|
61
64
|
types/comex.py
|
|
62
65
|
types/companies.py
|
|
63
66
|
types/core.py
|
|
67
|
+
types/criteria.py
|
|
64
68
|
types/directors.py
|
|
65
69
|
types/documents.py
|
|
66
70
|
types/esg.py
|
|
@@ -7,6 +7,7 @@ from ._auditors import AuditorMixin
|
|
|
7
7
|
from ._base import Base
|
|
8
8
|
from ._comex import ComexMixin
|
|
9
9
|
from ._companies import CompanyMixin
|
|
10
|
+
from ._criteria import CriteriaMixin
|
|
10
11
|
from ._directors import DirectorMixin
|
|
11
12
|
from ._documents import DocumentMixin
|
|
12
13
|
from ._esg import ESGMixin
|
|
@@ -25,6 +26,7 @@ class BoardDataClient(
|
|
|
25
26
|
AssemblyMixin,
|
|
26
27
|
ESGMixin,
|
|
27
28
|
SentinelMixin,
|
|
29
|
+
CriteriaMixin,
|
|
28
30
|
UtilitiesMixin,
|
|
29
31
|
Base,
|
|
30
32
|
):
|
|
@@ -26,12 +26,14 @@ class TestCreateComexCompensation:
|
|
|
26
26
|
c.create_comex_compensation(
|
|
27
27
|
"comex-uuid", 2024, "REAL",
|
|
28
28
|
fixed="500000.00", variable="200000.00", currency="EUR",
|
|
29
|
+
remuneration_via_holding=True,
|
|
29
30
|
)
|
|
30
31
|
_, kwargs = c._request.call_args
|
|
31
32
|
payload = kwargs["json"]
|
|
32
33
|
assert payload["fixed"] == "500000.00"
|
|
33
34
|
assert payload["variable"] == "200000.00"
|
|
34
35
|
assert payload["currency"] == "EUR"
|
|
36
|
+
assert payload["remuneration_via_holding"] is True
|
|
35
37
|
assert "token_personal" not in payload # board field, not comex
|
|
36
38
|
|
|
37
39
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Tests for CriteriaMixin methods."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from unittest.mock import MagicMock
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def make_client():
|
|
9
|
+
from boarddata._criteria import CriteriaMixin
|
|
10
|
+
from boarddata._base import Base
|
|
11
|
+
|
|
12
|
+
class TestClient(CriteriaMixin, 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 TestListCriteriaThemes:
|
|
24
|
+
def test_calls_correct_path(self):
|
|
25
|
+
c = make_client()
|
|
26
|
+
c._request.return_value = [{"id": "t1", "name": "Financial"}]
|
|
27
|
+
result = c.list_criteria_themes()
|
|
28
|
+
args, _ = c._request.call_args
|
|
29
|
+
assert args == ("GET", "criteria-themes/")
|
|
30
|
+
assert result[0]["name"] == "Financial"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TestListCriteria:
|
|
34
|
+
def test_calls_correct_path(self):
|
|
35
|
+
c = make_client()
|
|
36
|
+
c._request.return_value = [{"id": "c1", "name": "Revenue Growth"}]
|
|
37
|
+
result = c.list_criteria()
|
|
38
|
+
args, _ = c._request.call_args
|
|
39
|
+
assert args == ("GET", "criteria/")
|
|
40
|
+
assert result[0]["name"] == "Revenue Growth"
|
|
41
|
+
|
|
42
|
+
def test_filters_by_theme(self):
|
|
43
|
+
c = make_client()
|
|
44
|
+
c._request.return_value = []
|
|
45
|
+
c.list_criteria(theme="theme-uuid")
|
|
46
|
+
_, kwargs = c._request.call_args
|
|
47
|
+
assert kwargs["params"]["theme"] == "theme-uuid"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class TestCreateCriteria:
|
|
51
|
+
def test_sends_payload(self):
|
|
52
|
+
c = make_client()
|
|
53
|
+
c._request.return_value = {"id": "c1", "name": "Revenue Growth"}
|
|
54
|
+
result = c.create_criteria("Revenue Growth", theme_id="theme-uuid")
|
|
55
|
+
_, kwargs = c._request.call_args
|
|
56
|
+
payload = kwargs["json"]
|
|
57
|
+
assert payload["name"] == "Revenue Growth"
|
|
58
|
+
assert payload["theme_id"] == "theme-uuid"
|
|
59
|
+
assert result["id"] == "c1"
|
|
60
|
+
|
|
61
|
+
def test_without_theme(self):
|
|
62
|
+
c = make_client()
|
|
63
|
+
c._request.return_value = {"id": "c2", "name": "Safety Rate"}
|
|
64
|
+
c.create_criteria("Safety Rate")
|
|
65
|
+
_, kwargs = c._request.call_args
|
|
66
|
+
payload = kwargs["json"]
|
|
67
|
+
assert payload["name"] == "Safety Rate"
|
|
68
|
+
assert "theme_id" not in payload
|
|
@@ -103,6 +103,7 @@ class ComexCompensationItem(TypedDict):
|
|
|
103
103
|
subsidiary_remuneration: str | None
|
|
104
104
|
holding: bool
|
|
105
105
|
has_employment_contract: bool
|
|
106
|
+
remuneration_via_holding: bool
|
|
106
107
|
total: str | None
|
|
107
108
|
total_paid: str | None
|
|
108
109
|
currency: str
|
|
@@ -149,6 +150,7 @@ class ComexCompensationDetail(TypedDict):
|
|
|
149
150
|
has_employment_contract: bool
|
|
150
151
|
discretionary_grant: bool
|
|
151
152
|
subsidiary_remuneration: str | None
|
|
153
|
+
remuneration_via_holding: bool
|
|
152
154
|
currency: str
|
|
153
155
|
total: str | None
|
|
154
156
|
total_paid: str | None
|
|
@@ -196,6 +198,7 @@ class CreateComexCompensationPayload(TypedDict):
|
|
|
196
198
|
has_employment_contract: NotRequired[bool]
|
|
197
199
|
discretionary_grant: NotRequired[bool]
|
|
198
200
|
subsidiary_remuneration: NotRequired[str | None]
|
|
201
|
+
remuneration_via_holding: NotRequired[bool]
|
|
199
202
|
currency: NotRequired[str]
|
|
200
203
|
field_sources: NotRequired[list[FieldSourcePayload]]
|
|
201
204
|
criteria: NotRequired[list[dict[str, Any]]]
|
|
@@ -241,6 +244,7 @@ class UpdateComexCompensationPayload(TypedDict, total=False):
|
|
|
241
244
|
has_employment_contract: bool
|
|
242
245
|
discretionary_grant: bool
|
|
243
246
|
subsidiary_remuneration: str | None
|
|
247
|
+
remuneration_via_holding: bool
|
|
244
248
|
currency: str
|
|
245
249
|
field_sources: list[FieldSourcePayload]
|
|
246
250
|
criteria: list[dict[str, Any]]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Criteria catalog types."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
from typing import NotRequired, TypedDict
|
|
7
|
+
except ImportError:
|
|
8
|
+
from typing_extensions import NotRequired, TypedDict
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CriteriaThemeItem(TypedDict):
|
|
12
|
+
"""Criteria theme as returned by the criteria-themes endpoint."""
|
|
13
|
+
|
|
14
|
+
id: str
|
|
15
|
+
name: str
|
|
16
|
+
description: str
|
|
17
|
+
category: str
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CriteriaCatalogItem(TypedDict):
|
|
21
|
+
"""Criteria catalog entry as returned by the criteria endpoint."""
|
|
22
|
+
|
|
23
|
+
id: str
|
|
24
|
+
name: str
|
|
25
|
+
theme_id: str | None
|
|
26
|
+
theme_name: str
|
|
27
|
+
theme_category: str
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class CreateCriteriaPayload(TypedDict, total=False):
|
|
31
|
+
"""Payload for creating a criteria catalog entry."""
|
|
32
|
+
|
|
33
|
+
name: str
|
|
34
|
+
theme_id: str | None
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|