ingestr 0.13.47__py3-none-any.whl → 0.13.48__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/src/buildinfo.py CHANGED
@@ -1 +1 @@
1
- version = "v0.13.47"
1
+ version = "v0.13.48"
ingestr/src/factory.py CHANGED
@@ -54,6 +54,7 @@ from ingestr.src.sources import (
54
54
  SalesforceSource,
55
55
  ShopifySource,
56
56
  SlackSource,
57
+ SolidgateSource,
57
58
  SqlSource,
58
59
  StripeAnalyticsSource,
59
60
  TikTokSource,
@@ -159,6 +160,7 @@ class SourceDestinationFactory:
159
160
  "phantombuster": PhantombusterSource,
160
161
  "elasticsearch": ElasticsearchSource,
161
162
  "attio": AttioSource,
163
+ "solidgate": SolidgateSource,
162
164
  }
163
165
  destinations: Dict[str, Type[DestinationProtocol]] = {
164
166
  "bigquery": BigQueryDestination,
@@ -0,0 +1,97 @@
1
+ from typing import Iterable, Iterator
2
+
3
+ import dlt
4
+ import pendulum
5
+ from dlt.sources import DltResource
6
+
7
+ from .helpers import SolidgateClient
8
+
9
+
10
+ @dlt.source(max_table_nesting=0)
11
+ def solidgate_source(
12
+ start_date: pendulum.DateTime,
13
+ end_date: pendulum.DateTime | None,
14
+ public_key: str,
15
+ secret_key: str,
16
+ ) -> Iterable[DltResource]:
17
+ solidgate_client = SolidgateClient(public_key, secret_key)
18
+
19
+ @dlt.resource(
20
+ name="subscriptions",
21
+ write_disposition="merge",
22
+ primary_key="id",
23
+ columns={
24
+ "created_at": {"data_type": "timestamp", "partition": True},
25
+ },
26
+ )
27
+ def fetch_all_subscriptions(
28
+ dateTime=dlt.sources.incremental(
29
+ "updated_at",
30
+ initial_value=start_date,
31
+ end_value=end_date,
32
+ range_start="closed",
33
+ range_end="closed",
34
+ ),
35
+ ) -> Iterator[dict]:
36
+ path = "subscriptions"
37
+ if dateTime.end_value is None:
38
+ end_dt = pendulum.now(tz="UTC")
39
+ else:
40
+ end_dt = dateTime.end_value
41
+
42
+ start_dt = dateTime.last_value
43
+ yield solidgate_client.fetch_data(path, date_from=start_dt, date_to=end_dt)
44
+
45
+ @dlt.resource(
46
+ name="apm-orders",
47
+ write_disposition="merge",
48
+ primary_key="order_id",
49
+ columns={
50
+ "created_at": {"data_type": "timestamp", "partition": True},
51
+ },
52
+ )
53
+ def fetch_apm_orders(
54
+ dateTime=dlt.sources.incremental(
55
+ "updated_at",
56
+ initial_value=start_date,
57
+ end_value=end_date,
58
+ range_start="closed",
59
+ range_end="closed",
60
+ ),
61
+ ) -> Iterator[dict]:
62
+ path = "apm-orders"
63
+ if dateTime.end_value is None:
64
+ end_dt = pendulum.now(tz="UTC")
65
+ else:
66
+ end_dt = dateTime.end_value
67
+
68
+ start_dt = dateTime.last_value
69
+ yield solidgate_client.fetch_data(path, date_from=start_dt, date_to=end_dt)
70
+
71
+ @dlt.resource(
72
+ name="card-orders",
73
+ write_disposition="merge",
74
+ primary_key="order_id",
75
+ columns={
76
+ "created_at": {"data_type": "timestamp", "partition": True},
77
+ },
78
+ )
79
+ def fetch_card_orders(
80
+ dateTime=dlt.sources.incremental(
81
+ "updated_at",
82
+ initial_value=start_date,
83
+ end_value=end_date,
84
+ range_start="closed",
85
+ range_end="closed",
86
+ ),
87
+ ) -> Iterator[dict]:
88
+ path = "card-orders"
89
+ if dateTime.end_value is None:
90
+ end_dt = pendulum.now(tz="UTC")
91
+ else:
92
+ end_dt = dateTime.end_value
93
+
94
+ start_dt = dateTime.last_value
95
+ yield solidgate_client.fetch_data(path, date_from=start_dt, date_to=end_dt)
96
+
97
+ return fetch_all_subscriptions, fetch_apm_orders, fetch_card_orders
@@ -0,0 +1,78 @@
1
+ import base64
2
+ import hashlib
3
+ import hmac
4
+ import json
5
+
6
+ import pendulum
7
+
8
+ from ingestr.src.http_client import create_client
9
+
10
+
11
+ class SolidgateClient:
12
+ def __init__(self, public_key, secret_key):
13
+ self.base_url = "https://reports.solidgate.com/api/v1"
14
+ self.public_key = public_key
15
+ self.secret_key = secret_key
16
+ self.client = create_client()
17
+
18
+ def fetch_data(
19
+ self,
20
+ path: str,
21
+ date_from: pendulum.DateTime,
22
+ date_to: pendulum.DateTime,
23
+ ):
24
+ request_payload = {
25
+ "date_from": date_from.format("YYYY-MM-DD HH:mm:ss"),
26
+ "date_to": date_to.format("YYYY-MM-DD HH:mm:ss"),
27
+ }
28
+
29
+ json_string = json.dumps(request_payload)
30
+ signature = self.generateSignature(json_string)
31
+ headers = {
32
+ "merchant": self.public_key,
33
+ "Signature": signature,
34
+ "Content-Type": "application/json",
35
+ }
36
+
37
+ next_page_iterator = None
38
+ url = f"{self.base_url}/{path}"
39
+
40
+ while True:
41
+ payload = request_payload.copy()
42
+ if next_page_iterator:
43
+ payload["page_iterator"] = next_page_iterator
44
+
45
+ response = self.client.post(url, headers=headers, json=payload)
46
+ response.raise_for_status()
47
+ response_json = response.json()
48
+
49
+ if path == "subscriptions":
50
+ data = response_json["subscriptions"]
51
+ for _, value in data.items():
52
+ if "updated_at" in value:
53
+ value["updated_at"] = pendulum.parse(
54
+ value["updated_at"]
55
+ )
56
+ yield value
57
+
58
+ else:
59
+ data = response_json["orders"]
60
+ for value in data:
61
+ if "updated_at" in value:
62
+ value["updated_at"] = pendulum.parse(
63
+ value["updated_at"]
64
+ )
65
+ yield value
66
+
67
+ next_page_iterator = response_json.get("metadata", {}).get(
68
+ "next_page_iterator"
69
+ )
70
+ if not next_page_iterator or next_page_iterator == "None":
71
+ break
72
+
73
+ def generateSignature(self, json_string):
74
+ data = self.public_key + json_string + self.public_key
75
+ hmac_hash = hmac.new(
76
+ self.secret_key.encode("utf-8"), data.encode("utf-8"), hashlib.sha512
77
+ ).digest()
78
+ return base64.b64encode(hmac_hash.hex().encode("utf-8")).decode("utf-8")
ingestr/src/sources.py CHANGED
@@ -702,7 +702,7 @@ class StripeAnalyticsSource:
702
702
  table = "BalanceTransaction"
703
703
  else:
704
704
  table = table.capitalize()
705
-
705
+
706
706
  if table in [
707
707
  "Subscription",
708
708
  "Account",
@@ -2431,3 +2431,45 @@ class AttioSource:
2431
2431
  )
2432
2432
  except ResourcesNotFoundError:
2433
2433
  raise UnsupportedResourceError(table_name, "Attio")
2434
+
2435
+
2436
+ class SolidgateSource:
2437
+ def handles_incrementality(self) -> bool:
2438
+ return True
2439
+
2440
+ def dlt_source(self, uri: str, table: str, **kwargs):
2441
+ parsed_uri = urlparse(uri)
2442
+ query_params = parse_qs(parsed_uri.query)
2443
+ public_key = query_params.get("public_key")
2444
+ secret_key = query_params.get("secret_key")
2445
+
2446
+ if public_key is None:
2447
+ raise MissingValueError("public_key", "Solidgate")
2448
+
2449
+ if secret_key is None:
2450
+ raise MissingValueError("secret_key", "Solidgate")
2451
+
2452
+ table_name = table.replace(" ", "")
2453
+
2454
+ start_date = kwargs.get("interval_start")
2455
+ if start_date is None:
2456
+ start_date = pendulum.yesterday().in_tz("UTC")
2457
+ else:
2458
+ start_date = ensure_pendulum_datetime(start_date).in_tz("UTC")
2459
+
2460
+ end_date = kwargs.get("interval_end")
2461
+
2462
+ if end_date is not None:
2463
+ end_date = ensure_pendulum_datetime(end_date).in_tz("UTC")
2464
+
2465
+ from ingestr.src.solidgate import solidgate_source
2466
+
2467
+ try:
2468
+ return solidgate_source(
2469
+ public_key=public_key[0],
2470
+ secret_key=secret_key[0],
2471
+ start_date=start_date,
2472
+ end_date=end_date,
2473
+ ).with_resources(table_name)
2474
+ except ResourcesNotFoundError:
2475
+ raise UnsupportedResourceError(table_name, "Solidgate")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ingestr
3
- Version: 0.13.47
3
+ Version: 0.13.48
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
@@ -2,16 +2,16 @@ ingestr/conftest.py,sha256=Q03FIJIZpLBbpj55cfCHIKEjc1FCvWJhMF2cidUJKQU,1748
2
2
  ingestr/main.py,sha256=Pe_rzwcDRKIYa7baEVUAAPOHyqQbX29RUexMl0F_S1k,25273
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=SV5EmllSWi3j2_r09IqnWLNtpDD-P5xWoRY9SX2JAE4,21
5
+ ingestr/src/buildinfo.py,sha256=yhRWZauFAWKFe7lRKiLr-5OUeP2iQLHekroxm2J_e1c,21
6
6
  ingestr/src/destinations.py,sha256=41Bj1UgxR8a2KcZWqtGw74AKZKnSBrueQRnBdrf3c-A,16003
7
7
  ingestr/src/errors.py,sha256=Ufs4_DfE77_E3vnA1fOQdi6cmuLVNm7_SbFLkL1XPGk,686
8
- ingestr/src/factory.py,sha256=c5WfqmRrXFj1PddnBOzTzzZUHJ-Fb42cvCvsBEqn6Yo,5682
8
+ ingestr/src/factory.py,sha256=FXWJLFfBsKMzUwtsyaaruZU-_OLFKivobj6Olse9vSI,5741
9
9
  ingestr/src/filters.py,sha256=C-_TIVkF_cxZBgG-Run2Oyn0TAhJgA8IWXZ-OPY3uek,1136
10
10
  ingestr/src/http_client.py,sha256=UwPiv95EfHPdT4525xeLFJ1AYlf-cyaHKRU-2QnZt2o,435
11
11
  ingestr/src/loader.py,sha256=9NaWAyfkXdqAZSS-N72Iwo36Lbx4PyqIfaaH1dNdkFs,1712
12
12
  ingestr/src/partition.py,sha256=BrIP6wFJvyR7Nus_3ElnfxknUXeCipK_E_bB8kZowfc,969
13
13
  ingestr/src/resource.py,sha256=XG-sbBapFVEM7OhHQFQRTdTLlh-mHB-N4V1t8F8Tsww,543
14
- ingestr/src/sources.py,sha256=XtMZsuA2LO4WBg1pQeJQdSI8Z76oMt7Ki-a5ubuJQTw,83840
14
+ ingestr/src/sources.py,sha256=kT5XtFQyPPE0dEBXuPaPfEVTqCi0l-6Fa2DWWFCUMeg,85205
15
15
  ingestr/src/table_definition.py,sha256=REbAbqdlmUMUuRh8nEQRreWjPVOQ5ZcfqGkScKdCrmk,390
16
16
  ingestr/src/time.py,sha256=H_Fk2J4ShXyUM-EMY7MqCLZQhlnZMZvO952bmZPc4yE,254
17
17
  ingestr/src/version.py,sha256=J_2xgZ0mKlvuHcjdKCx2nlioneLH0I47JiU_Slr_Nwc,189
@@ -108,6 +108,8 @@ ingestr/src/shopify/settings.py,sha256=StY0EPr7wFJ7KzRRDN4TKxV0_gkIS1wPj2eR4AYSs
108
108
  ingestr/src/slack/__init__.py,sha256=pyDukxcilqTAe_bBzfWJ8Vxi83S-XEdEFBH2pEgILrM,10113
109
109
  ingestr/src/slack/helpers.py,sha256=08TLK7vhFvH_uekdLVOLF3bTDe1zgH0QxHObXHzk1a8,6545
110
110
  ingestr/src/slack/settings.py,sha256=NhKn4y1zokEa5EmIZ05wtj_-I0GOASXZ5V81M1zXCtY,457
111
+ ingestr/src/solidgate/__init__.py,sha256=vpoXu0Ox3zE_WPSzdsA6iUG1_XBa9OaA5F7eFBbZYuQ,2819
112
+ ingestr/src/solidgate/helpers.py,sha256=0TP71RQDo6ub-q0goivQOPiUxWIQU7SgQLUSXVctoVI,2532
111
113
  ingestr/src/sql_database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
112
114
  ingestr/src/sql_database/callbacks.py,sha256=sEFFmXxAURY3yeBjnawigDtq9LBCvi8HFqG4kLd7tMU,2002
113
115
  ingestr/src/stripe_analytics/__init__.py,sha256=0HCL0qsrh_si1RR3a4k9XS94VWQ4v9aG7CqXF-V-57M,4593
@@ -131,8 +133,8 @@ ingestr/testdata/delete_insert_part2.csv,sha256=B_KUzpzbNdDY_n7wWop1mT2cz36TmayS
131
133
  ingestr/testdata/merge_expected.csv,sha256=DReHqWGnQMsf2PBv_Q2pfjsgvikYFnf1zYcQZ7ZqYN0,276
132
134
  ingestr/testdata/merge_part1.csv,sha256=Pw8Z9IDKcNU0qQHx1z6BUf4rF_-SxKGFOvymCt4OY9I,185
133
135
  ingestr/testdata/merge_part2.csv,sha256=T_GiWxA81SN63_tMOIuemcvboEFeAmbKc7xRXvL9esw,287
134
- ingestr-0.13.47.dist-info/METADATA,sha256=uYpb1Z1exz85lRRKwkVunHVbSlWN11MGci7sPj4W4Mg,13852
135
- ingestr-0.13.47.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
136
- ingestr-0.13.47.dist-info/entry_points.txt,sha256=oPJy0KBnPWYjDtP1k8qwAihcTLHSZokSQvRAw_wtfJM,46
137
- ingestr-0.13.47.dist-info/licenses/LICENSE.md,sha256=cW8wIhn8HFE-KLStDF9jHQ1O_ARWP3kTpk_-eOccL24,1075
138
- ingestr-0.13.47.dist-info/RECORD,,
136
+ ingestr-0.13.48.dist-info/METADATA,sha256=wSTbG4xvQuRvVBXVzF0Q_0w0J9uVCKfJmyVmkQDbg50,13852
137
+ ingestr-0.13.48.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
138
+ ingestr-0.13.48.dist-info/entry_points.txt,sha256=oPJy0KBnPWYjDtP1k8qwAihcTLHSZokSQvRAw_wtfJM,46
139
+ ingestr-0.13.48.dist-info/licenses/LICENSE.md,sha256=cW8wIhn8HFE-KLStDF9jHQ1O_ARWP3kTpk_-eOccL24,1075
140
+ ingestr-0.13.48.dist-info/RECORD,,