boarddata 6.2.1__tar.gz → 6.2.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 (60) hide show
  1. {boarddata-6.2.1 → boarddata-6.2.2}/PKG-INFO +1 -1
  2. {boarddata-6.2.1 → boarddata-6.2.2}/__init__.py +1 -1
  3. {boarddata-6.2.1 → boarddata-6.2.2}/_persons.py +19 -3
  4. {boarddata-6.2.1 → boarddata-6.2.2}/boarddata.egg-info/PKG-INFO +1 -1
  5. {boarddata-6.2.1 → boarddata-6.2.2}/pyproject.toml +1 -1
  6. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_persons.py +46 -0
  7. {boarddata-6.2.1 → boarddata-6.2.2}/CLAUDE.md +0 -0
  8. {boarddata-6.2.1 → boarddata-6.2.2}/README.md +0 -0
  9. {boarddata-6.2.1 → boarddata-6.2.2}/_assemblies.py +0 -0
  10. {boarddata-6.2.1 → boarddata-6.2.2}/_auditors.py +0 -0
  11. {boarddata-6.2.1 → boarddata-6.2.2}/_base.py +0 -0
  12. {boarddata-6.2.1 → boarddata-6.2.2}/_comex.py +0 -0
  13. {boarddata-6.2.1 → boarddata-6.2.2}/_companies.py +0 -0
  14. {boarddata-6.2.1 → boarddata-6.2.2}/_criteria.py +0 -0
  15. {boarddata-6.2.1 → boarddata-6.2.2}/_directors.py +0 -0
  16. {boarddata-6.2.1 → boarddata-6.2.2}/_documents.py +0 -0
  17. {boarddata-6.2.1 → boarddata-6.2.2}/_esg.py +0 -0
  18. {boarddata-6.2.1 → boarddata-6.2.2}/_indexes.py +0 -0
  19. {boarddata-6.2.1 → boarddata-6.2.2}/_sentinel.py +0 -0
  20. {boarddata-6.2.1 → boarddata-6.2.2}/_utilities.py +0 -0
  21. {boarddata-6.2.1 → boarddata-6.2.2}/boarddata.egg-info/SOURCES.txt +0 -0
  22. {boarddata-6.2.1 → boarddata-6.2.2}/boarddata.egg-info/dependency_links.txt +0 -0
  23. {boarddata-6.2.1 → boarddata-6.2.2}/boarddata.egg-info/requires.txt +0 -0
  24. {boarddata-6.2.1 → boarddata-6.2.2}/boarddata.egg-info/top_level.txt +0 -0
  25. {boarddata-6.2.1 → boarddata-6.2.2}/cache.py +0 -0
  26. {boarddata-6.2.1 → boarddata-6.2.2}/client.py +0 -0
  27. {boarddata-6.2.1 → boarddata-6.2.2}/errors.py +0 -0
  28. {boarddata-6.2.1 → boarddata-6.2.2}/py.typed +0 -0
  29. {boarddata-6.2.1 → boarddata-6.2.2}/setup.cfg +0 -0
  30. {boarddata-6.2.1 → boarddata-6.2.2}/tests/__init__.py +0 -0
  31. {boarddata-6.2.1 → boarddata-6.2.2}/tests/conftest.py +0 -0
  32. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_assemblies.py +0 -0
  33. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_auditors.py +0 -0
  34. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_base.py +0 -0
  35. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_build_payload.py +0 -0
  36. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_cache.py +0 -0
  37. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_comex.py +0 -0
  38. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_companies.py +0 -0
  39. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_config.py +0 -0
  40. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_criteria.py +0 -0
  41. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_directors.py +0 -0
  42. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_documents.py +0 -0
  43. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_esg.py +0 -0
  44. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_exports.py +0 -0
  45. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_indexes.py +0 -0
  46. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_sentinel.py +0 -0
  47. {boarddata-6.2.1 → boarddata-6.2.2}/tests/test_utilities.py +0 -0
  48. {boarddata-6.2.1 → boarddata-6.2.2}/types/__init__.py +0 -0
  49. {boarddata-6.2.1 → boarddata-6.2.2}/types/assemblies.py +0 -0
  50. {boarddata-6.2.1 → boarddata-6.2.2}/types/auditors.py +0 -0
  51. {boarddata-6.2.1 → boarddata-6.2.2}/types/comex.py +0 -0
  52. {boarddata-6.2.1 → boarddata-6.2.2}/types/companies.py +0 -0
  53. {boarddata-6.2.1 → boarddata-6.2.2}/types/core.py +0 -0
  54. {boarddata-6.2.1 → boarddata-6.2.2}/types/criteria.py +0 -0
  55. {boarddata-6.2.1 → boarddata-6.2.2}/types/directors.py +0 -0
  56. {boarddata-6.2.1 → boarddata-6.2.2}/types/documents.py +0 -0
  57. {boarddata-6.2.1 → boarddata-6.2.2}/types/esg.py +0 -0
  58. {boarddata-6.2.1 → boarddata-6.2.2}/types/indexes.py +0 -0
  59. {boarddata-6.2.1 → boarddata-6.2.2}/types/persons.py +0 -0
  60. {boarddata-6.2.1 → boarddata-6.2.2}/types/sentinel.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boarddata
