ingestr 0.13.27__py3-none-any.whl → 0.13.29__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ingestr might be problematic. Click here for more details.

ingestr/main.py CHANGED
@@ -302,6 +302,13 @@ def ingest(
302
302
  envvar=["COLUMNS", "INGESTR_COLUMNS"],
303
303
  ),
304
304
  ] = None, # type: ignore
305
+ yield_limit: Annotated[
306
+ Optional[int],
307
+ typer.Option(
308
+ help="Limit the number of pages yielded from the source",
309
+ envvar=["YIELD_LIMIT", "INGESTR_YIELD_LIMIT"],
310
+ ),
311
+ ] = None, # type: ignore
305
312
  ):
306
313
  import hashlib
307
314
  import tempfile
@@ -556,6 +563,9 @@ def ingest(
556
563
  if factory.source_scheme.startswith("mysql"):
557
564
  resource.for_each(dlt_source, lambda x: x.add_map(handle_mysql_empty_dates))
558
565
 
566
+ if yield_limit:
567
+ resource.for_each(dlt_source, lambda x: x.add_limit(yield_limit))
568
+
559
569
  def col_h(x):
560
570
  if column_hints:
561
571
  x.apply_hints(columns=column_hints)
ingestr/src/buildinfo.py CHANGED
@@ -1 +1 @@
1
- version = "v0.13.27"
1
+ version = "v0.13.29"
@@ -56,6 +56,7 @@ def hubspot(
56
56
  api_key: str = dlt.secrets.value,
57
57
  include_history: bool = False,
58
58
  include_custom_props: bool = True,
59
+ custom_object: str = None,
59
60
  ) -> Sequence[DltResource]:
60
61
  """
61
62
  A DLT source that retrieves data from the HubSpot API using the
@@ -162,13 +163,13 @@ def hubspot(
162
163
  props,
163
164
  include_custom_props,
164
165
  )
165
-
166
+
166
167
  @dlt.resource(name="schemas", write_disposition="merge", primary_key="id")
167
168
  def schemas(
168
169
  api_key: str = api_key,
169
170
  ) -> Iterator[TDataItems]:
170
171
  """Hubspot schemas resource"""
171
- yield from fetch_data(CRM_SCHEMAS_ENDPOINT, api_key)
172
+ yield from fetch_data(CRM_SCHEMAS_ENDPOINT, api_key, resource_name="schemas")
172
173
 
173
174
  @dlt.resource(name="quotes", write_disposition="replace")
174
175
  def quotes(
@@ -186,7 +187,33 @@ def hubspot(
186
187
  include_custom_props,
187
188
  )
188
189
 
189
- return companies, contacts, deals, tickets, products, quotes, schemas
190
+ @dlt.resource(write_disposition="merge", primary_key="hs_object_id")
191
+ def custom(
192
+ api_key: str = api_key,
193
+ custom_object_name: str = custom_object,
194
+ ) -> Iterator[TDataItems]:
195
+ get_custom_object = schemas(api_key)
196
+ object_type_id = None
197
+ for custom_object in get_custom_object:
198
+ if custom_object["name"] == custom_object_name.capitalize():
199
+ object_type_id = custom_object["objectTypeId"]
200
+ break
201
+ if object_type_id is None:
202
+ raise ValueError(f"There is no such custom object as {custom_object_name}")
203
+ custom_object_properties = f"crm/v3/properties/{object_type_id}"
204
+
205
+ props_pages = fetch_data(custom_object_properties, api_key)
206
+ props = []
207
+ for page in props_pages:
208
+ props.extend([prop["name"] for prop in page])
209
+ props = ",".join(sorted(list(set(props))))
210
+
211
+ custom_object_endpoint = f"crm/v3/objects/{object_type_id}/?properties={props}"
212
+
213
+ """Hubspot custom object details resource"""
214
+ yield from fetch_data(custom_object_endpoint, api_key, resource_name="custom")
215
+
216
+ return companies, contacts, deals, tickets, products, quotes, schemas, custom
190
217
 
191
218
 
192
219
  def crm_objects(
@@ -90,7 +90,10 @@ def fetch_property_history(
90
90
 
91
91
 
92
92
  def fetch_data(
93
- endpoint: str, api_key: str, params: Optional[Dict[str, Any]] = None
93
+ endpoint: str,
94
+ api_key: str,
95
+ params: Optional[Dict[str, Any]] = None,
96
+ resource_name: str = None,
94
97
  ) -> Iterator[List[Dict[str, Any]]]:
95
98
  """
96
99
  Fetch data from HUBSPOT endpoint using a specified API key and yield the properties of each result.
@@ -132,16 +135,22 @@ def fetch_data(
132
135
  if "results" in _data:
133
136
  _objects: List[Dict[str, Any]] = []
134
137
  for _result in _data["results"]:
135
- if endpoint == "/crm/v3/schemas":
136
- _objects.append({
137
- "name": _result["labels"].get("singular", ""),
138
- "objectTypeId": _result.get("objectTypeId", ""),
139
- "id": _result.get("id", ""),
140
- "fullyQualifiedName": _result.get("fullyQualifiedName", ""),
141
- "properties": _result.get("properties", ""),
142
- "createdAt": _result.get("createdAt", ""),
143
- "updatedAt": _result.get("updatedAt", "")
144
- })
138
+ if resource_name == "schemas":
139
+ _objects.append(
140
+ {
141
+ "name": _result["labels"].get("singular", ""),
142
+ "objectTypeId": _result.get("objectTypeId", ""),
143
+ "id": _result.get("id", ""),
144
+ "fullyQualifiedName": _result.get("fullyQualifiedName", ""),
145
+ "properties": _result.get("properties", ""),
146
+ "createdAt": _result.get("createdAt", ""),
147
+ "updatedAt": _result.get("updatedAt", ""),
148
+ }
149
+ )
150
+ elif resource_name == "custom":
151
+ _objects.append(
152
+ _result.get("properties", ""),
153
+ )
145
154
  else:
146
155
  _obj = _result.get("properties", _result)
147
156
  if "id" not in _obj and "id" in _result:
@@ -153,9 +162,11 @@ def fetch_data(
153
162
  {
154
163
  "value": _obj["hs_object_id"],
155
164
  f"{association}_id": __r["id"],
156
- }
157
- for __r in _result["associations"][association]["results"]
158
- ]
165
+ }
166
+ for __r in _result["associations"][association][
167
+ "results"
168
+ ]
169
+ ]
159
170
 
