pingram-python 0.1.0__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.
Files changed (189) hide show
  1. pingram/__init__.py +395 -0
  2. pingram/api/__init__.py +21 -0
  3. pingram/api/account_api.py +2198 -0
  4. pingram/api/addresses_api.py +860 -0
  5. pingram/api/components_api.py +1681 -0
  6. pingram/api/default_api.py +320 -0
  7. pingram/api/domains_api.py +849 -0
  8. pingram/api/editor_api.py +320 -0
  9. pingram/api/environments_api.py +878 -0
  10. pingram/api/health_api.py +287 -0
  11. pingram/api/insights_api.py +321 -0
  12. pingram/api/keys_api.py +849 -0
  13. pingram/api/logs_api.py +1632 -0
  14. pingram/api/members_api.py +1780 -0
  15. pingram/api/sender_api.py +892 -0
  16. pingram/api/templates_api.py +1889 -0
  17. pingram/api/types_api.py +1411 -0
  18. pingram/api/user_api.py +2534 -0
  19. pingram/api/users_api.py +936 -0
  20. pingram/api_client.py +807 -0
  21. pingram/api_response.py +21 -0
  22. pingram/client_wrapper.py +357 -0
  23. pingram/configuration.py +623 -0
  24. pingram/exceptions.py +219 -0
  25. pingram/models/__init__.py +173 -0
  26. pingram/models/account_addresses_response.py +95 -0
  27. pingram/models/account_addresses_response_addresses_inner.py +104 -0
  28. pingram/models/account_get_response.py +143 -0
  29. pingram/models/account_get_response_pending_downgrade_usage_limit.py +99 -0
  30. pingram/models/address_response.py +91 -0
  31. pingram/models/auto_join_get_response.py +89 -0
  32. pingram/models/auto_join_post_response.py +89 -0
  33. pingram/models/auto_join_request_body.py +87 -0
  34. pingram/models/bee_token_v2.py +89 -0
  35. pingram/models/billing_post_request_body.py +91 -0
  36. pingram/models/billing_post_response_body.py +149 -0
  37. pingram/models/billing_post_response_body_pending_downgrade_usage_limit.py +99 -0
  38. pingram/models/channels_enum.py +42 -0
  39. pingram/models/create_account_request_body.py +87 -0
  40. pingram/models/create_account_response.py +89 -0
  41. pingram/models/create_address_request.py +91 -0
  42. pingram/models/create_key_request.py +98 -0
  43. pingram/models/create_key_response.py +104 -0
  44. pingram/models/delete_key_response.py +87 -0
  45. pingram/models/delete_user_response.py +87 -0
  46. pingram/models/email_auth_token_post_request.py +87 -0
  47. pingram/models/email_component_patch_request.py +93 -0
  48. pingram/models/email_component_post_request.py +95 -0
  49. pingram/models/email_component_response.py +120 -0
  50. pingram/models/email_component_response_referenced_by_inner.py +92 -0
  51. pingram/models/environment.py +96 -0
  52. pingram/models/environment_create_request.py +87 -0
  53. pingram/models/environment_patch_request.py +94 -0
  54. pingram/models/get_account_metadata_response.py +91 -0
  55. pingram/models/get_account_metadata_response_user_account_metadata.py +91 -0
  56. pingram/models/get_email_components_response_inner.py +120 -0
  57. pingram/models/get_environments_response_inner.py +96 -0
  58. pingram/models/get_inapp_notifications_response.py +95 -0
  59. pingram/models/get_inapp_notifications_response_notifications_inner.py +137 -0
  60. pingram/models/get_inapp_notifications_response_notifications_inner_delivery_options.py +106 -0
  61. pingram/models/get_inapp_notifications_response_notifications_inner_delivery_options_instant.py +93 -0
  62. pingram/models/get_inapp_notifications_response_notifications_inner_delivery_options_off.py +87 -0
  63. pingram/models/get_inapp_notifications_response_notifications_inner_replies_inner.py +89 -0
  64. pingram/models/get_inapp_notifications_response_notifications_inner_template.py +136 -0
  65. pingram/models/get_inapp_notifications_response_notifications_inner_template_any_of.py +98 -0
  66. pingram/models/get_keys_response.py +95 -0
  67. pingram/models/get_keys_response_keys_inner.py +110 -0
  68. pingram/models/get_logs_response.py +97 -0
  69. pingram/models/get_logs_response_messages_inner.py +141 -0
  70. pingram/models/get_logs_response_messages_inner_attachments_inner.py +93 -0
  71. pingram/models/get_members_response_inner.py +95 -0
  72. pingram/models/get_metrics_response_inner.py +116 -0
  73. pingram/models/get_metrics_response_inner_messages_inner.py +89 -0
  74. pingram/models/get_notifications_response_inner.py +126 -0
  75. pingram/models/get_notifications_response_inner_deduplication.py +87 -0
  76. pingram/models/get_notifications_response_inner_options.py +122 -0
  77. pingram/models/get_notifications_response_inner_options_email.py +128 -0
  78. pingram/models/get_notifications_response_inner_options_email_daily.py +89 -0
  79. pingram/models/get_notifications_response_inner_options_email_monthly.py +101 -0
  80. pingram/models/get_notifications_response_inner_options_email_weekly.py +91 -0
  81. pingram/models/get_notifications_response_inner_templates_inner.py +90 -0
  82. pingram/models/get_notifications_response_inner_throttling.py +111 -0
  83. pingram/models/get_senders_response_inner.py +128 -0
  84. pingram/models/get_templates_response.py +136 -0
  85. pingram/models/get_users_response.py +99 -0
  86. pingram/models/get_users_response_users_inner.py +133 -0
  87. pingram/models/get_users_response_users_inner_email_suppression_status.py +96 -0
  88. pingram/models/get_users_response_users_inner_push_tokens_inner.py +104 -0
  89. pingram/models/get_users_response_users_inner_push_tokens_inner_device.py +97 -0
  90. pingram/models/get_users_response_users_inner_slack_token.py +140 -0
  91. pingram/models/get_users_response_users_inner_slack_token_authed_user.py +97 -0
  92. pingram/models/get_users_response_users_inner_slack_token_enterprise.py +89 -0
  93. pingram/models/get_users_response_users_inner_slack_token_incoming_webhook.py +93 -0
  94. pingram/models/get_users_response_users_inner_slack_token_response_metadata.py +97 -0
  95. pingram/models/get_users_response_users_inner_web_push_tokens_inner.py +91 -0
  96. pingram/models/get_users_response_users_inner_web_push_tokens_inner_sub.py +93 -0
  97. pingram/models/get_users_response_users_inner_web_push_tokens_inner_sub_keys.py +89 -0
  98. pingram/models/in_app_notification_patch_request.py +112 -0
  99. pingram/models/in_app_notification_unread_clear_request.py +89 -0
  100. pingram/models/inapp_unread_count_response.py +87 -0
  101. pingram/models/inbound_request_body.py +138 -0
  102. pingram/models/inbound_response_body.py +104 -0
  103. pingram/models/inbound_response_body_results_inner.py +103 -0
  104. pingram/models/ingishts_post_request.py +121 -0
  105. pingram/models/ingishts_post_request_label_options.py +87 -0
  106. pingram/models/ingishts_post_request_metric_data_queries_inner.py +103 -0
  107. pingram/models/ingishts_post_request_metric_data_queries_inner_metric_stat.py +107 -0
  108. pingram/models/ingishts_post_request_metric_data_queries_inner_metric_stat_metric.py +99 -0
  109. pingram/models/ingishts_post_request_metric_data_queries_inner_metric_stat_metric_dimensions_inner.py +89 -0
  110. pingram/models/intercom_webhook.py +106 -0
  111. pingram/models/intercom_webhook_data.py +91 -0
  112. pingram/models/intercom_webhook_data_item.py +136 -0
  113. pingram/models/intercom_webhook_data_item_any_of.py +140 -0
  114. pingram/models/intercom_webhook_data_item_any_of_contacts.py +104 -0
  115. pingram/models/intercom_webhook_data_item_any_of_contacts_contacts_inner.py +91 -0
  116. pingram/models/intercom_webhook_data_item_any_of_source.py +101 -0
  117. pingram/models/intercom_webhook_data_item_any_of_source_author.py +93 -0
  118. pingram/models/invite_post_response.py +89 -0
  119. pingram/models/log_query_post_body.py +109 -0
  120. pingram/models/logs_bulk_request.py +87 -0
  121. pingram/models/logs_get_response.py +95 -0
  122. pingram/models/logs_get_response_logs_inner.py +627 -0
  123. pingram/models/logs_query_response.py +87 -0
  124. pingram/models/logs_query_result_response.py +101 -0
  125. pingram/models/logs_retention_response.py +87 -0
  126. pingram/models/logs_tail_response.py +95 -0
  127. pingram/models/member_invite_request.py +89 -0
  128. pingram/models/member_update_request.py +87 -0
  129. pingram/models/message_response.py +87 -0
  130. pingram/models/notification.py +126 -0
  131. pingram/models/notification_create_request.py +97 -0
  132. pingram/models/notification_patch_request.py +112 -0
  133. pingram/models/post_email_test_request.py +99 -0
  134. pingram/models/post_email_test_response.py +89 -0
  135. pingram/models/post_senders_request_body.py +87 -0
  136. pingram/models/post_user_request.py +121 -0
  137. pingram/models/sender_post_body.py +166 -0
  138. pingram/models/sender_post_body_email.py +95 -0
  139. pingram/models/sender_post_body_inapp.py +91 -0
  140. pingram/models/sender_post_body_mobile_push.py +89 -0
  141. pingram/models/sender_post_body_options.py +103 -0
  142. pingram/models/sender_post_body_options_apn.py +99 -0
  143. pingram/models/sender_post_body_options_email.py +107 -0
  144. pingram/models/sender_post_body_options_email_attachments_inner.py +134 -0
  145. pingram/models/sender_post_body_options_email_attachments_inner_any_of.py +89 -0
  146. pingram/models/sender_post_body_options_email_attachments_inner_any_of1.py +91 -0
  147. pingram/models/sender_post_body_options_fcm.py +91 -0
  148. pingram/models/sender_post_body_options_fcm_android.py +103 -0
  149. pingram/models/sender_post_body_slack.py +123 -0
  150. pingram/models/sender_post_body_slack_metadata.py +99 -0
  151. pingram/models/sender_post_body_slack_metadata_entities_inner.py +99 -0
  152. pingram/models/sender_post_body_slack_metadata_entities_inner_external_ref.py +89 -0
  153. pingram/models/sender_post_body_sms.py +93 -0
  154. pingram/models/sender_post_body_sms_auto_reply.py +87 -0
  155. pingram/models/sender_post_body_to.py +133 -0
  156. pingram/models/sender_post_body_user.py +133 -0
  157. pingram/models/sender_post_body_web_push.py +93 -0
  158. pingram/models/sender_post_response.py +89 -0
  159. pingram/models/set_default_template_request.py +97 -0
  160. pingram/models/slack_interactivity_response.py +87 -0
  161. pingram/models/slack_oauth_request.py +89 -0
  162. pingram/models/success_response.py +87 -0
  163. pingram/models/supabase_configure_request.py +93 -0
  164. pingram/models/supabase_configure_response.py +89 -0
  165. pingram/models/supabase_o_auth_request.py +91 -0
  166. pingram/models/supabase_o_auth_response.py +89 -0
  167. pingram/models/supabase_projects_response.py +95 -0
  168. pingram/models/supabase_projects_response_projects_inner.py +95 -0
  169. pingram/models/supabase_status_response.py +93 -0
  170. pingram/models/template.py +98 -0
  171. pingram/models/template_patch_request.py +134 -0
  172. pingram/models/template_patch_request_any_of.py +97 -0
  173. pingram/models/template_patch_request_any_of1.py +103 -0
  174. pingram/models/template_patch_request_any_of1_batch.py +91 -0
  175. pingram/models/template_patch_request_any_of1_instant.py +91 -0
  176. pingram/models/template_post_request.py +131 -0
  177. pingram/models/template_post_request_batch.py +91 -0
  178. pingram/models/template_post_request_instant.py +91 -0
  179. pingram/models/update_address_request.py +91 -0
  180. pingram/models/user.py +133 -0
  181. pingram/models/user_suppression_delete_response.py +91 -0
  182. pingram/models/webhook_response.py +104 -0
  183. pingram/py.typed +0 -0
  184. pingram/rest.py +199 -0
  185. pingram_python-0.1.0.dist-info/METADATA +69 -0
  186. pingram_python-0.1.0.dist-info/RECORD +189 -0
  187. pingram_python-0.1.0.dist-info/WHEEL +5 -0
  188. pingram_python-0.1.0.dist-info/licenses/LICENSE +21 -0
  189. pingram_python-0.1.0.dist-info/top_level.txt +1 -0