3
- Version: 6.2.1
3
+ Version: 6.2.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.2.1"
9
+ __version__ = "6.2.2"
10
10
  __all__ = [
11
11
  "Base",
12
12
  "BoardDataClient",
@@ -19,6 +19,7 @@ class PersonMixin:
19
19
  *,
20
20
  search: str | None = None,
21
21
  similarity: str | None = None,
22
+ similarity_threshold: float | None = None,
22
23
  gender: str | None = None,
23
24
  nationality: str | None = None,
24
25
  page: int | None = None,
@@ -29,6 +30,9 @@ class PersonMixin:
29
30
  Args:
30
31
  search: Search by first/last name.
31
32
  similarity: Trigram similarity search (returns best matches by name).
33
+ similarity_threshold: Minimum trigram similarity (0.0–1.0). Only
34
+ applies when ``similarity`` is set. ``None`` uses the server
35
+ default (0.80).
32
36
  gender: Filter by gender code.
33
37
  nationality: Filter by nationality code(s), comma-separated.
34
38
  page: Page number (1-indexed).
@@ -44,6 +48,7 @@ class PersonMixin:
44
48
  "persons/",
45
49
  search=search,
46
50
  similarity=similarity,
51
+ similarity_threshold=similarity_threshold,
47
52
  gender=gender,
48
53
  nationality=nationality,
49
54
  page=page,
@@ -261,11 +266,18 @@ class PersonMixin:
261
266
  """
262
267
  return self._post("schools/", {"name": name, "country": country}) # type: ignore[attr-defined]
263
268
 
264
- def find_person_by_similarity(self, full_name: str) -> PersonSimilarityItem | None:
269
+ def find_person_by_similarity(
270
+ self,
271
+ full_name: str,
272
+ *,
273
+ similarity_threshold: float | None = None,
274
+ ) -> PersonSimilarityItem | None:
265
275
  """Find the best-matching person by trigram similarity.
266
276
 
267
277
  Args:
268
278
  full_name: Full name to search for (e.g. ``"Jean Dupont"``).
279
+ similarity_threshold: Minimum trigram similarity (0.0–1.0).
280
+ ``None`` uses the server default (0.80).
269
281
 
270
282
  Returns:
271
283
  PersonSimilarityItem for the best match, or ``None`` if no match found.
@@ -273,7 +285,7 @@ class PersonMixin:
273
285
  Raises:
274
286
  BoardDataError: On non-2xx API response.
275
287
  """
276
- resp = self.list_persons(similarity=full_name)
288
+ resp = self.list_persons(similarity=full_name, similarity_threshold=similarity_threshold)
277
289
  if isinstance(resp, dict) and "results" in resp:
278
290
  results = resp["results"]
279
291
  elif isinstance(resp, list):
@@ -295,6 +307,7 @@ class PersonMixin:
295
307
  schools: list[int] | None = None,
296
308
  professional_address: AddressPayload | None = None,
297
309
  field_sources: list[FieldSourcePayload] | None = None,
310
+ similarity_threshold: float | None = None,
298
311
  ) -> UpsertResult:
299
312
  """Find person by similarity, create or update.
300
313
 
@@ -309,6 +322,9 @@ class PersonMixin:
309
322
  schools: List of school IDs.
310
323
  professional_address: Professional address.
311
324
  field_sources: Document provenance for fields.
325
+ similarity_threshold: Minimum trigram similarity (0.0–1.0) for the
326
+ pre-write match step. ``None`` uses the server default (0.80).
327
+ Raise for strict ingestion; lower for loose dedup behavior.
312
328
 
313
329
  Returns:
314
330
  UpsertResult::
@@ -318,7 +334,7 @@ class PersonMixin:
318
334
  Raises:
319
335
  BoardDataError: On non-2xx API response.
320
336
  """
321
- person = self.find_person_by_similarity(person_name)
337
+ person = self.find_person_by_similarity(person_name, similarity_threshold=similarity_threshold)
322
338
  person_uid = person["id"] if person else None
323
339
 
324
340
  payload = self._build_payload( # type: ignore[attr-defined]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boarddata
3
- Version: 6.2.1
3
+ Version: 6.2.2
4
4
  Summary: Python SDK for the BoardData V2 REST API
5
5
  License: MIT
6
6
  Classifier: Development Status :: 4 - Beta
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "boarddata"
7
- version = "6.2.1"
7
+ version = "6.2.2"
8
8
  description = "Python SDK for the BoardData V2 REST API"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -28,6 +28,24 @@ class TestListPersons:
28
28
  _, kwargs = c._request.call_args
29
29
  assert kwargs["params"] == {"search": "Jean", "gender": "M", "page": 1}
30
30
 
31
+ def test_forwards_similarity_threshold(self):
32
+ c = make_client()
33
+ c._request.return_value = {"count": 0, "results": []}
34
+ c.list_persons(similarity="Jean Dupont", similarity_threshold=0.85)
35
+ _, kwargs = c._request.call_args
36
+ assert kwargs["params"] == {
37
+ "similarity": "Jean Dupont",
38
+ "similarity_threshold": 0.85,
39
+ }
40
+
41
+ def test_omits_similarity_threshold_when_none(self):
42
+ c = make_client()
43
+ c._request.return_value = {"count": 0, "results": []}
44
+ c.list_persons(similarity="Jean Dupont")
45
+ _, kwargs = c._request.call_args
46
+ assert kwargs["params"] == {"similarity": "Jean Dupont"}
47
+ assert "similarity_threshold" not in kwargs["params"]
48
+
31
49
 
32
50
  class TestFindPersonBySimilarity:
33
51
  def test_returns_best_match(self):
@@ -41,6 +59,16 @@ class TestFindPersonBySimilarity:
41
59
  c._request.return_value = {"count": 0, "results": []}
42
60
  assert c.find_person_by_similarity("Unknown") is None
43
61
 
62
+ def test_forwards_similarity_threshold(self):
63
+ c = make_client()
64
+ c._request.return_value = {"count": 0, "results": []}
65
+ c.find_person_by_similarity("Jean Dupont", similarity_threshold=0.9)
66
+ _, kwargs = c._request.call_args
67
+ assert kwargs["params"] == {
68
+ "similarity": "Jean Dupont",
69
+ "similarity_threshold": 0.9,
70
+ }
71
+
44
72
 
45
73
  class TestUpsertPerson:
46
74
  def test_creates_when_not_found(self):
@@ -62,3 +90,21 @@ class TestUpsertPerson:
62
90
  result = c.upsert_person("Jean Dupont", first_name="Jean", last_name="Dupont")
63
91
  assert result["action"] == "updated"
64
92
  assert result["id"] == "existing"
93
+
94
+ def test_forwards_similarity_threshold_to_lookup(self):
95
+ c = make_client()
96
+ c._request.side_effect = [
97
+ {"count": 0, "results": []}, # similarity search
98
+ {"id": "new-uuid", "first_name": "Jean", "last_name": "Dupont"}, # create
99
+ ]
100
+ c.upsert_person(
101
+ "Jean Dupont",
102
+ first_name="Jean",
103
+ last_name="Dupont",
104
+ similarity_threshold=0.95,
105
+ )
106
+ lookup_call = c._request.call_args_list[0]
107
+ assert lookup_call.kwargs["params"] == {
108
+ "similarity": "Jean Dupont",
109
+ "similarity_threshold": 0.95,
110
+ }
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