160
171
  # remove duplicates from list of dicts
161
172
  __values = [
@@ -5,15 +5,21 @@ from dlt.common import pendulum
5
5
  STARTDATE = pendulum.datetime(year=2000, month=1, day=1)
6
6
 
7
7
  CRM_CONTACTS_ENDPOINT = (
8
- "/crm/v3/objects/contacts?associations=deals,products,tickets,quotes"
8
+ "/crm/v3/objects/contacts?associations=companies,deals,products,tickets,quotes"
9
9
  )
10
- CRM_COMPANIES_ENDPOINT = (
11
- "/crm/v3/objects/companies?associations=contacts,deals,products,tickets,quotes"
10
+ CRM_COMPANIES_ENDPOINT = "/crm/v3/objects/companies?associations=products"
11
+ CRM_DEALS_ENDPOINT = (
12
+ "/crm/v3/objects/deals?associations=companies,contacts,products,tickets,quotes"
13
+ )
14
+ CRM_PRODUCTS_ENDPOINT = (
15
+ "/crm/v3/objects/products?associations=companies,contacts,deals,tickets,quotes"
16
+ )
17
+ CRM_TICKETS_ENDPOINT = (
18
+ "/crm/v3/objects/tickets?associations=companies,contacts,deals,products,quotes"
19
+ )
20
+ CRM_QUOTES_ENDPOINT = (
21
+ "/crm/v3/objects/quotes?associations=companies,contacts,deals,products,tickets"
12
22
  )
13
- CRM_DEALS_ENDPOINT = "/crm/v3/objects/deals"
14
- CRM_PRODUCTS_ENDPOINT = "/crm/v3/objects/products"
15
- CRM_TICKETS_ENDPOINT = "/crm/v3/objects/tickets"
16
- CRM_QUOTES_ENDPOINT = "/crm/v3/objects/quotes"
17
23
  CRM_SCHEMAS_ENDPOINT = "/crm/v3/schemas"
18
24
 
19
25
  CRM_OBJECT_ENDPOINTS = {
ingestr/src/sources.py CHANGED
@@ -803,7 +803,20 @@ class HubspotSource:
803
803
  raise ValueError("api_key in the URI is required to connect to Hubspot")
804
804
 
805
805
  endpoint = None
806
- if table in ["contacts", "companies", "deals", "tickets", "products", "quotes", "schemas"]:
806
+
807
+ if table.startswith("custom:"):
808
+ fields = table.split(":", 2)
809
+ if len(fields) != 2:
810
+ raise ValueError(
811
+ "Invalid Hubspot custom table format. Expected format: custom:<custom_object_type>"
812
+ )
813
+ endpoint = fields[1]
814
+ return hubspot(
815
+ api_key=api_key[0],
816
+ custom_object=endpoint,
817
+ ).with_resources("custom")
818
+
819
+ elif table in ["contacts", "companies", "deals", "tickets", "products", "quotes", "schemas"]:
807
820
  endpoint = table
808
821
  else:
809
822
  raise ValueError(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ingestr
3
- Version: 0.13.27
3
+ Version: 0.13.29
4
4
  Summary: ingestr is a command-line application that ingests data from various sources and stores them in any database.
5
5
  Project-URL: Homepage, https://github.com/bruin-data/ingestr
6
6
  Project-URL: Issues, https://github.com/bruin-data/ingestr/issues
@@ -1,8 +1,8 @@
1
1
  ingestr/conftest.py,sha256=Q03FIJIZpLBbpj55cfCHIKEjc1FCvWJhMF2cidUJKQU,1748
2
- ingestr/main.py,sha256=wvbRCJ2--M0Zw2cYtSH874TxTtlD0wadHREeLG3anOY,25618
2
+ ingestr/main.py,sha256=Vt5NFN59BUlkYrOwiF9xF5MCFYp9r-aVSnQ99f1ypRE,25964
3
3
  ingestr/src/.gitignore,sha256=8cX1AZTSI0TcdZFGTmS_oyBjpfCzhOEt0DdAo2dFIY8,203
4
4
  ingestr/src/blob.py,sha256=onMe5ZHxPXTdcB_s2oGNdMo-XQJ3ajwOsWE9eSTGFmc,1495
5
- ingestr/src/buildinfo.py,sha256=KAR_TXhR11JwQNb01TN64yrPzC6Xv6G-HVq71tG_n90,21
5
+ ingestr/src/buildinfo.py,sha256=fraAO4VHAeBDwo-MJW7EhZKMHMio-7qqLE2lULqrTHA,21
6
6
  ingestr/src/destinations.py,sha256=vrGij4qMPCdXTMIimROWBJFqzOqCM4DFmgyubgSHejA,11279
7
7
  ingestr/src/errors.py,sha256=Ufs4_DfE77_E3vnA1fOQdi6cmuLVNm7_SbFLkL1XPGk,686
8
8
  ingestr/src/factory.py,sha256=659h_sVRBhtPv2dvtOK8tf3PtUhlK3KsWLrb20_iQKw,5333
@@ -10,7 +10,7 @@ ingestr/src/filters.py,sha256=5LNpBgm8FJXdrFHGyM7dLVyphKykSpPk7yuQAZ8GML4,1133
10
10
  ingestr/src/loader.py,sha256=9NaWAyfkXdqAZSS-N72Iwo36Lbx4PyqIfaaH1dNdkFs,1712
11
11
  ingestr/src/partition.py,sha256=E0WHqh1FTheQAIVK_-jWUx0dgyYZCD1VxlAm362gao4,964
12
12
  ingestr/src/resource.py,sha256=XG-sbBapFVEM7OhHQFQRTdTLlh-mHB-N4V1t8F8Tsww,543
13
- ingestr/src/sources.py,sha256=Zmjg3pDsCjSl8IG_bwH1eGiBxsrUMVesPLlYtz7YU-U,73859
13
+ ingestr/src/sources.py,sha256=GNX3dLFFqNxe6-humD46PZI9nh84tyuiwh9Cl0RwUg8,74309
14
14
  ingestr/src/table_definition.py,sha256=REbAbqdlmUMUuRh8nEQRreWjPVOQ5ZcfqGkScKdCrmk,390
15
15
  ingestr/src/time.py,sha256=H_Fk2J4ShXyUM-EMY7MqCLZQhlnZMZvO952bmZPc4yE,254
16
16
  ingestr/src/version.py,sha256=J_2xgZ0mKlvuHcjdKCx2nlioneLH0I47JiU_Slr_Nwc,189
@@ -61,9 +61,9 @@ ingestr/src/google_sheets/helpers/api_calls.py,sha256=RiVfdacbaneszhmuhYilkJnkc9
61
61
  ingestr/src/google_sheets/helpers/data_processing.py,sha256=RNt2MYfdJhk4bRahnQVezpNg2x9z0vx60YFq2ukZ8vI,11004
62
62
  ingestr/src/gorgias/__init__.py,sha256=_mFkMYwlY5OKEY0o_FK1OKol03A-8uk7bm1cKlmt5cs,21432
63
63
  ingestr/src/gorgias/helpers.py,sha256=DamuijnvhGY9hysQO4txrVMf4izkGbh5qfBKImdOINE,5427
64
- ingestr/src/hubspot/__init__.py,sha256=nHjMvqUAUNVy9dX-1YiaY6PeplDnzc_LjQl25DdVrYg,9765
65
- ingestr/src/hubspot/helpers.py,sha256=vJPaF9qU71-w-LUe4NaRowioIJG3GfX4MObyitHJC6U,7388
66
- ingestr/src/hubspot/settings.py,sha256=hXnIhE4_FlhtgUiCjMLGGZJ_lBlBQJ0YWi6lHJ6Q3WU,2234
64
+ ingestr/src/hubspot/__init__.py,sha256=rSYmN8h6qqxhWCW6elD-pC7iqHXlIofb1F9wvTzziUE,10962
65
+ ingestr/src/hubspot/helpers.py,sha256=fscilfO_K7HS2XQxzf7MeZwVXLTP0WdqnV-NhdeqQAA,7748
66
+ ingestr/src/hubspot/settings.py,sha256=i73MkSiJfRLMFLfiJgYdhp-rhymHTfoqFzZ4uOJdFJM,2456
67
67
  ingestr/src/kafka/__init__.py,sha256=wMCXdiraeKd1Kssi9WcVCGZaNGm2tJEtnNyuB4aR5_k,3541
68
68
  ingestr/src/kafka/helpers.py,sha256=V9WcVn3PKnEpggArHda4vnAcaV8VDuh__dSmRviJb5Y,7502
69
69
  ingestr/src/kinesis/__init__.py,sha256=u5ThH1y8uObZKXgIo71em1UnX6MsVHWOjcf1jKqKbE8,6205
@@ -121,8 +121,8 @@ ingestr/testdata/delete_insert_part2.csv,sha256=B_KUzpzbNdDY_n7wWop1mT2cz36TmayS
121
121
  ingestr/testdata/merge_expected.csv,sha256=DReHqWGnQMsf2PBv_Q2pfjsgvikYFnf1zYcQZ7ZqYN0,276
122
122
  ingestr/testdata/merge_part1.csv,sha256=Pw8Z9IDKcNU0qQHx1z6BUf4rF_-SxKGFOvymCt4OY9I,185
123
123
  ingestr/testdata/merge_part2.csv,sha256=T_GiWxA81SN63_tMOIuemcvboEFeAmbKc7xRXvL9esw,287
124
- ingestr-0.13.27.dist-info/METADATA,sha256=cq7IIe2m-ecKzlBDJVATmzn-t82fASfuQEgwHRf4v10,13659
125
- ingestr-0.13.27.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
126
- ingestr-0.13.27.dist-info/entry_points.txt,sha256=oPJy0KBnPWYjDtP1k8qwAihcTLHSZokSQvRAw_wtfJM,46
127
- ingestr-0.13.27.dist-info/licenses/LICENSE.md,sha256=cW8wIhn8HFE-KLStDF9jHQ1O_ARWP3kTpk_-eOccL24,1075
128
- ingestr-0.13.27.dist-info/RECORD,,
124
+ ingestr-0.13.29.dist-info/METADATA,sha256=bHCOtgvVHv64YRJ9hylunKHeARE2caXv7SuBfD9x1fc,13659
125
+ ingestr-0.13.29.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
126
+ ingestr-0.13.29.dist-info/entry_points.txt,sha256=oPJy0KBnPWYjDtP1k8qwAihcTLHSZokSQvRAw_wtfJM,46
127
+ ingestr-0.13.29.dist-info/licenses/LICENSE.md,sha256=cW8wIhn8HFE-KLStDF9jHQ1O_ARWP3kTpk_-eOccL24,1075
128
+ ingestr-0.13.29.dist-info/RECORD,,