pingram/models/user.py ADDED
@@ -0,0 +1,133 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ NotificationAPI
5
+
6
+ Internal API for notification delivery and management
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+
15
+ from __future__ import annotations
16
+ import pprint
17
+ import re # noqa: F401
18
+ import json
19
+
20
+ from pydantic import BaseModel, ConfigDict, Field, StrictStr
21
+ from typing import Any, ClassVar, Dict, List, Optional
22
+ from pingram.models.get_users_response_users_inner_email_suppression_status import GetUsersResponseUsersInnerEmailSuppressionStatus
23
+ from pingram.models.get_users_response_users_inner_push_tokens_inner import GetUsersResponseUsersInnerPushTokensInner
24
+ from pingram.models.get_users_response_users_inner_slack_token import GetUsersResponseUsersInnerSlackToken
25
+ from pingram.models.get_users_response_users_inner_web_push_tokens_inner import GetUsersResponseUsersInnerWebPushTokensInner
26
+ from typing import Optional, Set
27
+ from typing_extensions import Self
28
+
29
+ class User(BaseModel):
30
+ """
31
+ User
32
+ """ # noqa: E501
33
+ id: StrictStr
34
+ email: Optional[StrictStr] = None
35
+ number: Optional[StrictStr] = None
36
+ push_tokens: Optional[List[GetUsersResponseUsersInnerPushTokensInner]] = Field(default=None, alias="pushTokens")
37
+ web_push_tokens: Optional[List[GetUsersResponseUsersInnerWebPushTokensInner]] = Field(default=None, alias="webPushTokens")
38
+ timezone: Optional[StrictStr] = None
39
+ slack_channel: Optional[StrictStr] = Field(default=None, description="The destination channel of slack notifications sent to this user. Can be either of the following: - Channel name, e.g. \"test\" - Channel name with # prefix, e.g. \"#test\" - Channel ID, e.g. \"C1234567890\" - User ID for DM, e.g. \"U1234567890\" - Username with @ prefix, e.g. \"@test\"", alias="slackChannel")
40
+ slack_token: Optional[GetUsersResponseUsersInnerSlackToken] = Field(default=None, alias="slackToken")
41
+ last_seen_time: Optional[StrictStr] = Field(default=None, alias="lastSeenTime")
42
+ updated_at: Optional[StrictStr] = Field(default=None, alias="updatedAt")
43
+ created_at: Optional[StrictStr] = Field(default=None, alias="createdAt")
44
+ email_suppression_status: Optional[GetUsersResponseUsersInnerEmailSuppressionStatus] = Field(default=None, alias="emailSuppressionStatus")
45
+ __properties: ClassVar[List[str]] = ["id", "email", "number", "pushTokens", "webPushTokens", "timezone", "slackChannel", "slackToken", "lastSeenTime", "updatedAt", "createdAt", "emailSuppressionStatus"]
46
+
47
+ model_config = ConfigDict(
48
+ populate_by_name=True,
49
+ validate_assignment=True,
50
+ protected_namespaces=(),
51
+ )
52
+
53
+
54
+ def to_str(self) -> str:
55
+ """Returns the string representation of the model using alias"""
56
+ return pprint.pformat(self.model_dump(by_alias=True))
57
+
58
+ def to_json(self) -> str:
59
+ """Returns the JSON representation of the model using alias"""
60
+ # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
61
+ return json.dumps(self.to_dict())
62
+
63
+ @classmethod
64
+ def from_json(cls, json_str: str) -> Optional[Self]:
65
+ """Create an instance of User from a JSON string"""
66
+ return cls.from_dict(json.loads(json_str))
67
+
68
+ def to_dict(self) -> Dict[str, Any]:
69
+ """Return the dictionary representation of the model using alias.
70
+
71
+ This has the following differences from calling pydantic's
72
+ `self.model_dump(by_alias=True)`:
73
+
74
+ * `None` is only added to the output dict for nullable fields that
75
+ were set at model initialization. Other fields with value `None`
76
+ are ignored.
77
+ """
78
+ excluded_fields: Set[str] = set([
79
+ ])
80
+
81
+ _dict = self.model_dump(
82
+ by_alias=True,
83
+ exclude=excluded_fields,
84
+ exclude_none=True,
85
+ )
86
+ # override the default output from pydantic by calling `to_dict()` of each item in push_tokens (list)
87
+ _items = []
88
+ if self.push_tokens:
89
+ for _item_push_tokens in self.push_tokens:
90
+ if _item_push_tokens:
91
+ _items.append(_item_push_tokens.to_dict())
92
+ _dict['pushTokens'] = _items
93
+ # override the default output from pydantic by calling `to_dict()` of each item in web_push_tokens (list)
94
+ _items = []
95
+ if self.web_push_tokens:
96
+ for _item_web_push_tokens in self.web_push_tokens:
97
+ if _item_web_push_tokens:
98
+ _items.append(_item_web_push_tokens.to_dict())
99
+ _dict['webPushTokens'] = _items
100
+ # override the default output from pydantic by calling `to_dict()` of slack_token
101
+ if self.slack_token:
102
+ _dict['slackToken'] = self.slack_token.to_dict()
103
+ # override the default output from pydantic by calling `to_dict()` of email_suppression_status
104
+ if self.email_suppression_status:
105
+ _dict['emailSuppressionStatus'] = self.email_suppression_status.to_dict()
106
+ return _dict
107
+
108
+ @classmethod
109
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
110
+ """Create an instance of User from a dict"""
111
+ if obj is None:
112
+ return None
113
+
114
+ if not isinstance(obj, dict):
115
+ return cls.model_validate(obj)
116
+
117
+ _obj = cls.model_validate({
118
+ "id": obj.get("id"),
119
+ "email": obj.get("email"),
120
+ "number": obj.get("number"),
121
+ "pushTokens": [GetUsersResponseUsersInnerPushTokensInner.from_dict(_item) for _item in obj["pushTokens"]] if obj.get("pushTokens") is not None else None,
122
+ "webPushTokens": [GetUsersResponseUsersInnerWebPushTokensInner.from_dict(_item) for _item in obj["webPushTokens"]] if obj.get("webPushTokens") is not None else None,
123
+ "timezone": obj.get("timezone"),
124
+ "slackChannel": obj.get("slackChannel"),
125
+ "slackToken": GetUsersResponseUsersInnerSlackToken.from_dict(obj["slackToken"]) if obj.get("slackToken") is not None else None,
126
+ "lastSeenTime": obj.get("lastSeenTime"),
127
+ "updatedAt": obj.get("updatedAt"),
128
+ "createdAt": obj.get("createdAt"),
129
+ "emailSuppressionStatus": GetUsersResponseUsersInnerEmailSuppressionStatus.from_dict(obj["emailSuppressionStatus"]) if obj.get("emailSuppressionStatus") is not None else None
130
+ })
131
+ return _obj
132
+
133
+
@@ -0,0 +1,91 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ NotificationAPI
5
+
6
+ Internal API for notification delivery and management
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+
15
+ from __future__ import annotations
16
+ import pprint
17
+ import re # noqa: F401
18
+ import json
19
+
20
+ from pydantic import BaseModel, ConfigDict
21
+ from typing import Any, ClassVar, Dict, List
22
+ from pingram.models.get_users_response_users_inner import GetUsersResponseUsersInner
23
+ from typing import Optional, Set
24
+ from typing_extensions import Self
25
+
26
+ class UserSuppressionDeleteResponse(BaseModel):
27
+ """
28
+ UserSuppressionDeleteResponse
29
+ """ # noqa: E501
30
+ user: GetUsersResponseUsersInner
31
+ __properties: ClassVar[List[str]] = ["user"]
32
+
33
+ model_config = ConfigDict(
34
+ populate_by_name=True,
35
+ validate_assignment=True,
36
+ protected_namespaces=(),
37
+ )
38
+
39
+
40
+ def to_str(self) -> str:
41
+ """Returns the string representation of the model using alias"""
42
+ return pprint.pformat(self.model_dump(by_alias=True))
43
+
44
+ def to_json(self) -> str:
45
+ """Returns the JSON representation of the model using alias"""
46
+ # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
47
+ return json.dumps(self.to_dict())
48
+
49
+ @classmethod
50
+ def from_json(cls, json_str: str) -> Optional[Self]:
51
+ """Create an instance of UserSuppressionDeleteResponse from a JSON string"""
52
+ return cls.from_dict(json.loads(json_str))
53
+
54
+ def to_dict(self) -> Dict[str, Any]:
55
+ """Return the dictionary representation of the model using alias.
56
+
57
+ This has the following differences from calling pydantic's
58
+ `self.model_dump(by_alias=True)`:
59
+
60
+ * `None` is only added to the output dict for nullable fields that
61
+ were set at model initialization. Other fields with value `None`
62
+ are ignored.
63
+ """
64
+ excluded_fields: Set[str] = set([
65
+ ])
66
+
67
+ _dict = self.model_dump(
68
+ by_alias=True,
69
+ exclude=excluded_fields,
70
+ exclude_none=True,
71
+ )
72
+ # override the default output from pydantic by calling `to_dict()` of user
73
+ if self.user:
74
+ _dict['user'] = self.user.to_dict()
75
+ return _dict
76
+
77
+ @classmethod
78
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
79
+ """Create an instance of UserSuppressionDeleteResponse from a dict"""
80
+ if obj is None:
81
+ return None
82
+
83
+ if not isinstance(obj, dict):
84
+ return cls.model_validate(obj)
85
+
86
+ _obj = cls.model_validate({
87
+ "user": GetUsersResponseUsersInner.from_dict(obj["user"]) if obj.get("user") is not None else None
88
+ })
89
+ return _obj
90
+
91
+
@@ -0,0 +1,104 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ NotificationAPI
5
+
6
+ Internal API for notification delivery and management
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+
15
+ from __future__ import annotations
16
+ import pprint
17
+ import re # noqa: F401
18
+ import json
19
+
20
+ from pydantic import BaseModel, ConfigDict, StrictBool, StrictStr
21
+ from typing import Any, ClassVar, Dict, List, Optional
22
+ from typing import Optional, Set
23
+ from typing_extensions import Self
24
+
25
+ class WebhookResponse(BaseModel):
26
+ """
27
+ WebhookResponse
28
+ """ # noqa: E501
29
+ success: StrictBool
30
+ message: Optional[StrictStr] = None
31
+ topic: Optional[StrictStr] = None
32
+ additional_properties: Dict[str, Any] = {}
33
+ __properties: ClassVar[List[str]] = ["success", "message", "topic"]
34
+
35
+ model_config = ConfigDict(
36
+ populate_by_name=True,
37
+ validate_assignment=True,
38
+ protected_namespaces=(),
39
+ )
40
+
41
+
42
+ def to_str(self) -> str:
43
+ """Returns the string representation of the model using alias"""
44
+ return pprint.pformat(self.model_dump(by_alias=True))
45
+
46
+ def to_json(self) -> str:
47
+ """Returns the JSON representation of the model using alias"""
48
+ # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
49
+ return json.dumps(self.to_dict())
50
+
51
+ @classmethod
52
+ def from_json(cls, json_str: str) -> Optional[Self]:
53
+ """Create an instance of WebhookResponse from a JSON string"""
54
+ return cls.from_dict(json.loads(json_str))
55
+
56
+ def to_dict(self) -> Dict[str, Any]:
57
+ """Return the dictionary representation of the model using alias.
58
+
59
+ This has the following differences from calling pydantic's
60
+ `self.model_dump(by_alias=True)`:
61
+
62
+ * `None` is only added to the output dict for nullable fields that
63
+ were set at model initialization. Other fields with value `None`
64
+ are ignored.
65
+ * Fields in `self.additional_properties` are added to the output dict.
66
+ """
67
+ excluded_fields: Set[str] = set([
68
+ "additional_properties",
69
+ ])
70
+
71
+ _dict = self.model_dump(
72
+ by_alias=True,
73
+ exclude=excluded_fields,
74
+ exclude_none=True,
75
+ )
76
+ # puts key-value pairs in additional_properties in the top level
77
+ if self.additional_properties is not None:
78
+ for _key, _value in self.additional_properties.items():
79
+ _dict[_key] = _value
80
+
81
+ return _dict
82
+
83
+ @classmethod
84
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
85
+ """Create an instance of WebhookResponse from a dict"""
86
+ if obj is None:
87
+ return None
88
+
89
+ if not isinstance(obj, dict):
90
+ return cls.model_validate(obj)
91
+
92
+ _obj = cls.model_validate({
93
+ "success": obj.get("success"),
94
+ "message": obj.get("message"),
95
+ "topic": obj.get("topic")
96
+ })
97
+ # store additional fields in additional_properties
98
+ for _key in obj.keys():
99
+ if _key not in cls.__properties:
100
+ _obj.additional_properties[_key] = obj.get(_key)
101
+
102
+ return _obj
103
+
104
+
pingram/py.typed ADDED
File without changes
pingram/rest.py ADDED
@@ -0,0 +1,199 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ NotificationAPI
5
+
6
+ Internal API for notification delivery and management
7
+
8
+ The version of the OpenAPI document: 1.0.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+
15
+ import io
16
+ import json
17
+ import re
18
+ import ssl
19
+ from typing import Optional, Union
20
+
21
+ import httpx
22
+
23
+ from pingram.exceptions import ApiException, ApiValueError
24
+
25
+ RESTResponseType = httpx.Response
26
+
27
+ class RESTResponse(io.IOBase):
28
+
29
+ def __init__(self, resp) -> None:
30
+ self.response = resp
31
+ self.status = resp.status_code
32
+ self.reason = resp.reason_phrase
33
+ self.data = None
34
+
35
+ async def read(self):
36
+ if self.data is None:
37
+ self.data = await self.response.aread()
38
+ return self.data
39
+
40
+ @property
41
+ def headers(self):
42
+ """Returns a CIMultiDictProxy of response headers."""
43
+ return self.response.headers
44
+
45
+ def getheaders(self):
46
+ """Returns a CIMultiDictProxy of the response headers; use ``headers`` instead."""
47
+ return self.response.headers
48
+
49
+ def getheader(self, name, default=None):
50
+ """Returns a given response header; use ``headers`` instead."""
51
+ return self.response.headers.get(name, default)
52
+
53
+
54
+ class RESTClientObject:
55
+
56
+ def __init__(self, configuration) -> None:
57
+
58
+ # maxsize is number of requests to host that are allowed in parallel
59
+ self.maxsize = configuration.connection_pool_maxsize
60
+
61
+ self.ssl_context = ssl.create_default_context(
62
+ cafile=configuration.ssl_ca_cert,
63
+ cadata=configuration.ca_cert_data,
64
+ )
65
+ if configuration.cert_file:
66
+ self.ssl_context.load_cert_chain(
67
+ configuration.cert_file, keyfile=configuration.key_file
68
+ )
69
+
70
+ if not configuration.verify_ssl:
71
+ self.ssl_context.check_hostname = False
72
+ self.ssl_context.verify_mode = ssl.CERT_NONE
73
+
74
+ self.proxy = configuration.proxy
75
+ self.proxy_headers = configuration.proxy_headers
76
+
77
+ self.pool_manager: Optional[httpx.AsyncClient] = None
78
+
79
+ async def close(self):
80
+ if self.pool_manager is not None:
81
+ await self.pool_manager.aclose()
82
+
83
+ async def request(
84
+ self,
85
+ method,
86
+ url,
87
+ headers=None,
88
+ body=None,
89
+ post_params=None,
90
+ _request_timeout=None):
91
+ """Execute request
92
+
93
+ :param method: http request method
94
+ :param url: http request url
95
+ :param headers: http request headers
96
+ :param body: request json body, for `application/json`
97
+ :param post_params: request post parameters,
98
+ `application/x-www-form-urlencoded`
99
+ and `multipart/form-data`
100
+ :param _request_timeout: timeout setting for this request. If one
101
+ number provided, it will be total request
102
+ timeout. It can also be a pair (tuple) of
103
+ (connection, read) timeouts.
104
+ """
105
+ method = method.upper()
106
+ assert method in [
107
+ 'GET',
108
+ 'HEAD',
109
+ 'DELETE',
110
+ 'POST',
111
+ 'PUT',
112
+ 'PATCH',
113
+ 'OPTIONS'
114
+ ]
115
+
116
+ if post_params and body:
117
+ raise ApiValueError(
118
+ "body parameter cannot be used with post_params parameter."
119
+ )
120
+
121
+ post_params = post_params or {}
122
+ headers = headers or {}
123
+ timeout = _request_timeout or 5 * 60
124
+
125
+ if 'Content-Type' not in headers:
126
+ headers['Content-Type'] = 'application/json'
127
+
128
+ args = {
129
+ "method": method,
130
+ "url": url,
131
+ "timeout": timeout,
132
+ "headers": headers
133
+ }
134
+
135
+ # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE`
136
+ if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']:
137
+ if re.search('json', headers['Content-Type'], re.IGNORECASE):
138
+ if body is not None:
139
+ args["json"] = body
140
+ elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501
141
+ args["data"] = dict(post_params)
142
+ elif headers['Content-Type'] == 'multipart/form-data':
143
+ # must del headers['Content-Type'], or the correct
144
+ # Content-Type which generated by httpx
145
+ del headers['Content-Type']
146
+
147
+ files = []
148
+ data = {}
149
+ for param in post_params:
150
+ k, v = param
151
+ if isinstance(v, tuple) and len(v) == 3:
152
+ files.append((k, v))
153
+ else:
154
+ # Ensures that dict objects are serialized
155
+ if isinstance(v, dict):
156
+ v = json.dumps(v)
157
+ elif isinstance(v, int):
158
+ v = str(v)
159
+ data[k] = v
160
+
161
+ if files:
162
+ args["files"] = files
163
+ if data:
164
+ args["data"] = data
165
+
166
+ # Pass a `bytes` parameter directly in the body to support
167
+ # other content types than Json when `body` argument is provided
168
+ # in serialized form
169
+ elif isinstance(body, str) or isinstance(body, bytes):
170
+ args["data"] = body
171
+ else:
172
+ # Cannot generate the request from given parameters
173
+ msg = """Cannot prepare a request message for provided
174
+ arguments. Please check that your arguments match
175
+ declared content type."""
176
+ raise ApiException(status=0, reason=msg)
177
+
178
+ if self.pool_manager is None:
179
+ self.pool_manager = self._create_pool_manager()
180
+
181
+ r = await self.pool_manager.request(**args)
182
+ return RESTResponse(r)
183
+
184
+ def _create_pool_manager(self) -> httpx.AsyncClient:
185
+ limits = httpx.Limits(max_connections=self.maxsize)
186
+
187
+ proxy = None
188
+ if self.proxy:
189
+ proxy = httpx.Proxy(
190
+ url=self.proxy,
191
+ headers=self.proxy_headers
192
+ )
193
+
194
+ return httpx.AsyncClient(
195
+ limits=limits,
196
+ proxy=proxy,
197
+ verify=self.ssl_context,
198
+ trust_env=True
199
+ )
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.4
2
+ Name: pingram-python
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for Pingram - Send notifications via Email, SMS, Push, In-App, and more
5
+ Author: Pingram
6
+ License: MIT
7
+ Project-URL: Repository, https://github.com/notificationapi-com/serverless
8
+ Keywords: pingram,notificationapi,notification,sdk,email,sms,push,in-app
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: python-dateutil>=2.8.2
13
+ Requires-Dist: httpx>=0.28.1
14
+ Requires-Dist: pydantic>=2
15
+ Requires-Dist: typing-extensions>=4.7.1
16
+ Dynamic: license-file
17
+
18
+ # Pingram Python SDK
19
+
20
+ Official Python SDK for Pingram. Send notifications via Email, SMS, Push, In-App, and more from your server-side Python code.
21
+
22
+ ## Requirements
23
+
24
+ - Python 3.9+
25
+ - Dependencies: `httpx`, `pydantic`, `python-dateutil`, `typing-extensions` (installed automatically)
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ pip install pingram-python
31
+ ```
32
+
33
+ To install from source (e.g. from the [GitHub repo](https://github.com/notificationapi-com/serverless)):
34
+
35
+ ```bash
36
+ pip install -e sdks/python
37
+ ```
38
+
39
+ ## Quick start
40
+
41
+ Use the **Pingram** client with your **API key**, then call `send()` or the namespaced APIs (`user`, `users`, `logs`, etc.).
42
+
43
+ ```python
44
+ import asyncio
45
+ from pingram import Pingram, SenderPostBody, SenderPostBodyTo
46
+
47
+ async def main():
48
+ # API key (e.g. pingram_sk_...) or JWT; optional region ("us" | "eu" | "ca")
49
+ async with Pingram(api_key="pingram_sk_...") as client:
50
+ # Send a notification
51
+ body = SenderPostBody(
52
+ notification_id="your_notification_id",
53
+ to=SenderPostBodyTo(id="user_123"),
54
+ )
55
+ response = await client.send(sender_post_body=body)
56
+ print(response)
57
+
58
+ # Or use namespaced APIs (same as Node: client.user, client.users, client.logs, ...)
59
+ # user = await client.user.user_get_user(account_id="...", user_id="...")
60
+ # logs = await client.logs.logs_query_logs(...)
61
+
62
+ asyncio.run(main())
63
+ ```
64
+
65
+ You can also pass a config dict: `Pingram({"api_key": "pingram_sk_...", "region": "eu"})`. For full API coverage, use `client.send`, `client.user`, `client.users`, `client.logs`, `client.templates`, `client.environments`, and the other APIs.
66
+
67
+ ## Links
68
+
69
+ - [Documentation](https://www.pingram.io/docs/)