diff --git a/reference.md b/reference.md index a76be864..3dae59b7 100644 --- a/reference.md +++ b/reference.md @@ -1180,7 +1180,7 @@ client.negative_news.negative_news(
-**until:** `typing.Optional[dt.date]` — Date cutoff for article inclusion in `YYYY-MM-DD` format. If provided, only articles published before this date will be included in results. +**until:** `typing.Optional[dt.date]` — Date cutoff for article inclusion in `YYYY-MM-DD` format. If provided, only articles published after this date will be included in results.
@@ -2648,7 +2648,7 @@ client.ontology.get_source_types( ## ProjectEntityAttributes -
client.project_entity_attributes.update_project_entity_attribute(...) +
client.project_entity_attributes.get_project_entity_attributes(...)
@@ -2660,7 +2660,7 @@ client.ontology.get_source_types(
-Updates a specific attribute for a project entity. +Retrieves all attributes for a project entity.
@@ -2676,21 +2676,14 @@ Updates a specific attribute for a project entity. ```python from sayari import Sayari -from sayari.project_entity_attributes import UpdateProjectEntityAttributeRequest client = Sayari( client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET", ) -client.project_entity_attributes.update_project_entity_attribute( +client.project_entity_attributes.get_project_entity_attributes( project_id="V03eYM", project_entity_id="BG72YW", - attribute_id="xG8wYP", - request=UpdateProjectEntityAttributeRequest( - field="name", - value="updated name", - match_resolution=True, - ), ) ``` @@ -2723,22 +2716,6 @@ client.project_entity_attributes.update_project_entity_attribute(
-**attribute_id:** `str` - -
-
- -
-
- -**request:** `UpdateProjectEntityAttributeRequest` - -
-
- -
-
- **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -2751,8 +2728,7 @@ client.project_entity_attributes.update_project_entity_attribute(
-## ProjectEntitySupplyChainSnapshots -
client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshots(...) +
client.project_entity_attributes.create_project_entity_attribute(...)
@@ -2764,7 +2740,7 @@ client.project_entity_attributes.update_project_entity_attribute(
-Retrieves all supply chain snapshots for a project entity. +Creates a new attribute for a project entity.
@@ -2780,14 +2756,20 @@ Retrieves all supply chain snapshots for a project entity. ```python from sayari import Sayari +from sayari.project_entity_attributes import CreateProjectEntityAttributeRequest client = Sayari( client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET", ) -client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshots( +client.project_entity_attributes.create_project_entity_attribute( project_id="V03eYM", project_entity_id="BG72YW", + request=CreateProjectEntityAttributeRequest( + field="custom_phone", + value="+1-555-123-4567", + match_resolution=False, + ), ) ``` @@ -2820,6 +2802,14 @@ client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_sna
+**request:** `CreateProjectEntityAttributeRequest` + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -2832,7 +2822,7 @@ client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_sna
-
client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshot_by_id(...) +
client.project_entity_attributes.update_project_entity_attribute(...)
@@ -2844,7 +2834,7 @@ client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_sna
-Retrieves a specific supply chain snapshot by ID for a project entity. +Updates a specific attribute for a project entity.
@@ -2860,15 +2850,21 @@ Retrieves a specific supply chain snapshot by ID for a project entity. ```python from sayari import Sayari +from sayari.project_entity_attributes import UpdateProjectEntityAttributeRequest client = Sayari( client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET", ) -client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshot_by_id( +client.project_entity_attributes.update_project_entity_attribute( project_id="V03eYM", project_entity_id="BG72YW", - snapshot_id="sN4p2K", + attribute_id="xG8wYP", + request=UpdateProjectEntityAttributeRequest( + field="name", + value="updated name", + match_resolution=True, + ), ) ``` @@ -2901,7 +2897,15 @@ client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_sna
-**snapshot_id:** `str` +**attribute_id:** `str` + +
+
+ +
+
+ +**request:** `UpdateProjectEntityAttributeRequest`
@@ -2921,7 +2925,7 @@ client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_sna
-
client.project_entity_supply_chain_snapshots.create_project_entity_supply_chain_snapshot(...) +
client.project_entity_attributes.delete_project_entity_attribute(...)
@@ -2933,7 +2937,7 @@ client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_sna
-Creates a new supply chain snapshot for a project entity. +Deletes a specific attribute for a project entity.
@@ -2949,20 +2953,15 @@ Creates a new supply chain snapshot for a project entity. ```python from sayari import Sayari -from sayari.project_entity_supply_chain_snapshots import ( - CreateProjectEntitySupplyChainSnapshotRequest, -) client = Sayari( client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET", ) -client.project_entity_supply_chain_snapshots.create_project_entity_supply_chain_snapshot( - project_id="V03eYM", - project_entity_id="BG72YW", - request=CreateProjectEntitySupplyChainSnapshotRequest( - label="Q1 2024 Supply Chain Analysis", - ), +client.project_entity_attributes.delete_project_entity_attribute( + project_id="project_id", + project_entity_id="project_entity_id", + attribute_id="attribute_id", ) ``` @@ -2995,7 +2994,7 @@ client.project_entity_supply_chain_snapshots.create_project_entity_supply_chain_
-**request:** `CreateProjectEntitySupplyChainSnapshotRequest` +**attribute_id:** `str`
@@ -3015,7 +3014,8 @@ client.project_entity_supply_chain_snapshots.create_project_entity_supply_chain_
-
client.project_entity_supply_chain_snapshots.delete_project_entity_supply_chain_snapshot_by_id(...) +## ProjectEntitySupplyChainSnapshots +
client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshots(...)
@@ -3027,7 +3027,7 @@ client.project_entity_supply_chain_snapshots.create_project_entity_supply_chain_
-Deletes a specific supply chain snapshot by ID for a project entity. +Retrieves all supply chain snapshots for a project entity.
@@ -3048,10 +3048,9 @@ client = Sayari( client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET", ) -client.project_entity_supply_chain_snapshots.delete_project_entity_supply_chain_snapshot_by_id( - project_id="project_id", - project_entity_id="project_entity_id", - snapshot_id="snapshot_id", +client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshots( + project_id="V03eYM", + project_entity_id="BG72YW", ) ``` @@ -3084,14 +3083,6 @@ client.project_entity_supply_chain_snapshots.delete_project_entity_supply_chain_
-**snapshot_id:** `str` - -
-
- -
-
- **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -3104,8 +3095,7 @@ client.project_entity_supply_chain_snapshots.delete_project_entity_supply_chain_
-## ProjectEntity -
client.project_entity.create_project_entity(...) +
client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshot_by_id(...)
@@ -3117,7 +3107,7 @@ client.project_entity_supply_chain_snapshots.delete_project_entity_supply_chain_
-The resolution endpoints allow users to search for matching entities against a provided list of attributes. The endpoint is similar to the search endpoint, except it's tuned to only return the best match so the client doesn't need to do as much or any post-processing work to filter down results. +Retrieves a specific supply chain snapshot by ID for a project entity.
@@ -3133,21 +3123,15 @@ The resolution endpoints allow users to search for matching entities against a p ```python from sayari import Sayari -from sayari.project_entity import CreateResolvedProjectEntityRequest client = Sayari( client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET", ) -client.project_entity.create_project_entity( - project_id="0n4473", - request=CreateResolvedProjectEntityRequest( - name=["Marvel Garment"], - country=["KHM"], - address=[ - "Beung Thom 3 Village, Sangkat Beung Thom, Posenchey, Phnom Penh" - ], - ), +client.project_entity_supply_chain_snapshots.get_project_entity_supply_chain_snapshot_by_id( + project_id="V03eYM", + project_entity_id="BG72YW", + snapshot_id="sN4p2K", ) ``` @@ -3172,7 +3156,15 @@ client.project_entity.create_project_entity(
-**request:** `CreateResolvedProjectEntityRequest` +**project_entity_id:** `str` + +
+
+ +
+
+ +**snapshot_id:** `str`
@@ -3192,7 +3184,7 @@ client.project_entity.create_project_entity(
-
client.project_entity.get_project_entities(...) +
client.project_entity_supply_chain_snapshots.create_project_entity_supply_chain_snapshot(...)
@@ -3204,7 +3196,7 @@ client.project_entity.create_project_entity(
-Retrieves a list of entities for a specific project with pagination support. +Creates a new supply chain snapshot for a project entity.
@@ -3220,13 +3212,20 @@ Retrieves a list of entities for a specific project with pagination support. ```python from sayari import Sayari +from sayari.project_entity_supply_chain_snapshots import ( + CreateProjectEntitySupplyChainSnapshotRequest, +) client = Sayari( client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET", ) -client.project_entity.get_project_entities( - project_id="YVB88Y", +client.project_entity_supply_chain_snapshots.create_project_entity_supply_chain_snapshot( + project_id="V03eYM", + project_entity_id="BG72YW", + request=CreateProjectEntitySupplyChainSnapshotRequest( + label="Q1 2024 Supply Chain Analysis", + ), ) ``` @@ -3251,7 +3250,7 @@ client.project_entity.get_project_entities(
-**entity_id:** `typing.Optional[typing.Sequence[str]]` — Filter by entity IDs +**project_entity_id:** `str`
@@ -3259,7 +3258,7 @@ client.project_entity.get_project_entities(
-**uploads:** `typing.Optional[typing.Sequence[str]]` — Filter by upload IDs +**request:** `CreateProjectEntitySupplyChainSnapshotRequest`
@@ -3267,63 +3266,72 @@ client.project_entity.get_project_entities(
-**case_status:** `typing.Optional[typing.Sequence[CaseStatus]]` — Filter by case status +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+ +
-
-
-**tags:** `typing.Optional[typing.Sequence[str]]` — Filter by tag IDs -
+
+
client.project_entity_supply_chain_snapshots.delete_project_entity_supply_chain_snapshot_by_id(...)
-**match_count:** `typing.Optional[MatchCount]` — Filter by match count - -
-
+#### 📝 Description
-**match_strength:** `typing.Optional[typing.Sequence[MatchStrengthEnum]]` — Filter by match strength - -
-
-
-**entity_types:** `typing.Optional[typing.Sequence[str]]` — Filter by entity types - +Deletes a specific supply chain snapshot by ID for a project entity. +
+
+#### 🔌 Usage +
-**geo_facets:** `typing.Optional[bool]` — Include geo facets - -
-
-
-**exact_match:** `typing.Optional[bool]` — Use exact matching - +```python +from sayari import Sayari + +client = Sayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", +) +client.project_entity_supply_chain_snapshots.delete_project_entity_supply_chain_snapshot_by_id( + project_id="project_id", + project_entity_id="project_entity_id", + snapshot_id="snapshot_id", +) + +```
+ + + +#### ⚙️ Parameters
-**hs_codes:** `typing.Optional[typing.Sequence[str]]` — Filter by HS codes +
+
+ +**project_id:** `str`
@@ -3331,7 +3339,7 @@ client.project_entity.get_project_entities(
-**received_hs_codes:** `typing.Optional[typing.Sequence[str]]` — Filter by received HS codes +**project_entity_id:** `str`
@@ -3339,7 +3347,7 @@ client.project_entity.get_project_entities(
-**shipped_hs_codes:** `typing.Optional[typing.Sequence[str]]` — Filter by shipped HS codes +**snapshot_id:** `str`
@@ -3347,47 +3355,79 @@ client.project_entity.get_project_entities(
-**upstream_product:** `typing.Optional[typing.Sequence[str]]` — Filter by upstream product +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+
+
-
-
-**limit:** `typing.Optional[int]` — Maximum number of results to return -
+
+## ProjectEntity +
client.project_entity.create_project_entity(...)
-**token:** `typing.Optional[str]` — Pagination token - -
-
+#### 📝 Description
-**sort:** `typing.Optional[typing.Sequence[str]]` — Sort fields - +
+
+ +The resolution endpoints allow users to search for matching entities against a provided list of attributes. The endpoint is similar to the search endpoint, except it's tuned to only return the best match so the client doesn't need to do as much or any post-processing work to filter down results. +
+
+#### 🔌 Usage +
-**aggregations:** `typing.Optional[typing.Sequence[str]]` — Fields to aggregate - +
+
+ +```python +from sayari import Sayari +from sayari.project_entity import CreateResolvedProjectEntityRequest + +client = Sayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", +) +client.project_entity.create_project_entity( + project_id="0n4473", + request=CreateResolvedProjectEntityRequest( + name=["Marvel Garment"], + country=["KHM"], + address=[ + "Beung Thom 3 Village, Sangkat Beung Thom, Posenchey, Phnom Penh" + ], + ), +) + +``` +
+
+#### ⚙️ Parameters + +
+
+
-**num_aggregation_buckets:** `typing.Optional[int]` — Number of aggregation buckets +**project_id:** `str`
@@ -3395,7 +3435,7 @@ client.project_entity.get_project_entities(
-**risk:** `typing.Optional[typing.Sequence[Risk]]` — List of risk factors to filter by +**request:** `CreateResolvedProjectEntityRequest`
@@ -3403,7 +3443,7 @@ client.project_entity.get_project_entities(
-**risk_category:** `typing.Optional[typing.Sequence[RiskCategory]]` — List of risk categories to filter by. An entity matches if it has any risk factor belonging to one of the specified categories +**enable_llm_clean:** `typing.Optional[bool]` — Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning.
@@ -3423,7 +3463,7 @@ client.project_entity.get_project_entities(
-
client.project_entity.get_project_entity(...) +
client.project_entity.get_project_entities(...)
@@ -3435,7 +3475,19 @@ client.project_entity.get_project_entities(
-Retrieves a specific entity in a project. +Retrieves a list of entities for a specific project with pagination support. + +**Response Formats:** +- **JSON** (default): Returns structured data with nested objects +- **CSV**: Returns tabular data with dynamic columns for attributes and risk categories + +**CSV Format:** +The CSV response includes dynamic columns based on the data: +- `attribute_{field_name}`: Dynamic columns for each attribute field found in the data +- `risk_category_{category_id}`: Dynamic columns for each risk category found in the data +- Standard columns: project_id, project_entity_id, label, project_entity_url, upload_ids, strength, countries, tags, case_status, created_at, match_count, upstream_products, upstream_risk_factors, upstream_countries + +Use the `Accept: text/csv` header to request CSV format.
@@ -3451,14 +3503,43 @@ Retrieves a specific entity in a project. ```python from sayari import Sayari +from sayari.project_entity import ( + ProjectEntitiesExactFilter, + ProjectEntitiesFilter, + ProjectEntitiesFuzzyFilter, +) client = Sayari( client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET", ) -client.project_entity.get_project_entity( - project_id="project_id", - project_entity_id="project_entity_id", +client.project_entity.get_project_entities( + project_id="YVB88Y", + limit=25, + filter=ProjectEntitiesFilter( + risk_category=["sanctions", "export_controls"], + upstream_product=["8536", "8544"], + shipment_country=["CHN", "VNM"], + tier_1_shipment_country=["CHN"], + city=ProjectEntitiesFuzzyFilter( + fuzzy=["moscow", "beijing"], + ), + identifier=ProjectEntitiesFuzzyFilter( + fuzzy=["253400V1H6ART1UQ0N98"], + ), + source=ProjectEntitiesExactFilter( + exact=[ + "92edb8fe6615498f6e3e7b0e220f74e6", + "c10d482320f207d92aa814519c3bd686", + ], + ), + status=["active"], + bounds="55.680357237879136|-71.53607290158526|41.10876347746233|-40.963927098414736", + match_entity_id=["dy-rh2g0QtzUN_jC_e9S_A"], + entity_type=["company"], + upload=["upload_123"], + match_count="one", + ), ) ``` @@ -3483,7 +3564,7 @@ client.project_entity.get_project_entity(
-**project_entity_id:** `str` +**next:** `typing.Optional[str]` — The pagination token for the next page of projects.
@@ -3491,7 +3572,7 @@ client.project_entity.get_project_entity(
-**entity_id:** `typing.Optional[typing.Sequence[str]]` — Filter by entity IDs +**prev:** `typing.Optional[str]` — The pagination token for the previous page of projects.
@@ -3499,7 +3580,7 @@ client.project_entity.get_project_entity(
-**uploads:** `typing.Optional[typing.Sequence[str]]` — Filter by upload IDs +**limit:** `typing.Optional[int]` — Limit total values returned for projects. Defaults to 100. Max 100.
@@ -3507,7 +3588,7 @@ client.project_entity.get_project_entity(
-**case_status:** `typing.Optional[typing.Sequence[CaseStatus]]` — Filter by case status +**filter:** `typing.Optional[ProjectEntitiesFilter]` — Filter the project entities. Supports both dot notation (e.g., 'filter.attribute.name') and bracket notation (e.g., 'filter[attribute][name]') for nested field filtering.
@@ -3515,39 +3596,71 @@ client.project_entity.get_project_entity(
-**tags:** `typing.Optional[typing.Sequence[str]]` — Filter by tag IDs +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
+ +
+ + + + +
+
client.project_entity.get_project_entity(...)
-**match_count:** `typing.Optional[MatchCount]` — Filter by match count - +#### 📝 Description + +
+
+ +
+
+ +Retrieves a specific entity in a project. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from sayari import Sayari + +client = Sayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", +) +client.project_entity.get_project_entity( + project_id="project_id", + project_entity_id="project_entity_id", +) + +```
- -
-
- -**match_strength:** `typing.Optional[typing.Sequence[MatchStrengthEnum]]` — Filter by match strength -
+#### ⚙️ Parameters +
-**entity_types:** `typing.Optional[typing.Sequence[str]]` — Filter by entity types - -
-
-
-**risk:** `typing.Optional[typing.Sequence[Risk]]` — List of risk factors to filter by +**project_id:** `str`
@@ -3555,7 +3668,7 @@ client.project_entity.get_project_entity(
-**risk_category:** `typing.Optional[typing.Sequence[RiskCategory]]` — List of risk categories to filter by. An entity matches if it has any risk factor belonging to one of the specified categories +**project_entity_id:** `str`
@@ -4147,6 +4260,105 @@ client.project_entity.project_entity_supply_chain(
+
+
+
+ +
client.project_entity.get_project_entity_risk_summary(...) +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieves a risk summary for a specific project entity, including risk factors with network paths and risk intelligence data. + +**Response includes:** +- Risk factors with their levels (elevated, high, critical) +- Network paths showing relationships between entities +- Risk intelligence scores and metadata +- Risk categories and source entity information +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from sayari import Sayari +from sayari.project_entity import ProjectEntityRiskSummaryFilters + +client = Sayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", +) +client.project_entity.get_project_entity_risk_summary( + project_id="YVB88Y", + project_entity_id="52z4Wa", + filter=ProjectEntityRiskSummaryFilters( + risk_factor=["sanctioned", "regulatory_action"], + risk_category=["sanctions", "export_controls"], + ), +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**project_id:** `str` + +
+
+ +
+
+ +**project_entity_id:** `str` + +
+
+ +
+
+ +**filter:** `ProjectEntityRiskSummaryFilters` — Filter risk factors by risk factor IDs and risk categories + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ +
@@ -4876,6 +5088,14 @@ client.resolution.resolution(
+**enable_llm_clean:** `typing.Optional[bool]` — Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning. + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -4924,9 +5144,14 @@ client = Sayari( ) client.resolution.resolution_post( limit=1, + enable_llm_clean=False, request=ResolutionBody( - name=["Oleg Deripaska"], - country=["RUS"], + name=["Chongqing Jingyou Zhicai New Materials Co."], + address=[ + "4-2, Building B2, No. 5, Middle Mount Huangshan Avenue, Gaoxinyuan, Dazhulin Street, Liangjiang New District, Chongqing,Chongqing,continuation,CN" + ], + country=["CHN"], + enable_llm_clean=False, ), ) @@ -4968,6 +5193,14 @@ client.resolution.resolution_post(
+**enable_llm_clean:** `typing.Optional[bool]` — Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning. + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -5118,11 +5351,17 @@ client = Sayari( client.resolution.resolution_upload( project_id="V03eYM", request=ResolutionUploadBody( - filename="vbeck.json", + filename="testblah.csv", + enable_llm_clean=False, data=[ ResolutionBody( - name=["victoria beckham limited"], - tags=["spice girls"], + name=[ + "Chongqing Jingyou Zhicai New Materials Co. ABC XYZ Blah Blah Nonsense 1 489 929 49492 1839 1848" + ], + address=[ + "4-2, Building B2, No. 5, Middle Mount Huangshan Avenue, Gaoxinyuan, Dazhulin Street, Liangjiang New District, Chongqing,Chongqing,continuation,CN" + ], + country=["CHN"], ) ], ), @@ -5789,157 +6028,6 @@ client.search.search_record_get(
- -
-
- -## Source -
client.source.list_sources(...) -
-
- -#### 📝 Description - -
-
- -
-
- -This endpoint is deprecated. Use /v1/ontology/sources instead. Returns metadata for all sources that Sayari collects data from -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from sayari import Sayari - -client = Sayari( - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", -) -client.source.list_sources( - limit=2, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**limit:** `typing.Optional[int]` — A limit on the number of objects to be returned with a range between 1 and 100. Defaults to 100. - -
-
- -
-
- -**offset:** `typing.Optional[int]` — Number of results to skip before returning response. Defaults to 0. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.source.get_source(...) -
-
- -#### 📝 Description - -
-
- -
-
- -This endpoint is deprecated. Use /v1/ontology/sources instead. Returns metadata for a source that Sayari collects data from -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from sayari import Sayari - -client = Sayari( - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", -) -client.source.get_source( - id="f4396e4b8a41d1fd9f09ea94d2ebedb9", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` — The unique identifier for a source in the database - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- -
@@ -6212,7 +6300,7 @@ client.trade.search_shipments( departure_country=["DEU"], arrival_country=["RUS"], hs_code=["854231"], - arrival_date=["2024-01 TO 2024-10"], + arrival_date="2024-01|2024-10", ), ) @@ -6230,7 +6318,7 @@ client.trade.search_shipments(
-**limit:** `typing.Optional[int]` — A limit on the number of objects to be returned with a range between 1 and 10000. Defaults to 100. +**limit:** `typing.Optional[int]` — A limit on the number of objects to be returned with a range between 1 and 3000. Defaults to 100.
@@ -6322,7 +6410,7 @@ client.trade.search_suppliers( departure_country=["DEU"], arrival_country=["RUS"], hs_code=["854231"], - arrival_date=["2024-01 TO 2024-10"], + arrival_date="2024-01|2024-10", ), ) @@ -6340,7 +6428,7 @@ client.trade.search_suppliers(
-**limit:** `typing.Optional[int]` — A limit on the number of objects to be returned with a range between 1 and 10000. Defaults to 100. +**limit:** `typing.Optional[int]` — A limit on the number of objects to be returned with a range between 1 and 3000. Defaults to 100.
@@ -6432,7 +6520,7 @@ client.trade.search_buyers( departure_country=["DEU"], arrival_country=["RUS"], hs_code=["854231"], - arrival_date=["2024-01 TO 2024-10"], + arrival_date="2024-01|2024-10", ), ) @@ -6450,7 +6538,7 @@ client.trade.search_buyers(
-**limit:** `typing.Optional[int]` — A limit on the number of objects to be returned with a range between 1 and 10000. Defaults to 100. +**limit:** `typing.Optional[int]` — A limit on the number of objects to be returned with a range between 1 and 3000. Defaults to 100.
diff --git a/src/sayari/__init__.py b/src/sayari/__init__.py index 95532d56..216b14d2 100644 --- a/src/sayari/__init__.py +++ b/src/sayari/__init__.py @@ -21,13 +21,12 @@ search, shared_errors, shared_types, - source, supply_chain, trade, traversal, ) from .attributes import AddAttribute, AttributeProperties, AttributeResponse, AttributeResponseData, UpdateAttribute -from .auth import AuthResponse +from .auth import Audience, AuthResponse from .base_types import CountQualifier, CustomFieldValue, PaginatedResponse, QualifiedCount from .client import AsyncSayari, Sayari from .entity import EntitySummaryResponse, GetEntityResponse @@ -202,7 +201,6 @@ ProjectCounts, ProjectEntitiesAggs, ProjectEntitiesAggsDefinition, - ProjectEntitiesFilter, ProjectEntity, ProjectEntityUpstream, ProjectShareOnCreate, @@ -225,26 +223,34 @@ AttributeValues, AttributesResponse, BusinessPurpose, - CaseStatus, CountType, CreateResolvedProjectEntityRequest, FacetBucket, FacetsResponse, + FieldMatchQuality, GroupedAttribute, GroupedAttributeValue, Location, - MatchCount, MatchProfileEnum, - MatchStrengthEnum, - MatchedAttributes, ProductBucket, ProductCount, ProductMapping, + ProjectEntitiesCustomFieldFilter, + ProjectEntitiesExactFilter, + ProjectEntitiesFilter, + ProjectEntitiesFuzzyFilter, ProjectEntitiesResponse, ProjectEntityExistsResponseData, ProjectEntityIdResponse, + ProjectEntityMatchExplanation, ProjectEntityMatchResponse, ProjectEntityResponse, + ProjectEntityRiskSummaryData, + ProjectEntityRiskSummaryFilters, + ProjectEntityRiskSummaryNetworkPath, + ProjectEntityRiskSummaryResponse, + ProjectEntityRiskSummaryResponseFilters, + ProjectEntityRiskSummaryRiskFactor, ProjectEntitySupplyChainSummaryResponse, ProjectEntitySupplyChainSummaryResponseData, ProjectEntitySupplyChainUpstream, @@ -254,6 +260,7 @@ ResolutionProfile, RiskCategoriesSummary, SaveProjectEntityBody, + ShareInformation, SingleProjectEntityResponse, SourceField, SpecialFacetBucket, @@ -268,6 +275,12 @@ UpstreamInfo, ) from .project_entity_attributes import ( + CreateProjectEntityAttributeRequest, + CreateProjectEntityAttributeResponse, + CreateProjectEntityAttributeResponseData, + ProjectEntityAttribute, + ProjectEntityAttributeValue, + ProjectEntityAttributesResponse, UpdateProjectEntityAttributeRequest, UpdateProjectEntityAttributeResponse, UpdateProjectEntityAttributeResponseData, @@ -327,8 +340,11 @@ RateLimitResponse, Unauthorized, UnauthorizedResponse, + UnprocessableContent, + UnprocessableContentResponse, ) from .shared_types import ( + CaseStatus, ClientName, CompanyType, Coordinate, @@ -343,6 +359,8 @@ EntitySummary, EntityTranslatedLabel, Identifier, + MatchCount, + MatchStrengthEnum, PossiblySameAs, PossiblySameAsData, PossiblySameAsMatch, @@ -365,7 +383,6 @@ SourceCountInfo, Status, ) -from .source import GetSourceResponse, ListSourcesResponse, Source from .supply_chain import ( TradeTraversalComponent, TradeTraversalData, @@ -427,6 +444,7 @@ "AttributeValues", "Attributes", "AttributesResponse", + "Audience", "AuthResponse", "BadGateway", "BadGatewayResponse", @@ -463,6 +481,9 @@ "CountryData", "CountryInfo", "CountryProperties", + "CreateProjectEntityAttributeRequest", + "CreateProjectEntityAttributeResponse", + "CreateProjectEntityAttributeResponseData", "CreateProjectEntitySupplyChainSnapshotRequest", "CreateProjectEntitySupplyChainSnapshotResponse", "CreateProjectRequest", @@ -493,6 +514,7 @@ "EventInfo", "FacetBucket", "FacetsResponse", + "FieldMatchQuality", "FilterList", "FinanceType", "FinancesData", @@ -528,7 +550,6 @@ "GetProjectEntitiesResponse", "GetProjectsResponse", "GetRecordResponse", - "GetSourceResponse", "GroupedAttribute", "GroupedAttributeValue", "HistoryInfo", @@ -544,7 +565,6 @@ "InternalServerError", "InternalServerErrorResponse", "Language", - "ListSourcesResponse", "Location", "MatchCount", "MatchExplanation", @@ -552,7 +572,6 @@ "MatchQuality", "MatchStrength", "MatchStrengthEnum", - "MatchedAttributes", "MeasurementData", "MeasurementInfo", "MeasurementProperties", @@ -625,13 +644,26 @@ "ProjectCounts", "ProjectEntitiesAggs", "ProjectEntitiesAggsDefinition", + "ProjectEntitiesCustomFieldFilter", + "ProjectEntitiesExactFilter", "ProjectEntitiesFilter", + "ProjectEntitiesFuzzyFilter", "ProjectEntitiesResponse", "ProjectEntity", + "ProjectEntityAttribute", + "ProjectEntityAttributeValue", + "ProjectEntityAttributesResponse", "ProjectEntityExistsResponseData", "ProjectEntityIdResponse", + "ProjectEntityMatchExplanation", "ProjectEntityMatchResponse", "ProjectEntityResponse", + "ProjectEntityRiskSummaryData", + "ProjectEntityRiskSummaryFilters", + "ProjectEntityRiskSummaryNetworkPath", + "ProjectEntityRiskSummaryResponse", + "ProjectEntityRiskSummaryResponseFilters", + "ProjectEntityRiskSummaryRiskFactor", "ProjectEntitySupplyChainSnapshotByIdResponse", "ProjectEntitySupplyChainSnapshotData", "ProjectEntitySupplyChainSnapshotDetailData", @@ -699,6 +731,7 @@ "SayariEnvironment", "SearchField", "SearchResults", + "ShareInformation", "SharesData", "SharesInfo", "SharesProperties", @@ -714,7 +747,6 @@ "ShortestPathResponse", "SingleProjectEntityResponse", "SortField", - "Source", "SourceCountInfo", "SourceField", "SourceId", @@ -760,6 +792,8 @@ "Unauthorized", "UnauthorizedResponse", "Unit", + "UnprocessableContent", + "UnprocessableContentResponse", "UpdateAttribute", "UpdateEntityTagsResponse", "UpdateProjectEntityAttributeRequest", @@ -799,7 +833,6 @@ "search", "shared_errors", "shared_types", - "source", "supply_chain", "trade", "traversal", diff --git a/src/sayari/auth/__init__.py b/src/sayari/auth/__init__.py index e05b0511..8efaff72 100644 --- a/src/sayari/auth/__init__.py +++ b/src/sayari/auth/__init__.py @@ -1,5 +1,5 @@ # This file was auto-generated by Fern from our API Definition. -from .types import AuthResponse +from .types import Audience, AuthResponse -__all__ = ["AuthResponse"] +__all__ = ["Audience", "AuthResponse"] diff --git a/src/sayari/auth/types/__init__.py b/src/sayari/auth/types/__init__.py index 299ab463..6e06f06e 100644 --- a/src/sayari/auth/types/__init__.py +++ b/src/sayari/auth/types/__init__.py @@ -1,5 +1,6 @@ # This file was auto-generated by Fern from our API Definition. +from .audience import Audience from .auth_response import AuthResponse -__all__ = ["AuthResponse"] +__all__ = ["Audience", "AuthResponse"] diff --git a/src/sayari/auth/types/audience.py b/src/sayari/auth/types/audience.py new file mode 100644 index 00000000..9ce8d76e --- /dev/null +++ b/src/sayari/auth/types/audience.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +Audience = typing.Union[typing.Literal["sayari.com", "uk.sayari.com"], typing.Any] diff --git a/src/sayari/base_client.py b/src/sayari/base_client.py index f4f0ab9a..81965b11 100644 --- a/src/sayari/base_client.py +++ b/src/sayari/base_client.py @@ -21,7 +21,6 @@ from .resolution.client import ResolutionClient from .resource.client import ResourceClient from .search.client import SearchClient -from .source.client import SourceClient from .supply_chain.client import SupplyChainClient from .trade.client import TradeClient from .traversal.client import TraversalClient @@ -42,7 +41,6 @@ from .resolution.client import AsyncResolutionClient from .resource.client import AsyncResourceClient from .search.client import AsyncSearchClient -from .source.client import AsyncSourceClient from .supply_chain.client import AsyncSupplyChainClient from .trade.client import AsyncTradeClient from .traversal.client import AsyncTraversalClient @@ -140,7 +138,6 @@ def __init__( self.resolution = ResolutionClient(client_wrapper=self._client_wrapper) self.resource = ResourceClient(client_wrapper=self._client_wrapper) self.search = SearchClient(client_wrapper=self._client_wrapper) - self.source = SourceClient(client_wrapper=self._client_wrapper) self.supply_chain = SupplyChainClient(client_wrapper=self._client_wrapper) self.trade = TradeClient(client_wrapper=self._client_wrapper) self.traversal = TraversalClient(client_wrapper=self._client_wrapper) @@ -238,7 +235,6 @@ def __init__( self.resolution = AsyncResolutionClient(client_wrapper=self._client_wrapper) self.resource = AsyncResourceClient(client_wrapper=self._client_wrapper) self.search = AsyncSearchClient(client_wrapper=self._client_wrapper) - self.source = AsyncSourceClient(client_wrapper=self._client_wrapper) self.supply_chain = AsyncSupplyChainClient(client_wrapper=self._client_wrapper) self.trade = AsyncTradeClient(client_wrapper=self._client_wrapper) self.traversal = AsyncTraversalClient(client_wrapper=self._client_wrapper) diff --git a/src/sayari/environment.py b/src/sayari/environment.py index c8450a37..88b8bbe2 100644 --- a/src/sayari/environment.py +++ b/src/sayari/environment.py @@ -13,3 +13,8 @@ class SayariEnvironment(enum.Enum): """ Sayari development - utilized for internal testing before promotion to production """ + + PRODUCTION_UK = "https://api.uk.sayari.com" + """ + Sayari production - UK environment + """ diff --git a/src/sayari/negative_news/client.py b/src/sayari/negative_news/client.py index 34611058..b4bc9d9a 100644 --- a/src/sayari/negative_news/client.py +++ b/src/sayari/negative_news/client.py @@ -49,7 +49,7 @@ def negative_news( Risk category filter for targeted screening. Each topic represents a distinct risk domain (e.g., `environmental` for environmental violations, `financial` for financial misconduct). until : typing.Optional[dt.date] - Date cutoff for article inclusion in `YYYY-MM-DD` format. If provided, only articles published before this date will be included in results. + Date cutoff for article inclusion in `YYYY-MM-DD` format. If provided, only articles published after this date will be included in results. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -70,7 +70,7 @@ def negative_news( ) client.negative_news.negative_news( name="Gazprom", - topic="sanctions", + topic="sanctions_and_regulatory", until=datetime.date.fromisoformat( "2024-10-01", ), @@ -178,7 +178,7 @@ async def negative_news( Risk category filter for targeted screening. Each topic represents a distinct risk domain (e.g., `environmental` for environmental violations, `financial` for financial misconduct). until : typing.Optional[dt.date] - Date cutoff for article inclusion in `YYYY-MM-DD` format. If provided, only articles published before this date will be included in results. + Date cutoff for article inclusion in `YYYY-MM-DD` format. If provided, only articles published after this date will be included in results. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -203,7 +203,7 @@ async def negative_news( async def main() -> None: await client.negative_news.negative_news( name="Gazprom", - topic="sanctions", + topic="sanctions_and_regulatory", until=datetime.date.fromisoformat( "2024-10-01", ), diff --git a/src/sayari/negative_news/types/topics.py b/src/sayari/negative_news/types/topics.py index 2d131562..4df08b18 100644 --- a/src/sayari/negative_news/types/topics.py +++ b/src/sayari/negative_news/types/topics.py @@ -4,20 +4,17 @@ Topics = typing.Union[ typing.Literal[ - "basic", - "environmental", - "social", + "overview", + "environmental_and_social", "cybersecurity", "disruption", "criminal", "reputational", "financial", - "regulatory", + "sanctions_and_regulatory", "legal", - "misconduct", + "political", "terrorism", - "sanctions", - "all", ], typing.Any, ] diff --git a/src/sayari/project/__init__.py b/src/sayari/project/__init__.py index b9acab6e..8570e7de 100644 --- a/src/sayari/project/__init__.py +++ b/src/sayari/project/__init__.py @@ -14,7 +14,6 @@ ProjectCounts, ProjectEntitiesAggs, ProjectEntitiesAggsDefinition, - ProjectEntitiesFilter, ProjectEntity, ProjectEntityUpstream, ProjectShareOnCreate, @@ -45,7 +44,6 @@ "ProjectCounts", "ProjectEntitiesAggs", "ProjectEntitiesAggsDefinition", - "ProjectEntitiesFilter", "ProjectEntity", "ProjectEntityUpstream", "ProjectShareOnCreate", diff --git a/src/sayari/project/types/__init__.py b/src/sayari/project/types/__init__.py index 069aeaa3..51e53adf 100644 --- a/src/sayari/project/types/__init__.py +++ b/src/sayari/project/types/__init__.py @@ -13,7 +13,6 @@ from .project_counts import ProjectCounts from .project_entities_aggs import ProjectEntitiesAggs from .project_entities_aggs_definition import ProjectEntitiesAggsDefinition -from .project_entities_filter import ProjectEntitiesFilter from .project_entity import ProjectEntity from .project_entity_upstream import ProjectEntityUpstream from .project_share_on_create import ProjectShareOnCreate @@ -43,7 +42,6 @@ "ProjectCounts", "ProjectEntitiesAggs", "ProjectEntitiesAggsDefinition", - "ProjectEntitiesFilter", "ProjectEntity", "ProjectEntityUpstream", "ProjectShareOnCreate", diff --git a/src/sayari/project_entity/__init__.py b/src/sayari/project_entity/__init__.py index add92aca..0e652ac8 100644 --- a/src/sayari/project_entity/__init__.py +++ b/src/sayari/project_entity/__init__.py @@ -7,26 +7,34 @@ AttributeValues, AttributesResponse, BusinessPurpose, - CaseStatus, CountType, CreateResolvedProjectEntityRequest, FacetBucket, FacetsResponse, + FieldMatchQuality, GroupedAttribute, GroupedAttributeValue, Location, - MatchCount, MatchProfileEnum, - MatchStrengthEnum, - MatchedAttributes, ProductBucket, ProductCount, ProductMapping, + ProjectEntitiesCustomFieldFilter, + ProjectEntitiesExactFilter, + ProjectEntitiesFilter, + ProjectEntitiesFuzzyFilter, ProjectEntitiesResponse, ProjectEntityExistsResponseData, ProjectEntityIdResponse, + ProjectEntityMatchExplanation, ProjectEntityMatchResponse, ProjectEntityResponse, + ProjectEntityRiskSummaryData, + ProjectEntityRiskSummaryFilters, + ProjectEntityRiskSummaryNetworkPath, + ProjectEntityRiskSummaryResponse, + ProjectEntityRiskSummaryResponseFilters, + ProjectEntityRiskSummaryRiskFactor, ProjectEntitySupplyChainSummaryResponse, ProjectEntitySupplyChainSummaryResponseData, ProjectEntitySupplyChainUpstream, @@ -36,6 +44,7 @@ ResolutionProfile, RiskCategoriesSummary, SaveProjectEntityBody, + ShareInformation, SingleProjectEntityResponse, SourceField, SpecialFacetBucket, @@ -57,26 +66,34 @@ "AttributeValues", "AttributesResponse", "BusinessPurpose", - "CaseStatus", "CountType", "CreateResolvedProjectEntityRequest", "FacetBucket", "FacetsResponse", + "FieldMatchQuality", "GroupedAttribute", "GroupedAttributeValue", "Location", - "MatchCount", "MatchProfileEnum", - "MatchStrengthEnum", - "MatchedAttributes", "ProductBucket", "ProductCount", "ProductMapping", + "ProjectEntitiesCustomFieldFilter", + "ProjectEntitiesExactFilter", + "ProjectEntitiesFilter", + "ProjectEntitiesFuzzyFilter", "ProjectEntitiesResponse", "ProjectEntityExistsResponseData", "ProjectEntityIdResponse", + "ProjectEntityMatchExplanation", "ProjectEntityMatchResponse", "ProjectEntityResponse", + "ProjectEntityRiskSummaryData", + "ProjectEntityRiskSummaryFilters", + "ProjectEntityRiskSummaryNetworkPath", + "ProjectEntityRiskSummaryResponse", + "ProjectEntityRiskSummaryResponseFilters", + "ProjectEntityRiskSummaryRiskFactor", "ProjectEntitySupplyChainSummaryResponse", "ProjectEntitySupplyChainSummaryResponseData", "ProjectEntitySupplyChainUpstream", @@ -86,6 +103,7 @@ "ResolutionProfile", "RiskCategoriesSummary", "SaveProjectEntityBody", + "ShareInformation", "SingleProjectEntityResponse", "SourceField", "SpecialFacetBucket", diff --git a/src/sayari/project_entity/client.py b/src/sayari/project_entity/client.py index 83281508..dbb0f37b 100644 --- a/src/sayari/project_entity/client.py +++ b/src/sayari/project_entity/client.py @@ -22,17 +22,16 @@ from ..shared_errors.types.internal_server_error_response import InternalServerErrorResponse from json.decoder import JSONDecodeError from ..core.api_error import ApiError -from .types.case_status import CaseStatus -from .types.match_count import MatchCount -from .types.match_strength_enum import MatchStrengthEnum -from ..generated_types.types.risk import Risk -from ..generated_types.types.risk_category import RiskCategory +from .types.project_entities_filter import ProjectEntitiesFilter from .types.project_entities_response import ProjectEntitiesResponse from .types.resolution_attributes import ResolutionAttributes from .types.project_entity_id_response import ProjectEntityIdResponse from .types.save_project_entity_body import SaveProjectEntityBody +from ..generated_types.types.risk import Risk from ..generated_types.types.country import Country from ..supply_chain.types.upstream_trade_traversal_response import UpstreamTradeTraversalResponse +from .types.project_entity_risk_summary_filters import ProjectEntityRiskSummaryFilters +from .types.project_entity_risk_summary_response import ProjectEntityRiskSummaryResponse from .types.project_entity_supply_chain_summary_response import ProjectEntitySupplyChainSummaryResponse from ..core.client_wrapper import AsyncClientWrapper @@ -49,6 +48,7 @@ def create_project_entity( project_id: str, *, request: CreateResolvedProjectEntityRequest, + enable_llm_clean: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> SingleProjectEntityResponse: """ @@ -60,6 +60,9 @@ def create_project_entity( request : CreateResolvedProjectEntityRequest + enable_llm_clean : typing.Optional[bool] + Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -90,6 +93,9 @@ def create_project_entity( _response = self._client_wrapper.httpx_client.request( f"v1/projects/{jsonable_encoder(project_id)}/entities/create", method="POST", + params={ + "enable_llm_clean": enable_llm_clean, + }, json=convert_and_respect_annotation_metadata( object_=request, annotation=CreateResolvedProjectEntityRequest, direction="write" ), @@ -174,94 +180,42 @@ def get_project_entities( self, project_id: str, *, - entity_id: typing.Optional[typing.Sequence[str]] = None, - uploads: typing.Optional[typing.Sequence[str]] = None, - case_status: typing.Optional[typing.Sequence[CaseStatus]] = None, - tags: typing.Optional[typing.Sequence[str]] = None, - match_count: typing.Optional[MatchCount] = None, - match_strength: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None, - entity_types: typing.Optional[typing.Sequence[str]] = None, - geo_facets: typing.Optional[bool] = None, - exact_match: typing.Optional[bool] = None, - hs_codes: typing.Optional[typing.Sequence[str]] = None, - received_hs_codes: typing.Optional[typing.Sequence[str]] = None, - shipped_hs_codes: typing.Optional[typing.Sequence[str]] = None, - upstream_product: typing.Optional[typing.Sequence[str]] = None, + next: typing.Optional[str] = None, + prev: typing.Optional[str] = None, limit: typing.Optional[int] = None, - token: typing.Optional[str] = None, - sort: typing.Optional[typing.Sequence[str]] = None, - aggregations: typing.Optional[typing.Sequence[str]] = None, - num_aggregation_buckets: typing.Optional[int] = None, - risk: typing.Optional[typing.Sequence[Risk]] = None, - risk_category: typing.Optional[typing.Sequence[RiskCategory]] = None, + filter: typing.Optional[ProjectEntitiesFilter] = None, request_options: typing.Optional[RequestOptions] = None, ) -> ProjectEntitiesResponse: """ Retrieves a list of entities for a specific project with pagination support. - Parameters - ---------- - project_id : str - - entity_id : typing.Optional[typing.Sequence[str]] - Filter by entity IDs - - uploads : typing.Optional[typing.Sequence[str]] - Filter by upload IDs + **Response Formats:** + - **JSON** (default): Returns structured data with nested objects + - **CSV**: Returns tabular data with dynamic columns for attributes and risk categories - case_status : typing.Optional[typing.Sequence[CaseStatus]] - Filter by case status + **CSV Format:** + The CSV response includes dynamic columns based on the data: + - `attribute_{field_name}`: Dynamic columns for each attribute field found in the data + - `risk_category_{category_id}`: Dynamic columns for each risk category found in the data + - Standard columns: project_id, project_entity_id, label, project_entity_url, upload_ids, strength, countries, tags, case_status, created_at, match_count, upstream_products, upstream_risk_factors, upstream_countries - tags : typing.Optional[typing.Sequence[str]] - Filter by tag IDs + Use the `Accept: text/csv` header to request CSV format. - match_count : typing.Optional[MatchCount] - Filter by match count - - match_strength : typing.Optional[typing.Sequence[MatchStrengthEnum]] - Filter by match strength - - entity_types : typing.Optional[typing.Sequence[str]] - Filter by entity types - - geo_facets : typing.Optional[bool] - Include geo facets - - exact_match : typing.Optional[bool] - Use exact matching - - hs_codes : typing.Optional[typing.Sequence[str]] - Filter by HS codes - - received_hs_codes : typing.Optional[typing.Sequence[str]] - Filter by received HS codes + Parameters + ---------- + project_id : str - shipped_hs_codes : typing.Optional[typing.Sequence[str]] - Filter by shipped HS codes + next : typing.Optional[str] + The pagination token for the next page of projects. - upstream_product : typing.Optional[typing.Sequence[str]] - Filter by upstream product + prev : typing.Optional[str] + The pagination token for the previous page of projects. limit : typing.Optional[int] - Maximum number of results to return - - token : typing.Optional[str] - Pagination token + Limit total values returned for projects. Defaults to 100. Max 100. - sort : typing.Optional[typing.Sequence[str]] - Sort fields - - aggregations : typing.Optional[typing.Sequence[str]] - Fields to aggregate - - num_aggregation_buckets : typing.Optional[int] - Number of aggregation buckets - - risk : typing.Optional[typing.Sequence[Risk]] - List of risk factors to filter by - - risk_category : typing.Optional[typing.Sequence[RiskCategory]] - List of risk categories to filter by. An entity matches if it has any risk factor belonging to one of the specified categories + filter : typing.Optional[ProjectEntitiesFilter] + Filter the project entities. Supports both dot notation (e.g., 'filter.attribute.name') and bracket notation (e.g., 'filter[attribute][name]') for nested field filtering. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -286,26 +240,12 @@ def get_project_entities( f"v1/projects/{jsonable_encoder(project_id)}/entities", method="GET", params={ - "entity_id": entity_id, - "uploads": uploads, - "case_status": case_status, - "tags": tags, - "match_count": match_count, - "match_strength": match_strength, - "entity_types": entity_types, - "geo_facets": geo_facets, - "exact_match": exact_match, - "hs_codes": hs_codes, - "received_hs_codes": received_hs_codes, - "shipped_hs_codes": shipped_hs_codes, - "upstream_product": upstream_product, + "next": next, + "prev": prev, "limit": limit, - "token": token, - "sort": sort, - "aggregations": aggregations, - "num_aggregation_buckets": num_aggregation_buckets, - "risk": risk, - "risk_category": risk_category, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=ProjectEntitiesFilter, direction="write" + ), }, request_options=request_options, ) @@ -384,20 +324,7 @@ def get_project_entities( raise ApiError(status_code=_response.status_code, body=_response_json) def get_project_entity( - self, - project_id: str, - project_entity_id: str, - *, - entity_id: typing.Optional[typing.Sequence[str]] = None, - uploads: typing.Optional[typing.Sequence[str]] = None, - case_status: typing.Optional[typing.Sequence[CaseStatus]] = None, - tags: typing.Optional[typing.Sequence[str]] = None, - match_count: typing.Optional[MatchCount] = None, - match_strength: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None, - entity_types: typing.Optional[typing.Sequence[str]] = None, - risk: typing.Optional[typing.Sequence[Risk]] = None, - risk_category: typing.Optional[typing.Sequence[RiskCategory]] = None, - request_options: typing.Optional[RequestOptions] = None, + self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> SingleProjectEntityResponse: """ Retrieves a specific entity in a project. @@ -408,33 +335,6 @@ def get_project_entity( project_entity_id : str - entity_id : typing.Optional[typing.Sequence[str]] - Filter by entity IDs - - uploads : typing.Optional[typing.Sequence[str]] - Filter by upload IDs - - case_status : typing.Optional[typing.Sequence[CaseStatus]] - Filter by case status - - tags : typing.Optional[typing.Sequence[str]] - Filter by tag IDs - - match_count : typing.Optional[MatchCount] - Filter by match count - - match_strength : typing.Optional[typing.Sequence[MatchStrengthEnum]] - Filter by match strength - - entity_types : typing.Optional[typing.Sequence[str]] - Filter by entity types - - risk : typing.Optional[typing.Sequence[Risk]] - List of risk factors to filter by - - risk_category : typing.Optional[typing.Sequence[RiskCategory]] - List of risk categories to filter by. An entity matches if it has any risk factor belonging to one of the specified categories - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -458,17 +358,6 @@ def get_project_entity( _response = self._client_wrapper.httpx_client.request( f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}", method="GET", - params={ - "entity_id": entity_id, - "uploads": uploads, - "case_status": case_status, - "tags": tags, - "match_count": match_count, - "match_strength": match_strength, - "entity_types": entity_types, - "risk": risk, - "risk_category": risk_category, - }, request_options=request_options, ) try: @@ -1225,6 +1114,141 @@ def project_entity_supply_chain( raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + def get_project_entity_risk_summary( + self, + project_id: str, + project_entity_id: str, + *, + filter: ProjectEntityRiskSummaryFilters, + request_options: typing.Optional[RequestOptions] = None, + ) -> ProjectEntityRiskSummaryResponse: + """ + Retrieves a risk summary for a specific project entity, including risk factors with network paths and risk intelligence data. + + **Response includes:** + - Risk factors with their levels (elevated, high, critical) + - Network paths showing relationships between entities + - Risk intelligence scores and metadata + - Risk categories and source entity information + + Parameters + ---------- + project_id : str + + project_entity_id : str + + filter : ProjectEntityRiskSummaryFilters + Filter risk factors by risk factor IDs and risk categories + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ProjectEntityRiskSummaryResponse + + Examples + -------- + from sayari import Sayari + from sayari.project_entity import ProjectEntityRiskSummaryFilters + + client = Sayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + client.project_entity.get_project_entity_risk_summary( + project_id="YVB88Y", + project_entity_id="52z4Wa", + filter=ProjectEntityRiskSummaryFilters( + risk_factor=["sanctioned", "regulatory_action"], + risk_category=["sanctions", "export_controls"], + ), + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/risk_summary", + method="GET", + params={ + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=ProjectEntityRiskSummaryFilters, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + ProjectEntityRiskSummaryResponse, + parse_obj_as( + type_=ProjectEntityRiskSummaryResponse, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequest( + typing.cast( + BadRequestResponse, + parse_obj_as( + type_=BadRequestResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise Unauthorized( + typing.cast( + UnauthorizedResponse, + parse_obj_as( + type_=UnauthorizedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFound( + typing.cast( + NotFoundResponse, + parse_obj_as( + type_=NotFoundResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 405: + raise MethodNotAllowed( + typing.cast( + MethodNotAllowedResponse, + parse_obj_as( + type_=MethodNotAllowedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise RateLimitExceeded( + typing.cast( + RateLimitResponse, + parse_obj_as( + type_=RateLimitResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + InternalServerErrorResponse, + parse_obj_as( + type_=InternalServerErrorResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + def project_entity_supply_chain_summary( self, project_id: str, @@ -1415,6 +1439,7 @@ async def create_project_entity( project_id: str, *, request: CreateResolvedProjectEntityRequest, + enable_llm_clean: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> SingleProjectEntityResponse: """ @@ -1426,6 +1451,9 @@ async def create_project_entity( request : CreateResolvedProjectEntityRequest + enable_llm_clean : typing.Optional[bool] + Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1464,6 +1492,9 @@ async def main() -> None: _response = await self._client_wrapper.httpx_client.request( f"v1/projects/{jsonable_encoder(project_id)}/entities/create", method="POST", + params={ + "enable_llm_clean": enable_llm_clean, + }, json=convert_and_respect_annotation_metadata( object_=request, annotation=CreateResolvedProjectEntityRequest, direction="write" ), @@ -1548,94 +1579,42 @@ async def get_project_entities( self, project_id: str, *, - entity_id: typing.Optional[typing.Sequence[str]] = None, - uploads: typing.Optional[typing.Sequence[str]] = None, - case_status: typing.Optional[typing.Sequence[CaseStatus]] = None, - tags: typing.Optional[typing.Sequence[str]] = None, - match_count: typing.Optional[MatchCount] = None, - match_strength: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None, - entity_types: typing.Optional[typing.Sequence[str]] = None, - geo_facets: typing.Optional[bool] = None, - exact_match: typing.Optional[bool] = None, - hs_codes: typing.Optional[typing.Sequence[str]] = None, - received_hs_codes: typing.Optional[typing.Sequence[str]] = None, - shipped_hs_codes: typing.Optional[typing.Sequence[str]] = None, - upstream_product: typing.Optional[typing.Sequence[str]] = None, + next: typing.Optional[str] = None, + prev: typing.Optional[str] = None, limit: typing.Optional[int] = None, - token: typing.Optional[str] = None, - sort: typing.Optional[typing.Sequence[str]] = None, - aggregations: typing.Optional[typing.Sequence[str]] = None, - num_aggregation_buckets: typing.Optional[int] = None, - risk: typing.Optional[typing.Sequence[Risk]] = None, - risk_category: typing.Optional[typing.Sequence[RiskCategory]] = None, + filter: typing.Optional[ProjectEntitiesFilter] = None, request_options: typing.Optional[RequestOptions] = None, ) -> ProjectEntitiesResponse: """ Retrieves a list of entities for a specific project with pagination support. - Parameters - ---------- - project_id : str - - entity_id : typing.Optional[typing.Sequence[str]] - Filter by entity IDs - - uploads : typing.Optional[typing.Sequence[str]] - Filter by upload IDs - - case_status : typing.Optional[typing.Sequence[CaseStatus]] - Filter by case status - - tags : typing.Optional[typing.Sequence[str]] - Filter by tag IDs - - match_count : typing.Optional[MatchCount] - Filter by match count - - match_strength : typing.Optional[typing.Sequence[MatchStrengthEnum]] - Filter by match strength - - entity_types : typing.Optional[typing.Sequence[str]] - Filter by entity types + **Response Formats:** + - **JSON** (default): Returns structured data with nested objects + - **CSV**: Returns tabular data with dynamic columns for attributes and risk categories - geo_facets : typing.Optional[bool] - Include geo facets + **CSV Format:** + The CSV response includes dynamic columns based on the data: + - `attribute_{field_name}`: Dynamic columns for each attribute field found in the data + - `risk_category_{category_id}`: Dynamic columns for each risk category found in the data + - Standard columns: project_id, project_entity_id, label, project_entity_url, upload_ids, strength, countries, tags, case_status, created_at, match_count, upstream_products, upstream_risk_factors, upstream_countries - exact_match : typing.Optional[bool] - Use exact matching + Use the `Accept: text/csv` header to request CSV format. - hs_codes : typing.Optional[typing.Sequence[str]] - Filter by HS codes - - received_hs_codes : typing.Optional[typing.Sequence[str]] - Filter by received HS codes + Parameters + ---------- + project_id : str - shipped_hs_codes : typing.Optional[typing.Sequence[str]] - Filter by shipped HS codes + next : typing.Optional[str] + The pagination token for the next page of projects. - upstream_product : typing.Optional[typing.Sequence[str]] - Filter by upstream product + prev : typing.Optional[str] + The pagination token for the previous page of projects. limit : typing.Optional[int] - Maximum number of results to return - - token : typing.Optional[str] - Pagination token - - sort : typing.Optional[typing.Sequence[str]] - Sort fields - - aggregations : typing.Optional[typing.Sequence[str]] - Fields to aggregate - - num_aggregation_buckets : typing.Optional[int] - Number of aggregation buckets - - risk : typing.Optional[typing.Sequence[Risk]] - List of risk factors to filter by + Limit total values returned for projects. Defaults to 100. Max 100. - risk_category : typing.Optional[typing.Sequence[RiskCategory]] - List of risk categories to filter by. An entity matches if it has any risk factor belonging to one of the specified categories + filter : typing.Optional[ProjectEntitiesFilter] + Filter the project entities. Supports both dot notation (e.g., 'filter.attribute.name') and bracket notation (e.g., 'filter[attribute][name]') for nested field filtering. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1668,26 +1647,12 @@ async def main() -> None: f"v1/projects/{jsonable_encoder(project_id)}/entities", method="GET", params={ - "entity_id": entity_id, - "uploads": uploads, - "case_status": case_status, - "tags": tags, - "match_count": match_count, - "match_strength": match_strength, - "entity_types": entity_types, - "geo_facets": geo_facets, - "exact_match": exact_match, - "hs_codes": hs_codes, - "received_hs_codes": received_hs_codes, - "shipped_hs_codes": shipped_hs_codes, - "upstream_product": upstream_product, + "next": next, + "prev": prev, "limit": limit, - "token": token, - "sort": sort, - "aggregations": aggregations, - "num_aggregation_buckets": num_aggregation_buckets, - "risk": risk, - "risk_category": risk_category, + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=ProjectEntitiesFilter, direction="write" + ), }, request_options=request_options, ) @@ -1766,20 +1731,7 @@ async def main() -> None: raise ApiError(status_code=_response.status_code, body=_response_json) async def get_project_entity( - self, - project_id: str, - project_entity_id: str, - *, - entity_id: typing.Optional[typing.Sequence[str]] = None, - uploads: typing.Optional[typing.Sequence[str]] = None, - case_status: typing.Optional[typing.Sequence[CaseStatus]] = None, - tags: typing.Optional[typing.Sequence[str]] = None, - match_count: typing.Optional[MatchCount] = None, - match_strength: typing.Optional[typing.Sequence[MatchStrengthEnum]] = None, - entity_types: typing.Optional[typing.Sequence[str]] = None, - risk: typing.Optional[typing.Sequence[Risk]] = None, - risk_category: typing.Optional[typing.Sequence[RiskCategory]] = None, - request_options: typing.Optional[RequestOptions] = None, + self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> SingleProjectEntityResponse: """ Retrieves a specific entity in a project. @@ -1790,33 +1742,6 @@ async def get_project_entity( project_entity_id : str - entity_id : typing.Optional[typing.Sequence[str]] - Filter by entity IDs - - uploads : typing.Optional[typing.Sequence[str]] - Filter by upload IDs - - case_status : typing.Optional[typing.Sequence[CaseStatus]] - Filter by case status - - tags : typing.Optional[typing.Sequence[str]] - Filter by tag IDs - - match_count : typing.Optional[MatchCount] - Filter by match count - - match_strength : typing.Optional[typing.Sequence[MatchStrengthEnum]] - Filter by match strength - - entity_types : typing.Optional[typing.Sequence[str]] - Filter by entity types - - risk : typing.Optional[typing.Sequence[Risk]] - List of risk factors to filter by - - risk_category : typing.Optional[typing.Sequence[RiskCategory]] - List of risk categories to filter by. An entity matches if it has any risk factor belonging to one of the specified categories - request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1848,17 +1773,6 @@ async def main() -> None: _response = await self._client_wrapper.httpx_client.request( f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}", method="GET", - params={ - "entity_id": entity_id, - "uploads": uploads, - "case_status": case_status, - "tags": tags, - "match_count": match_count, - "match_strength": match_strength, - "entity_types": entity_types, - "risk": risk, - "risk_category": risk_category, - }, request_options=request_options, ) try: @@ -2655,6 +2569,149 @@ async def main() -> None: raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + async def get_project_entity_risk_summary( + self, + project_id: str, + project_entity_id: str, + *, + filter: ProjectEntityRiskSummaryFilters, + request_options: typing.Optional[RequestOptions] = None, + ) -> ProjectEntityRiskSummaryResponse: + """ + Retrieves a risk summary for a specific project entity, including risk factors with network paths and risk intelligence data. + + **Response includes:** + - Risk factors with their levels (elevated, high, critical) + - Network paths showing relationships between entities + - Risk intelligence scores and metadata + - Risk categories and source entity information + + Parameters + ---------- + project_id : str + + project_entity_id : str + + filter : ProjectEntityRiskSummaryFilters + Filter risk factors by risk factor IDs and risk categories + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ProjectEntityRiskSummaryResponse + + Examples + -------- + import asyncio + + from sayari import AsyncSayari + from sayari.project_entity import ProjectEntityRiskSummaryFilters + + client = AsyncSayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + + + async def main() -> None: + await client.project_entity.get_project_entity_risk_summary( + project_id="YVB88Y", + project_entity_id="52z4Wa", + filter=ProjectEntityRiskSummaryFilters( + risk_factor=["sanctioned", "regulatory_action"], + risk_category=["sanctions", "export_controls"], + ), + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/risk_summary", + method="GET", + params={ + "filter": convert_and_respect_annotation_metadata( + object_=filter, annotation=ProjectEntityRiskSummaryFilters, direction="write" + ), + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + ProjectEntityRiskSummaryResponse, + parse_obj_as( + type_=ProjectEntityRiskSummaryResponse, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequest( + typing.cast( + BadRequestResponse, + parse_obj_as( + type_=BadRequestResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise Unauthorized( + typing.cast( + UnauthorizedResponse, + parse_obj_as( + type_=UnauthorizedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFound( + typing.cast( + NotFoundResponse, + parse_obj_as( + type_=NotFoundResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 405: + raise MethodNotAllowed( + typing.cast( + MethodNotAllowedResponse, + parse_obj_as( + type_=MethodNotAllowedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise RateLimitExceeded( + typing.cast( + RateLimitResponse, + parse_obj_as( + type_=RateLimitResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + InternalServerErrorResponse, + parse_obj_as( + type_=InternalServerErrorResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + async def project_entity_supply_chain_summary( self, project_id: str, diff --git a/src/sayari/project_entity/types/__init__.py b/src/sayari/project_entity/types/__init__.py index 02a1fae0..436ffc08 100644 --- a/src/sayari/project_entity/types/__init__.py +++ b/src/sayari/project_entity/types/__init__.py @@ -6,26 +6,34 @@ from .attribute_values import AttributeValues from .attributes_response import AttributesResponse from .business_purpose import BusinessPurpose -from .case_status import CaseStatus from .count_type import CountType from .create_resolved_project_entity_request import CreateResolvedProjectEntityRequest from .facet_bucket import FacetBucket from .facets_response import FacetsResponse +from .field_match_quality import FieldMatchQuality from .grouped_attribute import GroupedAttribute from .grouped_attribute_value import GroupedAttributeValue from .location import Location -from .match_count import MatchCount from .match_profile_enum import MatchProfileEnum -from .match_strength_enum import MatchStrengthEnum -from .matched_attributes import MatchedAttributes from .product_bucket import ProductBucket from .product_count import ProductCount from .product_mapping import ProductMapping +from .project_entities_custom_field_filter import ProjectEntitiesCustomFieldFilter +from .project_entities_exact_filter import ProjectEntitiesExactFilter +from .project_entities_filter import ProjectEntitiesFilter +from .project_entities_fuzzy_filter import ProjectEntitiesFuzzyFilter from .project_entities_response import ProjectEntitiesResponse from .project_entity_exists_response_data import ProjectEntityExistsResponseData from .project_entity_id_response import ProjectEntityIdResponse +from .project_entity_match_explanation import ProjectEntityMatchExplanation from .project_entity_match_response import ProjectEntityMatchResponse from .project_entity_response import ProjectEntityResponse +from .project_entity_risk_summary_data import ProjectEntityRiskSummaryData +from .project_entity_risk_summary_filters import ProjectEntityRiskSummaryFilters +from .project_entity_risk_summary_network_path import ProjectEntityRiskSummaryNetworkPath +from .project_entity_risk_summary_response import ProjectEntityRiskSummaryResponse +from .project_entity_risk_summary_response_filters import ProjectEntityRiskSummaryResponseFilters +from .project_entity_risk_summary_risk_factor import ProjectEntityRiskSummaryRiskFactor from .project_entity_supply_chain_summary_response import ProjectEntitySupplyChainSummaryResponse from .project_entity_supply_chain_summary_response_data import ProjectEntitySupplyChainSummaryResponseData from .project_entity_supply_chain_upstream import ProjectEntitySupplyChainUpstream @@ -35,6 +43,7 @@ from .resolution_profile import ResolutionProfile from .risk_categories_summary import RiskCategoriesSummary from .save_project_entity_body import SaveProjectEntityBody +from .share_information import ShareInformation from .single_project_entity_response import SingleProjectEntityResponse from .source_field import SourceField from .special_facet_bucket import SpecialFacetBucket @@ -55,26 +64,34 @@ "AttributeValues", "AttributesResponse", "BusinessPurpose", - "CaseStatus", "CountType", "CreateResolvedProjectEntityRequest", "FacetBucket", "FacetsResponse", + "FieldMatchQuality", "GroupedAttribute", "GroupedAttributeValue", "Location", - "MatchCount", "MatchProfileEnum", - "MatchStrengthEnum", - "MatchedAttributes", "ProductBucket", "ProductCount", "ProductMapping", + "ProjectEntitiesCustomFieldFilter", + "ProjectEntitiesExactFilter", + "ProjectEntitiesFilter", + "ProjectEntitiesFuzzyFilter", "ProjectEntitiesResponse", "ProjectEntityExistsResponseData", "ProjectEntityIdResponse", + "ProjectEntityMatchExplanation", "ProjectEntityMatchResponse", "ProjectEntityResponse", + "ProjectEntityRiskSummaryData", + "ProjectEntityRiskSummaryFilters", + "ProjectEntityRiskSummaryNetworkPath", + "ProjectEntityRiskSummaryResponse", + "ProjectEntityRiskSummaryResponseFilters", + "ProjectEntityRiskSummaryRiskFactor", "ProjectEntitySupplyChainSummaryResponse", "ProjectEntitySupplyChainSummaryResponseData", "ProjectEntitySupplyChainUpstream", @@ -84,6 +101,7 @@ "ResolutionProfile", "RiskCategoriesSummary", "SaveProjectEntityBody", + "ShareInformation", "SingleProjectEntityResponse", "SourceField", "SpecialFacetBucket", diff --git a/src/sayari/project_entity/types/attribute_type.py b/src/sayari/project_entity/types/attribute_type.py index 990c6bc1..69b913ec 100644 --- a/src/sayari/project_entity/types/attribute_type.py +++ b/src/sayari/project_entity/types/attribute_type.py @@ -7,8 +7,8 @@ class AttributeType(UniversalBaseModel): - type: str - resolution: bool + field: str + match_resolution: bool if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/sayari/project_entity/types/attribute_values.py b/src/sayari/project_entity/types/attribute_values.py index 9c55120a..f979d8a8 100644 --- a/src/sayari/project_entity/types/attribute_values.py +++ b/src/sayari/project_entity/types/attribute_values.py @@ -7,7 +7,7 @@ class AttributeValues(UniversalBaseModel): - resolve: bool + match_resolution: bool values: typing.List[str] if IS_PYDANTIC_V2: diff --git a/src/sayari/project_entity/types/create_resolved_project_entity_request.py b/src/sayari/project_entity/types/create_resolved_project_entity_request.py index b166ee5e..e0860fb6 100644 --- a/src/sayari/project_entity/types/create_resolved_project_entity_request.py +++ b/src/sayari/project_entity/types/create_resolved_project_entity_request.py @@ -6,8 +6,8 @@ from ...generated_types.types.country import Country from ...generated_types.types.entities import Entities from .resolution_profile import ResolutionProfile -from ...core.pydantic_utilities import IS_PYDANTIC_V2 import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 class CreateResolvedProjectEntityRequest(UniversalBaseModel): @@ -35,6 +35,10 @@ class CreateResolvedProjectEntityRequest(UniversalBaseModel): city: typing.Optional[typing.List[str]] = None state: typing.Optional[typing.List[str]] = None profile: typing.Optional[ResolutionProfile] = None + enable_llm_clean: typing.Optional[bool] = pydantic.Field(default=None) + """ + Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning. + """ if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/sayari/project_entity/types/field_match_quality.py b/src/sayari/project_entity/types/field_match_quality.py new file mode 100644 index 00000000..e293538f --- /dev/null +++ b/src/sayari/project_entity/types/field_match_quality.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +FieldMatchQuality = typing.Union[typing.Literal["high", "medium", "low", "na"], typing.Any] diff --git a/src/sayari/project_entity/types/project_entities_custom_field_filter.py b/src/sayari/project_entity/types/project_entities_custom_field_filter.py new file mode 100644 index 00000000..d0ab1ec6 --- /dev/null +++ b/src/sayari/project_entity/types/project_entities_custom_field_filter.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +import typing_extensions +import typing +from ...base_types.types.custom_field_value import CustomFieldValue +from ...core.serialization import FieldMetadata +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ProjectEntitiesCustomFieldFilter(UniversalBaseModel): + custom_field_name: typing_extensions.Annotated[ + typing.Optional[CustomFieldValue], FieldMetadata(alias="custom_{field name}") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity/types/matched_attributes.py b/src/sayari/project_entity/types/project_entities_exact_filter.py similarity index 61% rename from src/sayari/project_entity/types/matched_attributes.py rename to src/sayari/project_entity/types/project_entities_exact_filter.py index 3a8210ed..281e1e1f 100644 --- a/src/sayari/project_entity/types/matched_attributes.py +++ b/src/sayari/project_entity/types/project_entities_exact_filter.py @@ -2,16 +2,15 @@ from ...core.pydantic_utilities import UniversalBaseModel import typing -from ...core.pydantic_utilities import IS_PYDANTIC_V2 import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 -class MatchedAttributes(UniversalBaseModel): - name: typing.Optional[typing.List[str]] = None - address: typing.Optional[typing.List[str]] = None - contact: typing.Optional[typing.List[str]] = None - country: typing.Optional[typing.List[str]] = None - identifier: typing.Optional[typing.List[str]] = None +class ProjectEntitiesExactFilter(UniversalBaseModel): + exact: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Filter with exact matching. + """ if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/sayari/project/types/project_entities_filter.py b/src/sayari/project_entity/types/project_entities_filter.py similarity index 67% rename from src/sayari/project/types/project_entities_filter.py rename to src/sayari/project_entity/types/project_entities_filter.py index 5fd228a6..63028221 100644 --- a/src/sayari/project/types/project_entities_filter.py +++ b/src/sayari/project_entity/types/project_entities_filter.py @@ -4,44 +4,33 @@ import typing from ...generated_types.types.risk import Risk import pydantic -from .upstream_tiers import UpstreamTiers from ...generated_types.types.country import Country import typing_extensions from ...core.serialization import FieldMetadata +from .project_entities_fuzzy_filter import ProjectEntitiesFuzzyFilter +from .project_entities_exact_filter import ProjectEntitiesExactFilter from ...generated_types.types.company_status import CompanyStatus -from ...base_types.types.custom_field_value import CustomFieldValue +from ...shared_types.types.case_status import CaseStatus +from ...shared_types.types.match_strength_enum import MatchStrengthEnum +from ...shared_types.types.match_count import MatchCount +from .project_entities_custom_field_filter import ProjectEntitiesCustomFieldFilter from ...core.pydantic_utilities import IS_PYDANTIC_V2 class ProjectEntitiesFilter(UniversalBaseModel): - risk: typing.Optional[typing.List[Risk]] = pydantic.Field(default=None) + risk_factor: typing.Optional[typing.List[Risk]] = pydantic.Field(default=None) """ Filter by [risk factor](/sayari-library/ontology/risk-factors) ID. """ - upstream_risk: typing.Optional[typing.List[Risk]] = pydantic.Field(default=None) - """ - Filter by upstream (supply chain) [risk factor](/sayari-library/ontology/risk-factors) ID. - """ - - upstream_risk_tiers: typing.Optional[typing.List[UpstreamTiers]] = pydantic.Field(default=None) - """ - Filter by upstream (supply chain) tiers that has one or more risks - """ - - country: typing.Optional[typing.List[Country]] = pydantic.Field(default=None) - """ - Filter by [country](/sayari-library/ontology/enumerated-types#country). - """ - - upstream_country: typing.Optional[typing.List[Country]] = pydantic.Field(default=None) + risk_category: typing.Optional[typing.List[str]] = pydantic.Field(default=None) """ - This filter is deprecated. Filter by upstream (supply chain) [country](/sayari-library/ontology/enumerated-types#country). + Filter by risk factor `category`, e.g. `sanctions`. At least one risk factor from each provided category must be present. """ - upstream_country_tiers: typing.Optional[typing.List[UpstreamTiers]] = pydantic.Field(default=None) + upstream_product: typing.Optional[typing.List[str]] = pydantic.Field(default=None) """ - This filter is deprecated. Filter by upstream (supply chain) tiers that has one or more countries + Filter by upstream (supply chain) product ID. """ shipment_country: typing.Optional[typing.List[Country]] = pydantic.Field(default=None) @@ -84,66 +73,90 @@ class ProjectEntitiesFilter(UniversalBaseModel): Filter by upstream (supply chain) [country](/sayari-library/ontology/enumerated-types#country) at tier 5. """ + country: typing.Optional[typing.List[Country]] = pydantic.Field(default=None) + """ + Filter by [country](/sayari-library/ontology/enumerated-types#country). + """ + business_purpose: typing.Optional[typing.List[str]] = pydantic.Field(default=None) """ Filter by HS code, HS code description, or business description. """ - label_fuzzy: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="label.fuzzy")] = ( - pydantic.Field(default=None) - ) + label: typing.Optional[ProjectEntitiesFuzzyFilter] = pydantic.Field(default=None) """ Filter by entity label with fuzzy matching. """ - city_fuzzy: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="city.fuzzy")] = ( - pydantic.Field(default=None) - ) + city: typing.Optional[ProjectEntitiesFuzzyFilter] = pydantic.Field(default=None) """ Filter by entity city with fuzzy matching. """ - state_fuzzy: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="state.fuzzy")] = ( - pydantic.Field(default=None) - ) + state: typing.Optional[ProjectEntitiesFuzzyFilter] = pydantic.Field(default=None) """ Filter by entity address state with fuzzy matching. """ - identifier_fuzzy: typing_extensions.Annotated[ - typing.Optional[typing.List[str]], FieldMetadata(alias="identifier.fuzzy") - ] = pydantic.Field(default=None) + identifier: typing.Optional[ProjectEntitiesFuzzyFilter] = pydantic.Field(default=None) """ Filter by entity identifier attributes with fuzzy matching. """ - source_exact: typing_extensions.Annotated[ - typing.Optional[typing.List[str]], FieldMetadata(alias="source.exact") - ] = pydantic.Field(default=None) + source: typing.Optional[ProjectEntitiesExactFilter] = pydantic.Field(default=None) """ Filter by entity source ID. """ - status_exact: typing_extensions.Annotated[ - typing.Optional[typing.List[CompanyStatus]], FieldMetadata(alias="status.exact") - ] = pydantic.Field(default=None) + status: typing.Optional[typing.List[CompanyStatus]] = pydantic.Field(default=None) """ Filter by entity [company status](/sayari-library/ontology/enumerated-types#company-status). """ - risk_category: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + bounds: typing.Optional[str] = pydantic.Field(default=None) """ - Filter by risk factor `category`, e.g. `sanctions`. At least one risk factor from each provided category must be present. + Filter by a geographical bounding box. The value is a pipe-delimited set of four values representing the top, left, bottom, and right sides of the bounding box, in that order. The pipes should be URL-encoded as `%7C`. The top coordinate must greater than the bottom coordinate, and the left coordinate must be less than the right coordinate. A sample is `55.680357237879136|-71.53607290158526|41.10876347746233|-40.963927098414736` """ - bounds: typing.Optional[str] = pydantic.Field(default=None) + match_entity_id: typing.Optional[typing.List[str]] = pydantic.Field(default=None) """ - Filter by a geographical bounding box. The value is a pipe-delimited set of four values representing the top, left, bottom, and right sides of the bounding box, in that order. The pipes should be URL-encoded as `%7C`. The top coordinate must greater than the bottom coordinate, and the left coordinate must be less than the right coordinate. A sample is `55.680357237879136|-71.53607290158526|41.10876347746233|-40.963927098414736` + Filter by match entity ID. + """ + + entity_type: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Filter by entity type. + """ + + tag: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Filter by tag ID. + """ + + upload: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Filter by upload ID. """ - custom_field_name: typing_extensions.Annotated[ - typing.Optional[CustomFieldValue], FieldMetadata(alias="custom_{field name}") - ] = None + case_status: typing.Optional[typing.List[CaseStatus]] = pydantic.Field(default=None) + """ + Filter by case status. + """ + + match_strength: typing.Optional[typing.List[MatchStrengthEnum]] = pydantic.Field(default=None) + """ + Filter by match strength. + """ + + match_count: typing.Optional[MatchCount] = pydantic.Field(default=None) + """ + Filter by match count. + """ + + attribute: typing.Optional[ProjectEntitiesCustomFieldFilter] = pydantic.Field(default=None) + """ + Filter by custom field. + """ if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/sayari/project_entity/types/project_entities_fuzzy_filter.py b/src/sayari/project_entity/types/project_entities_fuzzy_filter.py new file mode 100644 index 00000000..9b80c952 --- /dev/null +++ b/src/sayari/project_entity/types/project_entities_fuzzy_filter.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +import typing +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 + + +class ProjectEntitiesFuzzyFilter(UniversalBaseModel): + fuzzy: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + Filter with fuzzy matching. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity/types/project_entities_response.py b/src/sayari/project_entity/types/project_entities_response.py index abbcc145..942590db 100644 --- a/src/sayari/project_entity/types/project_entities_response.py +++ b/src/sayari/project_entity/types/project_entities_response.py @@ -17,8 +17,8 @@ class ProjectEntitiesResponse(UniversalBaseModel): Address, AttributeValues, BusinessPurpose, - MatchedAttributes, ProjectEntitiesResponse, + ProjectEntityMatchExplanation, ProjectEntityMatchResponse, ProjectEntityResponse, ProjectRiskCategory, @@ -40,19 +40,19 @@ class ProjectEntitiesResponse(UniversalBaseModel): created_at="2025-04-22 22:54:00.913586+00", attributes={ "name": AttributeValues( - resolve=True, + match_resolution=True, values=["VTB Bank"], ), "country": AttributeValues( - resolve=True, + match_resolution=True, values=["RUS"], ), "address": AttributeValues( - resolve=True, + match_resolution=True, values=["Moscow"], ), "identifier": AttributeValues( - resolve=True, + match_resolution=True, values=["253400V1H6ART1UQ0N98"], ), }, @@ -145,27 +145,40 @@ class ProjectEntitiesResponse(UniversalBaseModel): sayari_entity_id="dy-rh2g0QtzUN_jC_e9S_A", type="company", label='ОТКРЫТОЕ АКЦИОНЕРНОЕ ОБЩЕСТВО "РОССИЙСКИЕ ЖЕЛЕЗНЫЕ ДОРОГИ"', - matched_attributes=MatchedAttributes( - name=[ - "БАНК ВТБ (ПАО)", - "VTB BANK (PJSC)", - "БАНК ВТБ (ПУБЛИЧНОЕ АКЦИОНЕРНОЕ ОБЩЕСТВО)", - "VTB BANK (PUBLIC JOINT STOCK COMPANY)", - "VTB Bank", - ], - address=[ - "109147 Moscow, st. Vorontsovskaya, 43 building 1", - "119121 Moscow, st. Plyushchikha, 37.", - "Vorontsovskaya Str., 43 Moscow 109044 RUSSIAN FEDERATION", - "37 Plyushchikha ul., Moscow, 119121, Russia", - "Bashnya Zapad, Kompleks Federatsiya, 12, nab. Presnenskaya, Moscow, 123317, Russia", - ], - country=["RUS"], - identifier=[ - "253400V1H6ART1UQ0N98", - "253400V1H6ART1UQ0N98", - ], - ), + match_explanation=[ + ProjectEntityMatchExplanation( + field="name", + quality="high", + matches=[ + "БАНК ВТБ (ПАО)", + "VTB BANK (PJSC)", + "БАНК ВТБ (ПУБЛИЧНОЕ АКЦИОНЕРНОЕ ОБЩЕСТВО)", + "VTB BANK (PUBLIC JOINT STOCK COMPANY)", + "VTB Bank", + ], + ), + ProjectEntityMatchExplanation( + field="address", + quality="medium", + matches=[ + "109147 Moscow, st. Vorontsovskaya, 43 building 1", + "119121 Moscow, st. Plyushchikha, 37.", + "Vorontsovskaya Str., 43 Moscow 109044 RUSSIAN FEDERATION", + "37 Plyushchikha ul., Moscow, 119121, Russia", + "Bashnya Zapad, Kompleks Federatsiya, 12, nab. Presnenskaya, Moscow, 123317, Russia", + ], + ), + ProjectEntityMatchExplanation( + field="country", + quality="high", + matches=["RUS"], + ), + ProjectEntityMatchExplanation( + field="identifier", + quality="high", + matches=["253400V1H6ART1UQ0N98"], + ), + ], countries=[ "USA", "CYP", diff --git a/src/sayari/project_entity/types/project_entity_match_explanation.py b/src/sayari/project_entity/types/project_entity_match_explanation.py new file mode 100644 index 00000000..41bd9c15 --- /dev/null +++ b/src/sayari/project_entity/types/project_entity_match_explanation.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +from .field_match_quality import FieldMatchQuality +import pydantic +import typing +from ...core.pydantic_utilities import IS_PYDANTIC_V2 + + +class ProjectEntityMatchExplanation(UniversalBaseModel): + field: str + quality: FieldMatchQuality = pydantic.Field() + """ + Quality of the match + """ + + description: typing.Optional[typing.List[str]] = None + matches: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity/types/project_entity_match_response.py b/src/sayari/project_entity/types/project_entity_match_response.py index 2fab5108..904c9126 100644 --- a/src/sayari/project_entity/types/project_entity_match_response.py +++ b/src/sayari/project_entity/types/project_entity_match_response.py @@ -1,7 +1,6 @@ # This file was auto-generated by Fern from our API Definition. from ...core.pydantic_utilities import UniversalBaseModel -from .matched_attributes import MatchedAttributes import typing from .project_risk_category import ProjectRiskCategory from .project_risk_factor import ProjectRiskFactor @@ -10,6 +9,7 @@ from .source_field import SourceField from .address import Address from .match_profile_enum import MatchProfileEnum +from .project_entity_match_explanation import ProjectEntityMatchExplanation from ...core.pydantic_utilities import IS_PYDANTIC_V2 import pydantic @@ -19,7 +19,6 @@ class ProjectEntityMatchResponse(UniversalBaseModel): sayari_entity_id: str type: str label: str - matched_attributes: MatchedAttributes countries: typing.List[str] risk_categories: typing.List[ProjectRiskCategory] risk_factors: typing.List[ProjectRiskFactor] @@ -32,6 +31,7 @@ class ProjectEntityMatchResponse(UniversalBaseModel): updated_at: typing.Optional[str] = None match_profile: typing.Optional[MatchProfileEnum] = None deleted_at: typing.Optional[str] = None + match_explanation: typing.Optional[typing.List[ProjectEntityMatchExplanation]] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/sayari/project_entity/types/project_entity_response.py b/src/sayari/project_entity/types/project_entity_response.py index 11b7dcc5..dbd976cf 100644 --- a/src/sayari/project_entity/types/project_entity_response.py +++ b/src/sayari/project_entity/types/project_entity_response.py @@ -2,13 +2,13 @@ from ...core.pydantic_utilities import UniversalBaseModel import typing -from .match_strength_enum import MatchStrengthEnum +from ...shared_types.types.match_strength_enum import MatchStrengthEnum from .attribute_values import AttributeValues from .project_risk_category import ProjectRiskCategory from .project_risk_factor import ProjectRiskFactor from .upstream_info import UpstreamInfo from .tag_response import TagResponse -from .case_status import CaseStatus +from ...shared_types.types.case_status import CaseStatus from .project_entity_match_response import ProjectEntityMatchResponse from ...core.pydantic_utilities import IS_PYDANTIC_V2 import pydantic diff --git a/src/sayari/project_entity/types/project_entity_risk_summary_data.py b/src/sayari/project_entity/types/project_entity_risk_summary_data.py new file mode 100644 index 00000000..2ba1682a --- /dev/null +++ b/src/sayari/project_entity/types/project_entity_risk_summary_data.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +import typing +from .project_entity_risk_summary_risk_factor import ProjectEntityRiskSummaryRiskFactor +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ProjectEntityRiskSummaryData(UniversalBaseModel): + project_entity_id: str + project_id: str + risk_factors: typing.List[ProjectEntityRiskSummaryRiskFactor] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/source/types/source.py b/src/sayari/project_entity/types/project_entity_risk_summary_filters.py similarity index 52% rename from src/sayari/source/types/source.py rename to src/sayari/project_entity/types/project_entity_risk_summary_filters.py index 4fb5a822..bd143484 100644 --- a/src/sayari/source/types/source.py +++ b/src/sayari/project_entity/types/project_entity_risk_summary_filters.py @@ -1,34 +1,22 @@ # This file was auto-generated by Fern from our API Definition. from ...core.pydantic_utilities import UniversalBaseModel -import pydantic -from ...generated_types.types.country import Country import typing +import pydantic from ...core.pydantic_utilities import IS_PYDANTIC_V2 -class Source(UniversalBaseModel): - id: str = pydantic.Field() +class ProjectEntityRiskSummaryFilters(UniversalBaseModel): + risk_factor: typing.Optional[typing.List[str]] = pydantic.Field(default=None) """ - The unique identifier of the source + Filter by risk factor IDs """ - label: str - description: str - country: Country = pydantic.Field() + risk_category: typing.Optional[typing.List[str]] = pydantic.Field(default=None) """ - Source [country](/sayari-library/ontology/enumerated-types#country) + Filter by risk category IDs """ - region: str - date_added: str - source_type: str - record_type: str - structure: str - source_url: typing.Optional[str] = None - pep: bool - watchlist: bool - if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/sayari/project_entity/types/project_entity_risk_summary_network_path.py b/src/sayari/project_entity/types/project_entity_risk_summary_network_path.py new file mode 100644 index 00000000..74060767 --- /dev/null +++ b/src/sayari/project_entity/types/project_entity_risk_summary_network_path.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +import typing +from .share_information import ShareInformation +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ProjectEntityRiskSummaryNetworkPath(UniversalBaseModel): + sayari_entity_id: str + sayari_entity_label: str + relationship_type: str + relationship_status: str + former: bool + first_observed: str + last_observed: str + start_date: typing.Optional[str] = None + shares: typing.Optional[ShareInformation] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity/types/project_entity_risk_summary_response.py b/src/sayari/project_entity/types/project_entity_risk_summary_response.py new file mode 100644 index 00000000..f3632509 --- /dev/null +++ b/src/sayari/project_entity/types/project_entity_risk_summary_response.py @@ -0,0 +1,264 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +from .project_entity_risk_summary_data import ProjectEntityRiskSummaryData +from .project_entity_risk_summary_response_filters import ProjectEntityRiskSummaryResponseFilters +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import typing +import pydantic + + +class ProjectEntityRiskSummaryResponse(UniversalBaseModel): + """ + Examples + -------- + from sayari.project_entity import ( + ProjectEntityRiskSummaryData, + ProjectEntityRiskSummaryNetworkPath, + ProjectEntityRiskSummaryResponse, + ProjectEntityRiskSummaryResponseFilters, + ProjectEntityRiskSummaryRiskFactor, + ProjectRiskCategory, + ShareInformation, + ) + + ProjectEntityRiskSummaryResponse( + data=ProjectEntityRiskSummaryData( + project_entity_id="GleDrP", + project_id="8YMJNG", + risk_factors=[ + ProjectEntityRiskSummaryRiskFactor( + id="imports_ilab_child_labor", + label="Imports Goods with ILAB Child Labor Risk", + value="true", + level="elevated", + source_entity_ids=["FFgmjk4bK6vDn25yMypciw"], + metadata=[ + { + "traversal_path": [ + "FFgmjk4bK6vDn25yMypciw|receiver_of|QB7r598_7sPrCNefvZrAyw" + ], + "origin_shipment_product": [ + "640299", + "5705", + "62", + "5702", + "64", + "42", + ], + } + ], + risk_intelligence=[ + { + "type": "financial_risk_score", + "score": 36, + "Label": "S&P RiskGauge Credit Risk", + } + ], + risk_categories=[ + ProjectRiskCategory( + id="forced_labor", + label="Forced labor", + risk_factors=["imports_ilab_child_labor"], + ) + ], + network_paths=[[]], + ), + ProjectEntityRiskSummaryRiskFactor( + id="forced_labor_xinjiang_origin_subtier", + label="Supplier Network with Xinjiang-Based Entity", + value=2, + level="elevated", + source_entity_ids=["FFgmjk4bK6vDn25yMypciw"], + metadata=[ + { + "traversal_path": [ + "FFgmjk4bK6vDn25yMypciw|receives_from|doWJaXqr57DBYPyHcF_BxQ|receives_from|A3YwnnynaDQnlinlbt-UlQ" + ] + } + ], + risk_intelligence=[ + { + "type": "financial_risk_score", + "score": 36, + "Label": "S&P RiskGauge Credit Risk", + } + ], + risk_categories=[ + ProjectRiskCategory( + id="forced_labor", + label="Forced labor", + risk_factors=["forced_labor_xinjiang_origin_subtier"], + ) + ], + network_paths=[ + [ + ProjectEntityRiskSummaryNetworkPath( + sayari_entity_id="doWJaXqr57DBYPyHcF_BxQ", + sayari_entity_label="LIBERTY MILLS LIMITED", + relationship_type="receives_from", + relationship_status="active", + former=False, + first_observed="2024-03-08", + last_observed="2024-03-14", + start_date="2024-03-08", + shares=ShareInformation(), + ), + ProjectEntityRiskSummaryNetworkPath( + sayari_entity_id="A3YwnnynaDQnlinlbt-UlQ", + sayari_entity_label="XINXIANG CHEMICAL FIBRE CO., LTD", + relationship_type="receives_from", + relationship_status="active", + former=False, + first_observed="2024-03-11", + last_observed="2024-03-25", + start_date="2024-03-11", + shares=ShareInformation(), + ), + ] + ], + ), + ProjectEntityRiskSummaryRiskFactor( + id="forced_labor_sheffield_hallam_university_reports_origin_subtier", + label="Supplier Network with Entity from Sheffield Hallam University Forced Labor Reports", + value=2, + level="elevated", + source_entity_ids=["FFgmjk4bK6vDn25yMypciw"], + metadata=[ + { + "traversal_path": [ + "FFgmjk4bK6vDn25yMypciw|receives_from|hky4niXTOuJOZ3YJUHBvpw|receives_from|jcG2-gcTVXhH6J2UO7bASg" + ] + } + ], + risk_intelligence=[ + { + "type": "financial_risk_score", + "score": 36, + "Label": "S&P RiskGauge Credit Risk", + } + ], + risk_categories=[ + ProjectRiskCategory( + id="forced_labor", + label="Forced labor", + risk_factors=[ + "forced_labor_sheffield_hallam_university_reports_origin_subtier" + ], + ) + ], + network_paths=[ + [ + ProjectEntityRiskSummaryNetworkPath( + sayari_entity_id="hky4niXTOuJOZ3YJUHBvpw", + sayari_entity_label="KOHINOOR TEXTILE MILLS LIMITED", + relationship_type="receives_from", + relationship_status="active", + former=False, + first_observed="2023-09-27", + last_observed="2023-09-27", + start_date="2023-09-27", + shares=ShareInformation(), + ), + ProjectEntityRiskSummaryNetworkPath( + sayari_entity_id="jcG2-gcTVXhH6J2UO7bASg", + sayari_entity_label="WEIQIAO TEXTILE COMPANY LIMITED", + relationship_type="receives_from", + relationship_status="active", + former=False, + first_observed="2017-03-08", + last_observed="2025-04-21", + start_date="2017-03-08", + shares=ShareInformation(), + ), + ] + ], + ), + ProjectEntityRiskSummaryRiskFactor( + id="forced_labor_uflpa_origin_subtier", + label="Supplier Network with UFLPA Entity", + value=3, + level="elevated", + source_entity_ids=["FFgmjk4bK6vDn25yMypciw"], + metadata=[ + { + "traversal_path": [ + "FFgmjk4bK6vDn25yMypciw|receives_from|Lg1BHckRWGrKUT03LUy3iw|receives_from|rmgKmpNeQxhVNnrnemI2yQ|receives_from|CZAZypVNS-jkOGzpRpCXEw" + ] + } + ], + risk_intelligence=[ + { + "type": "financial_risk_score", + "score": 36, + "Label": "S&P RiskGauge Credit Risk", + } + ], + risk_categories=[ + ProjectRiskCategory( + id="forced_labor", + label="Forced labor", + risk_factors=["forced_labor_uflpa_origin_subtier"], + ) + ], + network_paths=[ + [ + ProjectEntityRiskSummaryNetworkPath( + sayari_entity_id="Lg1BHckRWGrKUT03LUy3iw", + sayari_entity_label="KAMAL LIMITED", + relationship_type="receives_from", + relationship_status="active", + former=False, + first_observed="2024-04-29", + last_observed="2025-04-21", + start_date="2024-04-29", + shares=ShareInformation(), + ), + ProjectEntityRiskSummaryNetworkPath( + sayari_entity_id="rmgKmpNeQxhVNnrnemI2yQ", + sayari_entity_label="CôNG TY TRáCH NHIệM HữU HạN HYOSUNG ĐồNG NAI", + relationship_type="receives_from", + relationship_status="active", + former=False, + first_observed="2023-09-28", + last_observed="2025-04-13", + start_date="2023-09-28", + shares=ShareInformation(), + ), + ProjectEntityRiskSummaryNetworkPath( + sayari_entity_id="CZAZypVNS-jkOGzpRpCXEw", + sayari_entity_label="HANGZHOU UNION BIOTECHNOLOGY CO., LTD", + relationship_type="receives_from", + relationship_status="active", + former=False, + first_observed="2023-03-09", + last_observed="2025-02-27", + start_date="2023-03-09", + shares=ShareInformation(), + ), + ] + ], + ), + ], + ), + filters=ProjectEntityRiskSummaryResponseFilters( + risk_factor=[ + "imports_ilab_child_labor", + "forced_labor_xinjiang_origin_subtier", + ], + risk_category=["forced_labor"], + ), + ) + """ + + data: ProjectEntityRiskSummaryData + filters: ProjectEntityRiskSummaryResponseFilters + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity/types/project_entity_risk_summary_response_filters.py b/src/sayari/project_entity/types/project_entity_risk_summary_response_filters.py new file mode 100644 index 00000000..8d443331 --- /dev/null +++ b/src/sayari/project_entity/types/project_entity_risk_summary_response_filters.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +import typing +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ProjectEntityRiskSummaryResponseFilters(UniversalBaseModel): + risk_factor: typing.Optional[typing.List[str]] = None + risk_category: typing.Optional[typing.List[str]] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity/types/project_entity_risk_summary_risk_factor.py b/src/sayari/project_entity/types/project_entity_risk_summary_risk_factor.py new file mode 100644 index 00000000..a3d577f8 --- /dev/null +++ b/src/sayari/project_entity/types/project_entity_risk_summary_risk_factor.py @@ -0,0 +1,31 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +from .string_or_number import StringOrNumber +from ...shared_types.types.risk_level import RiskLevel +import typing +from .project_risk_category import ProjectRiskCategory +from .project_entity_risk_summary_network_path import ProjectEntityRiskSummaryNetworkPath +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ProjectEntityRiskSummaryRiskFactor(UniversalBaseModel): + id: str + label: str + value: StringOrNumber + level: RiskLevel + risk_categories: typing.List[ProjectRiskCategory] + source_entity_ids: typing.List[str] + network_paths: typing.List[typing.List[ProjectEntityRiskSummaryNetworkPath]] + metadata: typing.List[typing.Dict[str, typing.List[StringOrNumber]]] + risk_intelligence: typing.List[typing.Dict[str, StringOrNumber]] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity/types/share_information.py b/src/sayari/project_entity/types/share_information.py new file mode 100644 index 00000000..e1b93a3d --- /dev/null +++ b/src/sayari/project_entity/types/share_information.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +import typing +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ShareInformation(UniversalBaseModel): + percentage: typing.Optional[float] = None + num_shares: typing.Optional[int] = None + monetary_value: typing.Optional[int] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity/types/single_project_entity_response.py b/src/sayari/project_entity/types/single_project_entity_response.py index f8319bb0..1f9373e5 100644 --- a/src/sayari/project_entity/types/single_project_entity_response.py +++ b/src/sayari/project_entity/types/single_project_entity_response.py @@ -15,7 +15,7 @@ class SingleProjectEntityResponse(UniversalBaseModel): Address, AttributeValues, BusinessPurpose, - MatchedAttributes, + ProjectEntityMatchExplanation, ProjectEntityMatchResponse, ProjectEntityResponse, ProjectRiskCategory, @@ -36,19 +36,19 @@ class SingleProjectEntityResponse(UniversalBaseModel): created_at="2025-04-22 22:54:00.913586+00", attributes={ "name": AttributeValues( - resolve=True, + match_resolution=True, values=["VTB Bank"], ), "country": AttributeValues( - resolve=True, + match_resolution=True, values=["RUS"], ), "address": AttributeValues( - resolve=True, + match_resolution=True, values=["Moscow"], ), "identifier": AttributeValues( - resolve=True, + match_resolution=True, values=["253400V1H6ART1UQ0N98"], ), }, @@ -141,27 +141,40 @@ class SingleProjectEntityResponse(UniversalBaseModel): sayari_entity_id="dy-rh2g0QtzUN_jC_e9S_A", type="company", label='ОТКРЫТОЕ АКЦИОНЕРНОЕ ОБЩЕСТВО "РОССИЙСКИЕ ЖЕЛЕЗНЫЕ ДОРОГИ"', - matched_attributes=MatchedAttributes( - name=[ - "БАНК ВТБ (ПАО)", - "VTB BANK (PJSC)", - "БАНК ВТБ (ПУБЛИЧНОЕ АКЦИОНЕРНОЕ ОБЩЕСТВО)", - "VTB BANK (PUBLIC JOINT STOCK COMPANY)", - "VTB Bank", - ], - address=[ - "109147 Moscow, st. Vorontsovskaya, 43 building 1", - "119121 Moscow, st. Plyushchikha, 37.", - "Vorontsovskaya Str., 43 Moscow 109044 RUSSIAN FEDERATION", - "37 Plyushchikha ul., Moscow, 119121, Russia", - "Bashnya Zapad, Kompleks Federatsiya, 12, nab. Presnenskaya, Moscow, 123317, Russia", - ], - country=["RUS"], - identifier=[ - "253400V1H6ART1UQ0N98", - "253400V1H6ART1UQ0N98", - ], - ), + match_explanation=[ + ProjectEntityMatchExplanation( + field="name", + quality="high", + matches=[ + "БАНК ВТБ (ПАО)", + "VTB BANK (PJSC)", + "БАНК ВТБ (ПУБЛИЧНОЕ АКЦИОНЕРНОЕ ОБЩЕСТВО)", + "VTB BANK (PUBLIC JOINT STOCK COMPANY)", + "VTB Bank", + ], + ), + ProjectEntityMatchExplanation( + field="address", + quality="medium", + matches=[ + "109147 Moscow, st. Vorontsovskaya, 43 building 1", + "119121 Moscow, st. Plyushchikha, 37.", + "Vorontsovskaya Str., 43 Moscow 109044 RUSSIAN FEDERATION", + "37 Plyushchikha ul., Moscow, 119121, Russia", + "Bashnya Zapad, Kompleks Federatsiya, 12, nab. Presnenskaya, Moscow, 123317, Russia", + ], + ), + ProjectEntityMatchExplanation( + field="country", + quality="high", + matches=["RUS"], + ), + ProjectEntityMatchExplanation( + field="identifier", + quality="high", + matches=["253400V1H6ART1UQ0N98"], + ), + ], countries=[ "USA", "CYP", diff --git a/src/sayari/project_entity_attributes/__init__.py b/src/sayari/project_entity_attributes/__init__.py index 7ba8a944..334bba5a 100644 --- a/src/sayari/project_entity_attributes/__init__.py +++ b/src/sayari/project_entity_attributes/__init__.py @@ -1,12 +1,24 @@ # This file was auto-generated by Fern from our API Definition. from .types import ( + CreateProjectEntityAttributeRequest, + CreateProjectEntityAttributeResponse, + CreateProjectEntityAttributeResponseData, + ProjectEntityAttribute, + ProjectEntityAttributeValue, + ProjectEntityAttributesResponse, UpdateProjectEntityAttributeRequest, UpdateProjectEntityAttributeResponse, UpdateProjectEntityAttributeResponseData, ) __all__ = [ + "CreateProjectEntityAttributeRequest", + "CreateProjectEntityAttributeResponse", + "CreateProjectEntityAttributeResponseData", + "ProjectEntityAttribute", + "ProjectEntityAttributeValue", + "ProjectEntityAttributesResponse", "UpdateProjectEntityAttributeRequest", "UpdateProjectEntityAttributeResponse", "UpdateProjectEntityAttributeResponseData", diff --git a/src/sayari/project_entity_attributes/client.py b/src/sayari/project_entity_attributes/client.py index 7bb2d741..855c2b9f 100644 --- a/src/sayari/project_entity_attributes/client.py +++ b/src/sayari/project_entity_attributes/client.py @@ -2,11 +2,9 @@ import typing from ..core.client_wrapper import SyncClientWrapper -from .types.update_project_entity_attribute_request import UpdateProjectEntityAttributeRequest from ..core.request_options import RequestOptions -from .types.update_project_entity_attribute_response import UpdateProjectEntityAttributeResponse +from .types.project_entity_attributes_response import ProjectEntityAttributesResponse from ..core.jsonable_encoder import jsonable_encoder -from ..core.serialization import convert_and_respect_annotation_metadata from ..core.pydantic_utilities import parse_obj_as from ..shared_errors.errors.bad_request import BadRequest from ..shared_errors.types.bad_request_response import BadRequestResponse @@ -22,6 +20,11 @@ from ..shared_errors.types.internal_server_error_response import InternalServerErrorResponse from json.decoder import JSONDecodeError from ..core.api_error import ApiError +from .types.create_project_entity_attribute_request import CreateProjectEntityAttributeRequest +from .types.create_project_entity_attribute_response import CreateProjectEntityAttributeResponse +from ..core.serialization import convert_and_respect_annotation_metadata +from .types.update_project_entity_attribute_request import UpdateProjectEntityAttributeRequest +from .types.update_project_entity_attribute_response import UpdateProjectEntityAttributeResponse from ..core.client_wrapper import AsyncClientWrapper # this is used as the default value for optional parameters @@ -32,17 +35,127 @@ class ProjectEntityAttributesClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper - def update_project_entity_attribute( + def get_project_entity_attributes( + self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> ProjectEntityAttributesResponse: + """ + Retrieves all attributes for a project entity. + + Parameters + ---------- + project_id : str + + project_entity_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ProjectEntityAttributesResponse + + Examples + -------- + from sayari import Sayari + + client = Sayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + client.project_entity_attributes.get_project_entity_attributes( + project_id="V03eYM", + project_entity_id="BG72YW", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/attributes", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + ProjectEntityAttributesResponse, + parse_obj_as( + type_=ProjectEntityAttributesResponse, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequest( + typing.cast( + BadRequestResponse, + parse_obj_as( + type_=BadRequestResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise Unauthorized( + typing.cast( + UnauthorizedResponse, + parse_obj_as( + type_=UnauthorizedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFound( + typing.cast( + NotFoundResponse, + parse_obj_as( + type_=NotFoundResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 405: + raise MethodNotAllowed( + typing.cast( + MethodNotAllowedResponse, + parse_obj_as( + type_=MethodNotAllowedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise RateLimitExceeded( + typing.cast( + RateLimitResponse, + parse_obj_as( + type_=RateLimitResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + InternalServerErrorResponse, + parse_obj_as( + type_=InternalServerErrorResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + def create_project_entity_attribute( self, project_id: str, project_entity_id: str, - attribute_id: str, *, - request: UpdateProjectEntityAttributeRequest, + request: CreateProjectEntityAttributeRequest, request_options: typing.Optional[RequestOptions] = None, - ) -> UpdateProjectEntityAttributeResponse: + ) -> CreateProjectEntityAttributeResponse: """ - Updates a specific attribute for a project entity. + Creates a new attribute for a project entity. Parameters ---------- @@ -50,42 +163,39 @@ def update_project_entity_attribute( project_entity_id : str - attribute_id : str - - request : UpdateProjectEntityAttributeRequest + request : CreateProjectEntityAttributeRequest request_options : typing.Optional[RequestOptions] Request-specific configuration. Returns ------- - UpdateProjectEntityAttributeResponse + CreateProjectEntityAttributeResponse Examples -------- from sayari import Sayari - from sayari.project_entity_attributes import UpdateProjectEntityAttributeRequest + from sayari.project_entity_attributes import CreateProjectEntityAttributeRequest client = Sayari( client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET", ) - client.project_entity_attributes.update_project_entity_attribute( + client.project_entity_attributes.create_project_entity_attribute( project_id="V03eYM", project_entity_id="BG72YW", - attribute_id="xG8wYP", - request=UpdateProjectEntityAttributeRequest( - field="name", - value="updated name", - match_resolution=True, + request=CreateProjectEntityAttributeRequest( + field="custom_phone", + value="+1-555-123-4567", + match_resolution=False, ), ) """ _response = self._client_wrapper.httpx_client.request( - f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/attributes/{jsonable_encoder(attribute_id)}", - method="PUT", + f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/attributes", + method="POST", json=convert_and_respect_annotation_metadata( - object_=request, annotation=UpdateProjectEntityAttributeRequest, direction="write" + object_=request, annotation=CreateProjectEntityAttributeRequest, direction="write" ), request_options=request_options, omit=OMIT, @@ -93,9 +203,9 @@ def update_project_entity_attribute( try: if 200 <= _response.status_code < 300: return typing.cast( - UpdateProjectEntityAttributeResponse, + CreateProjectEntityAttributeResponse, parse_obj_as( - type_=UpdateProjectEntityAttributeResponse, # type: ignore + type_=CreateProjectEntityAttributeResponse, # type: ignore object_=_response.json(), ), ) @@ -164,12 +274,7 @@ def update_project_entity_attribute( raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) - -class AsyncProjectEntityAttributesClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def update_project_entity_attribute( + def update_project_entity_attribute( self, project_id: str, project_entity_id: str, @@ -200,33 +305,25 @@ async def update_project_entity_attribute( Examples -------- - import asyncio - - from sayari import AsyncSayari + from sayari import Sayari from sayari.project_entity_attributes import UpdateProjectEntityAttributeRequest - client = AsyncSayari( + client = Sayari( client_id="YOUR_CLIENT_ID", client_secret="YOUR_CLIENT_SECRET", ) - - - async def main() -> None: - await client.project_entity_attributes.update_project_entity_attribute( - project_id="V03eYM", - project_entity_id="BG72YW", - attribute_id="xG8wYP", - request=UpdateProjectEntityAttributeRequest( - field="name", - value="updated name", - match_resolution=True, - ), - ) - - - asyncio.run(main()) + client.project_entity_attributes.update_project_entity_attribute( + project_id="V03eYM", + project_entity_id="BG72YW", + attribute_id="xG8wYP", + request=UpdateProjectEntityAttributeRequest( + field="name", + value="updated name", + match_resolution=True, + ), + ) """ - _response = await self._client_wrapper.httpx_client.request( + _response = self._client_wrapper.httpx_client.request( f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/attributes/{jsonable_encoder(attribute_id)}", method="PUT", json=convert_and_respect_annotation_metadata( @@ -308,3 +405,637 @@ async def main() -> None: except JSONDecodeError: raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + + def delete_project_entity_attribute( + self, + project_id: str, + project_entity_id: str, + attribute_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Deletes a specific attribute for a project entity. + + Parameters + ---------- + project_id : str + + project_entity_id : str + + attribute_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from sayari import Sayari + + client = Sayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + client.project_entity_attributes.delete_project_entity_attribute( + project_id="project_id", + project_entity_id="project_entity_id", + attribute_id="attribute_id", + ) + """ + _response = self._client_wrapper.httpx_client.request( + f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/attributes/{jsonable_encoder(attribute_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequest( + typing.cast( + BadRequestResponse, + parse_obj_as( + type_=BadRequestResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise Unauthorized( + typing.cast( + UnauthorizedResponse, + parse_obj_as( + type_=UnauthorizedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFound( + typing.cast( + NotFoundResponse, + parse_obj_as( + type_=NotFoundResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 405: + raise MethodNotAllowed( + typing.cast( + MethodNotAllowedResponse, + parse_obj_as( + type_=MethodNotAllowedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise RateLimitExceeded( + typing.cast( + RateLimitResponse, + parse_obj_as( + type_=RateLimitResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + InternalServerErrorResponse, + parse_obj_as( + type_=InternalServerErrorResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + +class AsyncProjectEntityAttributesClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get_project_entity_attributes( + self, project_id: str, project_entity_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> ProjectEntityAttributesResponse: + """ + Retrieves all attributes for a project entity. + + Parameters + ---------- + project_id : str + + project_entity_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ProjectEntityAttributesResponse + + Examples + -------- + import asyncio + + from sayari import AsyncSayari + + client = AsyncSayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + + + async def main() -> None: + await client.project_entity_attributes.get_project_entity_attributes( + project_id="V03eYM", + project_entity_id="BG72YW", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/attributes", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + ProjectEntityAttributesResponse, + parse_obj_as( + type_=ProjectEntityAttributesResponse, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequest( + typing.cast( + BadRequestResponse, + parse_obj_as( + type_=BadRequestResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise Unauthorized( + typing.cast( + UnauthorizedResponse, + parse_obj_as( + type_=UnauthorizedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFound( + typing.cast( + NotFoundResponse, + parse_obj_as( + type_=NotFoundResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 405: + raise MethodNotAllowed( + typing.cast( + MethodNotAllowedResponse, + parse_obj_as( + type_=MethodNotAllowedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise RateLimitExceeded( + typing.cast( + RateLimitResponse, + parse_obj_as( + type_=RateLimitResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + InternalServerErrorResponse, + parse_obj_as( + type_=InternalServerErrorResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def create_project_entity_attribute( + self, + project_id: str, + project_entity_id: str, + *, + request: CreateProjectEntityAttributeRequest, + request_options: typing.Optional[RequestOptions] = None, + ) -> CreateProjectEntityAttributeResponse: + """ + Creates a new attribute for a project entity. + + Parameters + ---------- + project_id : str + + project_entity_id : str + + request : CreateProjectEntityAttributeRequest + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CreateProjectEntityAttributeResponse + + Examples + -------- + import asyncio + + from sayari import AsyncSayari + from sayari.project_entity_attributes import CreateProjectEntityAttributeRequest + + client = AsyncSayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + + + async def main() -> None: + await client.project_entity_attributes.create_project_entity_attribute( + project_id="V03eYM", + project_entity_id="BG72YW", + request=CreateProjectEntityAttributeRequest( + field="custom_phone", + value="+1-555-123-4567", + match_resolution=False, + ), + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/attributes", + method="POST", + json=convert_and_respect_annotation_metadata( + object_=request, annotation=CreateProjectEntityAttributeRequest, direction="write" + ), + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + CreateProjectEntityAttributeResponse, + parse_obj_as( + type_=CreateProjectEntityAttributeResponse, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequest( + typing.cast( + BadRequestResponse, + parse_obj_as( + type_=BadRequestResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise Unauthorized( + typing.cast( + UnauthorizedResponse, + parse_obj_as( + type_=UnauthorizedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFound( + typing.cast( + NotFoundResponse, + parse_obj_as( + type_=NotFoundResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 405: + raise MethodNotAllowed( + typing.cast( + MethodNotAllowedResponse, + parse_obj_as( + type_=MethodNotAllowedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise RateLimitExceeded( + typing.cast( + RateLimitResponse, + parse_obj_as( + type_=RateLimitResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + InternalServerErrorResponse, + parse_obj_as( + type_=InternalServerErrorResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def update_project_entity_attribute( + self, + project_id: str, + project_entity_id: str, + attribute_id: str, + *, + request: UpdateProjectEntityAttributeRequest, + request_options: typing.Optional[RequestOptions] = None, + ) -> UpdateProjectEntityAttributeResponse: + """ + Updates a specific attribute for a project entity. + + Parameters + ---------- + project_id : str + + project_entity_id : str + + attribute_id : str + + request : UpdateProjectEntityAttributeRequest + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + UpdateProjectEntityAttributeResponse + + Examples + -------- + import asyncio + + from sayari import AsyncSayari + from sayari.project_entity_attributes import UpdateProjectEntityAttributeRequest + + client = AsyncSayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + + + async def main() -> None: + await client.project_entity_attributes.update_project_entity_attribute( + project_id="V03eYM", + project_entity_id="BG72YW", + attribute_id="xG8wYP", + request=UpdateProjectEntityAttributeRequest( + field="name", + value="updated name", + match_resolution=True, + ), + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/attributes/{jsonable_encoder(attribute_id)}", + method="PUT", + json=convert_and_respect_annotation_metadata( + object_=request, annotation=UpdateProjectEntityAttributeRequest, direction="write" + ), + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return typing.cast( + UpdateProjectEntityAttributeResponse, + parse_obj_as( + type_=UpdateProjectEntityAttributeResponse, # type: ignore + object_=_response.json(), + ), + ) + if _response.status_code == 400: + raise BadRequest( + typing.cast( + BadRequestResponse, + parse_obj_as( + type_=BadRequestResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise Unauthorized( + typing.cast( + UnauthorizedResponse, + parse_obj_as( + type_=UnauthorizedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFound( + typing.cast( + NotFoundResponse, + parse_obj_as( + type_=NotFoundResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 405: + raise MethodNotAllowed( + typing.cast( + MethodNotAllowedResponse, + parse_obj_as( + type_=MethodNotAllowedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise RateLimitExceeded( + typing.cast( + RateLimitResponse, + parse_obj_as( + type_=RateLimitResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + InternalServerErrorResponse, + parse_obj_as( + type_=InternalServerErrorResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + + async def delete_project_entity_attribute( + self, + project_id: str, + project_entity_id: str, + attribute_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Deletes a specific attribute for a project entity. + + Parameters + ---------- + project_id : str + + project_entity_id : str + + attribute_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import asyncio + + from sayari import AsyncSayari + + client = AsyncSayari( + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + + + async def main() -> None: + await client.project_entity_attributes.delete_project_entity_attribute( + project_id="project_id", + project_entity_id="project_entity_id", + attribute_id="attribute_id", + ) + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + f"v1/projects/{jsonable_encoder(project_id)}/entities/{jsonable_encoder(project_entity_id)}/attributes/{jsonable_encoder(attribute_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return + if _response.status_code == 400: + raise BadRequest( + typing.cast( + BadRequestResponse, + parse_obj_as( + type_=BadRequestResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 401: + raise Unauthorized( + typing.cast( + UnauthorizedResponse, + parse_obj_as( + type_=UnauthorizedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 404: + raise NotFound( + typing.cast( + NotFoundResponse, + parse_obj_as( + type_=NotFoundResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 405: + raise MethodNotAllowed( + typing.cast( + MethodNotAllowedResponse, + parse_obj_as( + type_=MethodNotAllowedResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 429: + raise RateLimitExceeded( + typing.cast( + RateLimitResponse, + parse_obj_as( + type_=RateLimitResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + if _response.status_code == 500: + raise InternalServerError( + typing.cast( + InternalServerErrorResponse, + parse_obj_as( + type_=InternalServerErrorResponse, # type: ignore + object_=_response.json(), + ), + ) + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/sayari/project_entity_attributes/types/__init__.py b/src/sayari/project_entity_attributes/types/__init__.py index d9b20917..a0329b1c 100644 --- a/src/sayari/project_entity_attributes/types/__init__.py +++ b/src/sayari/project_entity_attributes/types/__init__.py @@ -1,10 +1,22 @@ # This file was auto-generated by Fern from our API Definition. +from .create_project_entity_attribute_request import CreateProjectEntityAttributeRequest +from .create_project_entity_attribute_response import CreateProjectEntityAttributeResponse +from .create_project_entity_attribute_response_data import CreateProjectEntityAttributeResponseData +from .project_entity_attribute import ProjectEntityAttribute +from .project_entity_attribute_value import ProjectEntityAttributeValue +from .project_entity_attributes_response import ProjectEntityAttributesResponse from .update_project_entity_attribute_request import UpdateProjectEntityAttributeRequest from .update_project_entity_attribute_response import UpdateProjectEntityAttributeResponse from .update_project_entity_attribute_response_data import UpdateProjectEntityAttributeResponseData __all__ = [ + "CreateProjectEntityAttributeRequest", + "CreateProjectEntityAttributeResponse", + "CreateProjectEntityAttributeResponseData", + "ProjectEntityAttribute", + "ProjectEntityAttributeValue", + "ProjectEntityAttributesResponse", "UpdateProjectEntityAttributeRequest", "UpdateProjectEntityAttributeResponse", "UpdateProjectEntityAttributeResponseData", diff --git a/src/sayari/project_entity_attributes/types/create_project_entity_attribute_request.py b/src/sayari/project_entity_attributes/types/create_project_entity_attribute_request.py new file mode 100644 index 00000000..9b03897c --- /dev/null +++ b/src/sayari/project_entity_attributes/types/create_project_entity_attribute_request.py @@ -0,0 +1,33 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import typing +import pydantic + + +class CreateProjectEntityAttributeRequest(UniversalBaseModel): + """ + Examples + -------- + from sayari.project_entity_attributes import CreateProjectEntityAttributeRequest + + CreateProjectEntityAttributeRequest( + field="custom_phone", + value="+1-555-123-4567", + match_resolution=False, + ) + """ + + field: str + value: str + match_resolution: bool + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity_attributes/types/create_project_entity_attribute_response.py b/src/sayari/project_entity_attributes/types/create_project_entity_attribute_response.py new file mode 100644 index 00000000..2b0b4445 --- /dev/null +++ b/src/sayari/project_entity_attributes/types/create_project_entity_attribute_response.py @@ -0,0 +1,38 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +from .create_project_entity_attribute_response_data import CreateProjectEntityAttributeResponseData +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import typing +import pydantic + + +class CreateProjectEntityAttributeResponse(UniversalBaseModel): + """ + Examples + -------- + from sayari.project_entity_attributes import ( + CreateProjectEntityAttributeResponse, + CreateProjectEntityAttributeResponseData, + ) + + CreateProjectEntityAttributeResponse( + data=CreateProjectEntityAttributeResponseData( + id="nK9mP2", + field="custom_phone", + value="+1-555-123-4567", + match_resolution=False, + ), + ) + """ + + data: CreateProjectEntityAttributeResponseData + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity_attributes/types/create_project_entity_attribute_response_data.py b/src/sayari/project_entity_attributes/types/create_project_entity_attribute_response_data.py new file mode 100644 index 00000000..ef60e44b --- /dev/null +++ b/src/sayari/project_entity_attributes/types/create_project_entity_attribute_response_data.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import typing +import pydantic + + +class CreateProjectEntityAttributeResponseData(UniversalBaseModel): + id: str + field: str + value: str + match_resolution: bool + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity_attributes/types/project_entity_attribute.py b/src/sayari/project_entity_attributes/types/project_entity_attribute.py new file mode 100644 index 00000000..8ff11b38 --- /dev/null +++ b/src/sayari/project_entity_attributes/types/project_entity_attribute.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +import typing +from .project_entity_attribute_value import ProjectEntityAttributeValue +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ProjectEntityAttribute(UniversalBaseModel): + field: str + match_resolution: bool + values: typing.List[ProjectEntityAttributeValue] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity_attributes/types/project_entity_attribute_value.py b/src/sayari/project_entity_attributes/types/project_entity_attribute_value.py new file mode 100644 index 00000000..f04be680 --- /dev/null +++ b/src/sayari/project_entity_attributes/types/project_entity_attribute_value.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import typing +import pydantic + + +class ProjectEntityAttributeValue(UniversalBaseModel): + id: int + value: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/project_entity_attributes/types/project_entity_attributes_response.py b/src/sayari/project_entity_attributes/types/project_entity_attributes_response.py new file mode 100644 index 00000000..a903d91e --- /dev/null +++ b/src/sayari/project_entity_attributes/types/project_entity_attributes_response.py @@ -0,0 +1,63 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +import typing +from .project_entity_attribute import ProjectEntityAttribute +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class ProjectEntityAttributesResponse(UniversalBaseModel): + """ + Examples + -------- + from sayari.project_entity_attributes import ( + ProjectEntityAttribute, + ProjectEntityAttributesResponse, + ProjectEntityAttributeValue, + ) + + ProjectEntityAttributesResponse( + data=[ + ProjectEntityAttribute( + field="name", + match_resolution=True, + values=[ + ProjectEntityAttributeValue( + id=1, + value="Example Company", + ), + ProjectEntityAttributeValue( + id=2, + value="Updated Company Name", + ), + ], + ), + ProjectEntityAttribute( + field="custom_address", + match_resolution=False, + values=[ + ProjectEntityAttributeValue( + id=3, + value="123 Main Street", + ), + ProjectEntityAttributeValue( + id=4, + value="456 Oak Avenue", + ), + ], + ), + ], + ) + """ + + data: typing.List[ProjectEntityAttribute] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/resolution/client.py b/src/sayari/resolution/client.py index b5a75aca..5c8b6acf 100644 --- a/src/sayari/resolution/client.py +++ b/src/sayari/resolution/client.py @@ -61,6 +61,7 @@ def resolution( cutoff_threshold: typing.Optional[int] = None, candidate_pool_size: typing.Optional[int] = None, skip_post_process: typing.Optional[bool] = None, + enable_llm_clean: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> ResolutionResponse: """ @@ -125,6 +126,9 @@ def resolution( skip_post_process : typing.Optional[bool] Bypasses the post-processing setps and re-ranking. Useful for debugging. By default set to false, set to true to enable. + enable_llm_clean : typing.Optional[bool] + Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -169,6 +173,7 @@ def resolution( "cutoff_threshold": cutoff_threshold, "candidate_pool_size": candidate_pool_size, "skip_post_process": skip_post_process, + "enable_llm_clean": enable_llm_clean, }, request_options=request_options, ) @@ -252,6 +257,7 @@ def resolution_post( request: ResolutionBody, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, + enable_llm_clean: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> ResolutionResponse: """ @@ -267,6 +273,9 @@ def resolution_post( offset : typing.Optional[int] Number of results to skip before returning response. Defaults to 0. + enable_llm_clean : typing.Optional[bool] + Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -298,6 +307,7 @@ def resolution_post( params={ "limit": limit, "offset": offset, + "enable_llm_clean": enable_llm_clean, }, json=convert_and_respect_annotation_metadata(object_=request, annotation=ResolutionBody, direction="write"), request_options=request_options, @@ -663,6 +673,7 @@ async def resolution( cutoff_threshold: typing.Optional[int] = None, candidate_pool_size: typing.Optional[int] = None, skip_post_process: typing.Optional[bool] = None, + enable_llm_clean: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> ResolutionResponse: """ @@ -727,6 +738,9 @@ async def resolution( skip_post_process : typing.Optional[bool] Bypasses the post-processing setps and re-ranking. Useful for debugging. By default set to false, set to true to enable. + enable_llm_clean : typing.Optional[bool] + Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -779,6 +793,7 @@ async def main() -> None: "cutoff_threshold": cutoff_threshold, "candidate_pool_size": candidate_pool_size, "skip_post_process": skip_post_process, + "enable_llm_clean": enable_llm_clean, }, request_options=request_options, ) @@ -862,6 +877,7 @@ async def resolution_post( request: ResolutionBody, limit: typing.Optional[int] = None, offset: typing.Optional[int] = None, + enable_llm_clean: typing.Optional[bool] = None, request_options: typing.Optional[RequestOptions] = None, ) -> ResolutionResponse: """ @@ -877,6 +893,9 @@ async def resolution_post( offset : typing.Optional[int] Number of results to skip before returning response. Defaults to 0. + enable_llm_clean : typing.Optional[bool] + Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -916,6 +935,7 @@ async def main() -> None: params={ "limit": limit, "offset": offset, + "enable_llm_clean": enable_llm_clean, }, json=convert_and_respect_annotation_metadata(object_=request, annotation=ResolutionBody, direction="write"), request_options=request_options, diff --git a/src/sayari/resolution/types/resolution_body.py b/src/sayari/resolution/types/resolution_body.py index 1eb74796..28065dc8 100644 --- a/src/sayari/resolution/types/resolution_body.py +++ b/src/sayari/resolution/types/resolution_body.py @@ -101,6 +101,11 @@ class ResolutionBody(UniversalBaseModel): Bypasses the post-processing setps and re-ranking. Useful for debugging. By default set to false, set to true to enable. """ + enable_llm_clean: typing.Optional[bool] = pydantic.Field(default=None) + """ + Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning. + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/sayari/resolution/types/resolution_upload_body.py b/src/sayari/resolution/types/resolution_upload_body.py index ef902bed..0c926c1f 100644 --- a/src/sayari/resolution/types/resolution_upload_body.py +++ b/src/sayari/resolution/types/resolution_upload_body.py @@ -2,13 +2,18 @@ from ...core.pydantic_utilities import UniversalBaseModel import typing +import pydantic from .resolution_body import ResolutionBody from ...core.pydantic_utilities import IS_PYDANTIC_V2 -import pydantic class ResolutionUploadBody(UniversalBaseModel): filename: str + enable_llm_clean: typing.Optional[bool] = pydantic.Field(default=None) + """ + Whether to enable LLM-based data cleaning to remove noise and standardize entity attributes. Defaults to true if not supplied. Set to false to disable LLM cleaning. + """ + data: typing.List[ResolutionBody] if IS_PYDANTIC_V2: diff --git a/src/sayari/shared_errors/__init__.py b/src/sayari/shared_errors/__init__.py index 310de7ba..ca889f62 100644 --- a/src/sayari/shared_errors/__init__.py +++ b/src/sayari/shared_errors/__init__.py @@ -10,6 +10,7 @@ NotFoundResponse, RateLimitResponse, UnauthorizedResponse, + UnprocessableContentResponse, ) from .errors import ( BadGateway, @@ -21,6 +22,7 @@ NotFound, RateLimitExceeded, Unauthorized, + UnprocessableContent, ) __all__ = [ @@ -42,4 +44,6 @@ "RateLimitResponse", "Unauthorized", "UnauthorizedResponse", + "UnprocessableContent", + "UnprocessableContentResponse", ] diff --git a/src/sayari/shared_errors/errors/__init__.py b/src/sayari/shared_errors/errors/__init__.py index ba318ef4..fd0c66cb 100644 --- a/src/sayari/shared_errors/errors/__init__.py +++ b/src/sayari/shared_errors/errors/__init__.py @@ -9,6 +9,7 @@ from .not_found import NotFound from .rate_limit_exceeded import RateLimitExceeded from .unauthorized import Unauthorized +from .unprocessable_content import UnprocessableContent __all__ = [ "BadGateway", @@ -20,4 +21,5 @@ "NotFound", "RateLimitExceeded", "Unauthorized", + "UnprocessableContent", ] diff --git a/src/sayari/shared_errors/errors/unprocessable_content.py b/src/sayari/shared_errors/errors/unprocessable_content.py new file mode 100644 index 00000000..be24d344 --- /dev/null +++ b/src/sayari/shared_errors/errors/unprocessable_content.py @@ -0,0 +1,9 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.api_error import ApiError +from ..types.unprocessable_content_response import UnprocessableContentResponse + + +class UnprocessableContent(ApiError): + def __init__(self, body: UnprocessableContentResponse): + super().__init__(status_code=422, body=body) diff --git a/src/sayari/shared_errors/types/__init__.py b/src/sayari/shared_errors/types/__init__.py index 3e32c428..c0934f97 100644 --- a/src/sayari/shared_errors/types/__init__.py +++ b/src/sayari/shared_errors/types/__init__.py @@ -9,6 +9,7 @@ from .not_found_response import NotFoundResponse from .rate_limit_response import RateLimitResponse from .unauthorized_response import UnauthorizedResponse +from .unprocessable_content_response import UnprocessableContentResponse __all__ = [ "BadGatewayResponse", @@ -20,4 +21,5 @@ "NotFoundResponse", "RateLimitResponse", "UnauthorizedResponse", + "UnprocessableContentResponse", ] diff --git a/src/sayari/shared_errors/types/not_acceptable_response.py b/src/sayari/shared_errors/types/not_acceptable_response.py index 9ab699e1..df3f90eb 100644 --- a/src/sayari/shared_errors/types/not_acceptable_response.py +++ b/src/sayari/shared_errors/types/not_acceptable_response.py @@ -8,7 +8,7 @@ class NotAcceptableResponse(UniversalBaseModel): """ - Request made in an unacceptable state. This is most commonly due to parameter validation errors. + Request made in an unacceptable state due to an invalid Accept header. """ status: int diff --git a/src/sayari/shared_errors/types/unprocessable_content_response.py b/src/sayari/shared_errors/types/unprocessable_content_response.py new file mode 100644 index 00000000..14d0232a --- /dev/null +++ b/src/sayari/shared_errors/types/unprocessable_content_response.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +from ...core.pydantic_utilities import UniversalBaseModel +import typing +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +import pydantic + + +class UnprocessableContentResponse(UniversalBaseModel): + """ + Request made with an invalid body. This is most commonly due to parameter validation errors. + """ + + status: int + message: typing.List[str] + success: bool + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/sayari/shared_types/__init__.py b/src/sayari/shared_types/__init__.py index 0e6e7ec2..1a2063e3 100644 --- a/src/sayari/shared_types/__init__.py +++ b/src/sayari/shared_types/__init__.py @@ -1,6 +1,7 @@ # This file was auto-generated by Fern from our API Definition. from .types import ( + CaseStatus, ClientName, CompanyType, Coordinate, @@ -15,6 +16,8 @@ EntitySummary, EntityTranslatedLabel, Identifier, + MatchCount, + MatchStrengthEnum, PossiblySameAs, PossiblySameAsData, PossiblySameAsMatch, @@ -39,6 +42,7 @@ ) __all__ = [ + "CaseStatus", "ClientName", "CompanyType", "Coordinate", @@ -53,6 +57,8 @@ "EntitySummary", "EntityTranslatedLabel", "Identifier", + "MatchCount", + "MatchStrengthEnum", "PossiblySameAs", "PossiblySameAsData", "PossiblySameAsMatch", diff --git a/src/sayari/shared_types/types/__init__.py b/src/sayari/shared_types/types/__init__.py index be46eeed..f93f2ae6 100644 --- a/src/sayari/shared_types/types/__init__.py +++ b/src/sayari/shared_types/types/__init__.py @@ -1,5 +1,6 @@ # This file was auto-generated by Fern from our API Definition. +from .case_status import CaseStatus from .client_name import ClientName from .company_type import CompanyType from .coordinate import Coordinate @@ -14,6 +15,8 @@ from .entity_summary import EntitySummary from .entity_translated_label import EntityTranslatedLabel from .identifier import Identifier +from .match_count import MatchCount +from .match_strength_enum import MatchStrengthEnum from .possibly_same_as import PossiblySameAs from .possibly_same_as_data import PossiblySameAsData from .possibly_same_as_match import PossiblySameAsMatch @@ -37,6 +40,7 @@ from .status import Status __all__ = [ + "CaseStatus", "ClientName", "CompanyType", "Coordinate", @@ -51,6 +55,8 @@ "EntitySummary", "EntityTranslatedLabel", "Identifier", + "MatchCount", + "MatchStrengthEnum", "PossiblySameAs", "PossiblySameAsData", "PossiblySameAsMatch", diff --git a/src/sayari/project_entity/types/case_status.py b/src/sayari/shared_types/types/case_status.py similarity index 100% rename from src/sayari/project_entity/types/case_status.py rename to src/sayari/shared_types/types/case_status.py diff --git a/src/sayari/project_entity/types/match_count.py b/src/sayari/shared_types/types/match_count.py similarity index 100% rename from src/sayari/project_entity/types/match_count.py rename to src/sayari/shared_types/types/match_count.py diff --git a/src/sayari/project_entity/types/match_strength_enum.py b/src/sayari/shared_types/types/match_strength_enum.py similarity index 100% rename from src/sayari/project_entity/types/match_strength_enum.py rename to src/sayari/shared_types/types/match_strength_enum.py diff --git a/src/sayari/source/__init__.py b/src/sayari/source/__init__.py deleted file mode 100644 index 9574a002..00000000 --- a/src/sayari/source/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import GetSourceResponse, ListSourcesResponse, Source - -__all__ = ["GetSourceResponse", "ListSourcesResponse", "Source"] diff --git a/src/sayari/source/client.py b/src/sayari/source/client.py deleted file mode 100644 index 98142e80..00000000 --- a/src/sayari/source/client.py +++ /dev/null @@ -1,486 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ..core.client_wrapper import SyncClientWrapper -import typing -from ..core.request_options import RequestOptions -from .types.list_sources_response import ListSourcesResponse -from ..core.pydantic_utilities import parse_obj_as -from ..shared_errors.errors.bad_request import BadRequest -from ..shared_errors.types.bad_request_response import BadRequestResponse -from ..shared_errors.errors.unauthorized import Unauthorized -from ..shared_errors.types.unauthorized_response import UnauthorizedResponse -from ..shared_errors.errors.method_not_allowed import MethodNotAllowed -from ..shared_errors.types.method_not_allowed_response import MethodNotAllowedResponse -from ..shared_errors.errors.rate_limit_exceeded import RateLimitExceeded -from ..shared_errors.types.rate_limit_response import RateLimitResponse -from ..shared_errors.errors.internal_server_error import InternalServerError -from ..shared_errors.types.internal_server_error_response import InternalServerErrorResponse -from json.decoder import JSONDecodeError -from ..core.api_error import ApiError -from .types.get_source_response import GetSourceResponse -from ..core.jsonable_encoder import jsonable_encoder -from ..shared_errors.errors.not_found import NotFound -from ..shared_errors.types.not_found_response import NotFoundResponse -from ..core.client_wrapper import AsyncClientWrapper - - -class SourceClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def list_sources( - self, - *, - limit: typing.Optional[int] = None, - offset: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> ListSourcesResponse: - """ - This endpoint is deprecated. Use /v1/ontology/sources instead. Returns metadata for all sources that Sayari collects data from - - Parameters - ---------- - limit : typing.Optional[int] - A limit on the number of objects to be returned with a range between 1 and 100. Defaults to 100. - - offset : typing.Optional[int] - Number of results to skip before returning response. Defaults to 0. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListSourcesResponse - - Examples - -------- - from sayari import Sayari - - client = Sayari( - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", - ) - client.source.list_sources( - limit=2, - ) - """ - _response = self._client_wrapper.httpx_client.request( - "v1/sources", - method="GET", - params={ - "limit": limit, - "offset": offset, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListSourcesResponse, - parse_obj_as( - type_=ListSourcesResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequest( - typing.cast( - BadRequestResponse, - parse_obj_as( - type_=BadRequestResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise Unauthorized( - typing.cast( - UnauthorizedResponse, - parse_obj_as( - type_=UnauthorizedResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 405: - raise MethodNotAllowed( - typing.cast( - MethodNotAllowedResponse, - parse_obj_as( - type_=MethodNotAllowedResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 429: - raise RateLimitExceeded( - typing.cast( - RateLimitResponse, - parse_obj_as( - type_=RateLimitResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 500: - raise InternalServerError( - typing.cast( - InternalServerErrorResponse, - parse_obj_as( - type_=InternalServerErrorResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_source(self, id: str, *, request_options: typing.Optional[RequestOptions] = None) -> GetSourceResponse: - """ - This endpoint is deprecated. Use /v1/ontology/sources instead. Returns metadata for a source that Sayari collects data from - - Parameters - ---------- - id : str - The unique identifier for a source in the database - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetSourceResponse - - Examples - -------- - from sayari import Sayari - - client = Sayari( - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", - ) - client.source.get_source( - id="f4396e4b8a41d1fd9f09ea94d2ebedb9", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"v1/source/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - GetSourceResponse, - parse_obj_as( - type_=GetSourceResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequest( - typing.cast( - BadRequestResponse, - parse_obj_as( - type_=BadRequestResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise Unauthorized( - typing.cast( - UnauthorizedResponse, - parse_obj_as( - type_=UnauthorizedResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFound( - typing.cast( - NotFoundResponse, - parse_obj_as( - type_=NotFoundResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 405: - raise MethodNotAllowed( - typing.cast( - MethodNotAllowedResponse, - parse_obj_as( - type_=MethodNotAllowedResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 429: - raise RateLimitExceeded( - typing.cast( - RateLimitResponse, - parse_obj_as( - type_=RateLimitResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 500: - raise InternalServerError( - typing.cast( - InternalServerErrorResponse, - parse_obj_as( - type_=InternalServerErrorResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncSourceClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list_sources( - self, - *, - limit: typing.Optional[int] = None, - offset: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> ListSourcesResponse: - """ - This endpoint is deprecated. Use /v1/ontology/sources instead. Returns metadata for all sources that Sayari collects data from - - Parameters - ---------- - limit : typing.Optional[int] - A limit on the number of objects to be returned with a range between 1 and 100. Defaults to 100. - - offset : typing.Optional[int] - Number of results to skip before returning response. Defaults to 0. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ListSourcesResponse - - Examples - -------- - import asyncio - - from sayari import AsyncSayari - - client = AsyncSayari( - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", - ) - - - async def main() -> None: - await client.source.list_sources( - limit=2, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "v1/sources", - method="GET", - params={ - "limit": limit, - "offset": offset, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - ListSourcesResponse, - parse_obj_as( - type_=ListSourcesResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequest( - typing.cast( - BadRequestResponse, - parse_obj_as( - type_=BadRequestResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise Unauthorized( - typing.cast( - UnauthorizedResponse, - parse_obj_as( - type_=UnauthorizedResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 405: - raise MethodNotAllowed( - typing.cast( - MethodNotAllowedResponse, - parse_obj_as( - type_=MethodNotAllowedResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 429: - raise RateLimitExceeded( - typing.cast( - RateLimitResponse, - parse_obj_as( - type_=RateLimitResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 500: - raise InternalServerError( - typing.cast( - InternalServerErrorResponse, - parse_obj_as( - type_=InternalServerErrorResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_source( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> GetSourceResponse: - """ - This endpoint is deprecated. Use /v1/ontology/sources instead. Returns metadata for a source that Sayari collects data from - - Parameters - ---------- - id : str - The unique identifier for a source in the database - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetSourceResponse - - Examples - -------- - import asyncio - - from sayari import AsyncSayari - - client = AsyncSayari( - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", - ) - - - async def main() -> None: - await client.source.get_source( - id="f4396e4b8a41d1fd9f09ea94d2ebedb9", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"v1/source/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return typing.cast( - GetSourceResponse, - parse_obj_as( - type_=GetSourceResponse, # type: ignore - object_=_response.json(), - ), - ) - if _response.status_code == 400: - raise BadRequest( - typing.cast( - BadRequestResponse, - parse_obj_as( - type_=BadRequestResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 401: - raise Unauthorized( - typing.cast( - UnauthorizedResponse, - parse_obj_as( - type_=UnauthorizedResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 404: - raise NotFound( - typing.cast( - NotFoundResponse, - parse_obj_as( - type_=NotFoundResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 405: - raise MethodNotAllowed( - typing.cast( - MethodNotAllowedResponse, - parse_obj_as( - type_=MethodNotAllowedResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 429: - raise RateLimitExceeded( - typing.cast( - RateLimitResponse, - parse_obj_as( - type_=RateLimitResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - if _response.status_code == 500: - raise InternalServerError( - typing.cast( - InternalServerErrorResponse, - parse_obj_as( - type_=InternalServerErrorResponse, # type: ignore - object_=_response.json(), - ), - ) - ) - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/src/sayari/source/types/__init__.py b/src/sayari/source/types/__init__.py deleted file mode 100644 index e3b8d430..00000000 --- a/src/sayari/source/types/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .get_source_response import GetSourceResponse -from .list_sources_response import ListSourcesResponse -from .source import Source - -__all__ = ["GetSourceResponse", "ListSourcesResponse", "Source"] diff --git a/src/sayari/source/types/get_source_response.py b/src/sayari/source/types/get_source_response.py deleted file mode 100644 index c6db7080..00000000 --- a/src/sayari/source/types/get_source_response.py +++ /dev/null @@ -1,40 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .source import Source -from ...core.pydantic_utilities import IS_PYDANTIC_V2 -import typing -import pydantic - - -class GetSourceResponse(Source): - """ - OK - - Examples - -------- - from sayari.source import GetSourceResponse - - GetSourceResponse( - id="f4396e4b8a41d1fd9f09ea94d2ebedb9", - label="UAE Abu Dhabi Global Market Corporate Registry", - description="Contains profiles of registered companies. Provides standard company information including name, tax ID, status, address, and business purpose as well as current and former shareholders and directors.", - country="ARE", - region="middle_east_&_africa", - date_added="2022-07-25", - source_type="company_data", - record_type="company_record", - structure="structured", - source_url="https://www.adgm.com/public-registers", - pep=False, - watchlist=False, - ) - """ - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/sayari/source/types/list_sources_response.py b/src/sayari/source/types/list_sources_response.py deleted file mode 100644 index ae84ad88..00000000 --- a/src/sayari/source/types/list_sources_response.py +++ /dev/null @@ -1,71 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ...base_types.types.paginated_response import PaginatedResponse -import typing -from .source import Source -from ...core.pydantic_utilities import IS_PYDANTIC_V2 -import pydantic - - -class ListSourcesResponse(PaginatedResponse): - """ - OK - - Examples - -------- - from sayari.base_types import QualifiedCount - from sayari.source import ListSourcesResponse, Source - - ListSourcesResponse( - offset=0, - limit=2, - size=QualifiedCount( - count=547, - qualifier="eq", - ), - next=True, - data=[ - Source( - id="e85d865943ee6d8369307569d2ad9de0", - label="Acuris Risk Intelligence Adverse Media Data", - description="Contains PDFs and URLs to adverse media reporting for PEPs, SOEs, sanctioned entities, and entities linked to financial regulatory and law enforcement actions. Available for millions of entities from 'Acuris Risk Intelligence KYC6 (3rd Party Data)' in 'Records' section.", - country="XXX", - region="international_(multi-region_coverage)", - date_added="2022-04-11", - source_type="adverse_media_/_negative_news_data", - record_type="adverse_media_record", - structure="unstructured", - source_url="https://www.acurisriskintelligence.com/", - pep=False, - watchlist=False, - ), - Source( - id="a8c6ee1cd4dfc952105ee8c0e4836f08", - label="Acuris Risk Intelligence KYC6 (3rd Party Data)", - description="Contains profiles of PEPs, sanctioned entities, SOEs, and entities linked to financial regulatory and law enforcement actions from hundreds of international watchlists. Provides identifying information on individuals and companies as available.", - country="XXX", - region="international_(multi-region_coverage)", - date_added="2022-02-09", - source_type="risk_intelligence_data", - record_type="risk_intelligence_record", - structure="unstructured", - source_url="https://www.acurisriskintelligence.com/", - pep=False, - watchlist=False, - ), - ], - ) - """ - - offset: int - next: bool - data: typing.List[Source] - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow diff --git a/src/sayari/trade/client.py b/src/sayari/trade/client.py index bd42a15c..82213ab5 100644 --- a/src/sayari/trade/client.py +++ b/src/sayari/trade/client.py @@ -47,7 +47,7 @@ def search_shipments( Parameters ---------- limit : typing.Optional[int] - A limit on the number of objects to be returned with a range between 1 and 10000. Defaults to 100. + A limit on the number of objects to be returned with a range between 1 and 3000. Defaults to 100. offset : typing.Optional[int] Number of results to skip before returning response. Defaults to 0. @@ -83,7 +83,7 @@ def search_shipments( departure_country=["DEU"], arrival_country=["RUS"], hs_code=["854231"], - arrival_date=["2024-01 TO 2024-10"], + arrival_date="2024-01|2024-10", ), ) """ @@ -184,7 +184,7 @@ def search_suppliers( Parameters ---------- limit : typing.Optional[int] - A limit on the number of objects to be returned with a range between 1 and 10000. Defaults to 100. + A limit on the number of objects to be returned with a range between 1 and 3000. Defaults to 100. offset : typing.Optional[int] Number of results to skip before returning response. Defaults to 0. @@ -220,7 +220,7 @@ def search_suppliers( departure_country=["DEU"], arrival_country=["RUS"], hs_code=["854231"], - arrival_date=["2024-01 TO 2024-10"], + arrival_date="2024-01|2024-10", ), ) """ @@ -321,7 +321,7 @@ def search_buyers( Parameters ---------- limit : typing.Optional[int] - A limit on the number of objects to be returned with a range between 1 and 10000. Defaults to 100. + A limit on the number of objects to be returned with a range between 1 and 3000. Defaults to 100. offset : typing.Optional[int] Number of results to skip before returning response. Defaults to 0. @@ -357,7 +357,7 @@ def search_buyers( departure_country=["DEU"], arrival_country=["RUS"], hs_code=["854231"], - arrival_date=["2024-01 TO 2024-10"], + arrival_date="2024-01|2024-10", ), ) """ @@ -463,7 +463,7 @@ async def search_shipments( Parameters ---------- limit : typing.Optional[int] - A limit on the number of objects to be returned with a range between 1 and 10000. Defaults to 100. + A limit on the number of objects to be returned with a range between 1 and 3000. Defaults to 100. offset : typing.Optional[int] Number of results to skip before returning response. Defaults to 0. @@ -504,7 +504,7 @@ async def main() -> None: departure_country=["DEU"], arrival_country=["RUS"], hs_code=["854231"], - arrival_date=["2024-01 TO 2024-10"], + arrival_date="2024-01|2024-10", ), ) @@ -608,7 +608,7 @@ async def search_suppliers( Parameters ---------- limit : typing.Optional[int] - A limit on the number of objects to be returned with a range between 1 and 10000. Defaults to 100. + A limit on the number of objects to be returned with a range between 1 and 3000. Defaults to 100. offset : typing.Optional[int] Number of results to skip before returning response. Defaults to 0. @@ -649,7 +649,7 @@ async def main() -> None: departure_country=["DEU"], arrival_country=["RUS"], hs_code=["854231"], - arrival_date=["2024-01 TO 2024-10"], + arrival_date="2024-01|2024-10", ), ) @@ -753,7 +753,7 @@ async def search_buyers( Parameters ---------- limit : typing.Optional[int] - A limit on the number of objects to be returned with a range between 1 and 10000. Defaults to 100. + A limit on the number of objects to be returned with a range between 1 and 3000. Defaults to 100. offset : typing.Optional[int] Number of results to skip before returning response. Defaults to 0. @@ -794,7 +794,7 @@ async def main() -> None: departure_country=["DEU"], arrival_country=["RUS"], hs_code=["854231"], - arrival_date=["2024-01 TO 2024-10"], + arrival_date="2024-01|2024-10", ), ) diff --git a/src/sayari/trade/types/trade_filter_list.py b/src/sayari/trade/types/trade_filter_list.py index fc4e225b..64a6d5f7 100644 --- a/src/sayari/trade/types/trade_filter_list.py +++ b/src/sayari/trade/types/trade_filter_list.py @@ -128,16 +128,18 @@ class TradeFilterList(UniversalBaseModel): The buyer purpose contains the provided string. """ - arrival_date: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + arrival_date: typing.Optional[str] = pydantic.Field(default=None) """ The arrival date is within the provided range. Supports exact dates (YYYY-MM-DD) - or date ranges (YYYY-MM TO YYYY-MM). Example: ["2024-01 TO 2024-10"] or ["2024-01-30"]. + or date ranges (YYYY-MM | YYYY-MM). If an exact date is used it will be treated as the minimum date, with no maximum date specified. + Example: "2024-01|2024-10" or "2024-01-30". """ - departure_date: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + departure_date: typing.Optional[str] = pydantic.Field(default=None) """ The departure date is within the provided range. Supports exact dates (YYYY-MM-DD) - or date ranges (YYYY-MM TO YYYY-MM). Example: ["2024-01 TO 2024-10"] or ["2024-01-30"]. + If an exact date is used it will be treated as the minimum date, with no maximum date specified. + or date ranges (YYYY-MM | YYYY-MM). Example: "2024-01|2024-10" or "2024-01-30". """ shipment_identifier: typing.Optional[typing.List[str]] = pydantic.Field(default=None)