python-terminusgps 33.5.0__py3-none-any.whl → 34.0.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.

Potentially problematic release.


This version of python-terminusgps might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-terminusgps
3
- Version: 33.5.0
3
+ Version: 34.0.0
4
4
  Summary: Provides abstractions/utilities for working with Wialon API, Authorize.NET API, AWS API, and more.
5
5
  Project-URL: Documentation, https://docs.terminusgps.com
6
6
  Project-URL: Repository, https://github.com/terminusgps/python-terminusgps
@@ -1,23 +1,27 @@
1
1
  terminusgps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  terminusgps/authorizenet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- terminusgps/authorizenet/auth.py,sha256=umNpOXObDrIt2K40padWBedQl7tVAmEg2alBWhGk-qQ,1238
3
+ terminusgps/authorizenet/auth.py,sha256=g2tJPxP9V1nXnUcKzhHSRSs6ruSIHej5_hcf8P7bod8,1262
4
4
  terminusgps/authorizenet/constants.py,sha256=xmulPmiBLhFfZoc7Il3l-DZA9Nq5HSaJmJKU-v-5X-Y,420
5
5
  terminusgps/authorizenet/controllers.py,sha256=9t62qdGpmAkP4tNyPefd7vBRutXvMWsxql6z_pg52Bg,2146
6
6
  terminusgps/authorizenet/utils.py,sha256=FrKqXWrplcgiET1rDTmUaqmN_ze7j93jWgfFeJR8rlg,7073
7
7
  terminusgps/authorizenet/profiles/__init__.py,sha256=IG4XCEEYtHKqXOatlZlob6J3ukAgF7cFR-RXxOSMS1c,161
8
8
  terminusgps/authorizenet/profiles/addresses.py,sha256=xDlnFlIjuR7NVXwfj5aJT9E_GolnYFuYASkfenvWfm8,6292
9
- terminusgps/authorizenet/profiles/base.py,sha256=lPc8Pugp5EcXtZmeBpeqicij7l0ROGvMYTV8J0fLLmQ,3768
9
+ terminusgps/authorizenet/profiles/base.py,sha256=Pu1NGrvC5Ox2W1oZuVcPqUw3aUoSK191Evexw1U6_3k,3940
10
10
  terminusgps/authorizenet/profiles/customers.py,sha256=ArXOHPgyBu01tgBPHHYyezb4PIeXh70IWjYCy-lHpWg,11734
11
- terminusgps/authorizenet/profiles/payments.py,sha256=MmjvE4ZSfgyGPRUzeREB_dX_n6QfpC3zGIlqFnIC8BQ,10956
11
+ terminusgps/authorizenet/profiles/payments.py,sha256=nhudGuJ6RzmK0MrhDVuYL2BxvyzKNpliBIfIpFU5Y-4,11038
12
12
  terminusgps/authorizenet/profiles/subscriptions.py,sha256=m_jb9GqeD1tLmeqSnaGwJrzPcQOulEkF8K1wCaqKR24,7924
13
13
  terminusgps/authorizenet/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  terminusgps/authorizenet/tests/test_auth.py,sha256=sdByYrcv8RKjcJckOHbyHH1z_M4qrATFI3qj_XDQXbk,1624
15
15
  terminusgps/authorizenet/tests/test_profiles.py,sha256=tvLBY0iSAC33RlWiBP_NSnPskUQBjfrf0YHMpR-m22k,7566
16
16
  terminusgps/authorizenet/tests/test_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  terminusgps/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- terminusgps/aws/notifier.py,sha256=0w7tuMJ2tslMXKrLYcHi8kkxPsbvgfyFajkpD4UwlLc,1361
18
+ terminusgps/aws/notifications.py,sha256=N5p9EqN4wqBRJAMEFOjyseVatpwsxlB0QrHyqFDK5SI,5698
19
19
  terminusgps/aws/secrets.py,sha256=MxQEmmBLpMUQ2tYAsHdCYf-7RZ84LiogdKcTsACX5dw,361
20
20
  terminusgps/aws/utils.py,sha256=68GWcllu4h41qzFiKdUkWOAA4LDsTPqRY446VRMxYsY,116
21
+ terminusgps/aws/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ terminusgps/aws/tests/test_notifications.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ terminusgps/aws/tests/test_secrets.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ terminusgps/aws/tests/test_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
25
  terminusgps/django/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
26
  terminusgps/django/mixins.py,sha256=Q9ZJuzpk3d9lDnlVA8ZTVvnZWxB13p08EQ8yVJcztn4,1034
23
27
  terminusgps/django/settings.py,sha256=yJIcBE0xjY60AXF_gonY5hS3ofseqPW2k9uSoELgoho,639
@@ -50,7 +54,7 @@ terminusgps/wialon/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
50
54
  terminusgps/wialon/tests/test_items.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
55
  terminusgps/wialon/tests/test_session.py,sha256=9mBlYchMo9NeqRIZsmxYzrM1zBHorqu4ooxqSNppLpI,1336
52
56
  terminusgps/wialon/tests/test_utils.py,sha256=SK4PxJQGECFnzx_EQeRAQfsQ5_3FLaVcis2W9u_ibuI,1730
53
- python_terminusgps-33.5.0.dist-info/METADATA,sha256=Jd4lLTQC74E24wIMEG6WDYXiYg0e4uY8i-LTxwWkEvs,1616
54
- python_terminusgps-33.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
55
- python_terminusgps-33.5.0.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
56
- python_terminusgps-33.5.0.dist-info/RECORD,,
57
+ python_terminusgps-34.0.0.dist-info/METADATA,sha256=OLumu5xwbGDw-7yR3niZdmytYWiKwS80xQMazYTcy5g,1616
58
+ python_terminusgps-34.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
59
+ python_terminusgps-34.0.0.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
60
+ python_terminusgps-34.0.0.dist-info/RECORD,,
@@ -10,7 +10,7 @@ if not settings.configured:
10
10
 
11
11
  def get_merchant_auth() -> merchantAuthenticationType:
12
12
  """
13
- Returns the merchant authentication information for Authorizenet API requests.
13
+ Returns the current merchant authentication information for Authorizenet API requests.
14
14
 
15
15
  :returns: A merchant authentication object.
16
16
  :rtype: :py:obj:`~authorizenet.apicontractsv1.merchantAuthenticationType`
@@ -24,7 +24,7 @@ def get_merchant_auth() -> merchantAuthenticationType:
24
24
 
25
25
  def get_environment() -> str:
26
26
  """
27
- Returns the environment for Authorizenet API requests.
27
+ Returns the current environment for Authorizenet API requests.
28
28
 
29
29
  :returns: An Authorizenet API environment string.
30
30
  :rtype: :py:obj:`str`
@@ -35,7 +35,7 @@ def get_environment() -> str:
35
35
 
36
36
  def get_validation_mode() -> str:
37
37
  """
38
- Returns the validation mode for Authorizenet API requests.
38
+ Returns the current validation mode for Authorizenet API requests.
39
39
 
40
40
  :returns: An Authorizenet API validation string.
41
41
  :rtype: :py:obj:`str`
@@ -62,6 +62,17 @@ class AuthorizenetProfileBase(AuthorizenetControllerExecutor):
62
62
  """
63
63
  return get_merchant_auth()
64
64
 
65
+ @property
66
+ def validationMode(self) -> str:
67
+ """
68
+ The current Authorizenet API validation mode.
69
+
70
+ :returns: An Authorizenet API validation mode string.
71
+ :rtype: :py:obj:`str`
72
+
73
+ """
74
+ return get_validation_mode()
75
+
65
76
 
66
77
  class AuthorizenetSubProfileBase(AuthorizenetProfileBase):
67
78
  """Base class for Authorizenet 'sub-profiles', profiles that have an associated customer profile."""
@@ -83,10 +94,6 @@ class AuthorizenetSubProfileBase(AuthorizenetProfileBase):
83
94
  self.customerProfileId = customer_profile_id
84
95
  self.default = default
85
96
 
86
- @property
87
- def validationMode(self) -> str:
88
- return get_validation_mode()
89
-
90
97
  @property
91
98
  def customerProfileId(self) -> str:
92
99
  """
@@ -8,7 +8,12 @@ class PaymentProfile(AuthorizenetSubProfileBase):
8
8
 
9
9
  @property
10
10
  def last_4(self) -> str | None:
11
- """Last 4 digits of the payment profile credit card."""
11
+ """
12
+ Last 4 digits of the payment profile credit card.
13
+
14
+ :type: :py:obj:`str` | :py:obj:`None`
15
+
16
+ """
12
17
  if self.id:
13
18
  response = self._authorizenet_get_payment_profile()
14
19
  return str(response.paymentProfile.payment.creditCard.cardNumber)[-4:]
@@ -31,7 +36,7 @@ class PaymentProfile(AuthorizenetSubProfileBase):
31
36
  """
32
37
  return int(
33
38
  self._authorizenet_create_payment_profile(
34
- address, payment
39
+ address=address, payment=payment
35
40
  ).customerPaymentProfileId
36
41
  )
37
42
 
@@ -0,0 +1,193 @@
1
+ import asyncio
2
+ import uuid
3
+ from collections.abc import Sequence
4
+ from contextlib import AsyncExitStack
5
+
6
+ from aiobotocore.session import AioSession
7
+
8
+ from terminusgps.django.validators import validate_e164_phone_number
9
+
10
+
11
+ class AsyncNotificationManager:
12
+ def __init__(
13
+ self, group_id: str | None = None, region_name: str = "us-east-1"
14
+ ) -> None:
15
+ """
16
+ Sets :py:attr:`group_id` and :py:attr:`region_name` if provided.
17
+
18
+ :returns: Nothing.
19
+ :rtype: :py:obj:`None`
20
+
21
+ """
22
+ self._exit_stack = AsyncExitStack()
23
+ self._sns_client = None
24
+ self._region_name = region_name
25
+ self.group_id = group_id
26
+
27
+ async def __aenter__(self) -> "AsyncNotificationManager":
28
+ """
29
+ Creates an asyncronous session and client.
30
+
31
+ :returns: The notification manager.
32
+ :rtype: :py:obj:`~terminusgps.aws.notifications.AsyncNotificationManager`
33
+
34
+ """
35
+ session = AioSession()
36
+ self._sns_client = await self._exit_stack.enter_async_context(
37
+ session.create_client("sns", region_name=self.region_name)
38
+ )
39
+ return self
40
+
41
+ async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
42
+ """
43
+ Destroys the asyncronous session.
44
+
45
+ :param exc_type: Exception type.
46
+ :param exc_val: Exception value.
47
+ :param exc_tb: Exception traceback.
48
+ :returns: Nothing.
49
+ :rtype: :py:obj:`None`
50
+
51
+ """
52
+ await self._exit_stack.__aexit__(exc_type, exc_val, exc_tb)
53
+
54
+ @property
55
+ def region_name(self) -> str:
56
+ """
57
+ An AWS region name.
58
+
59
+ :type: :py:obj:`str`
60
+
61
+ """
62
+ return self._region_name
63
+
64
+ @property
65
+ def group_id(self) -> str:
66
+ """
67
+ A message group id.
68
+
69
+ :type: :py:obj:`str`
70
+
71
+ """
72
+ return str(self._group_id)
73
+
74
+ @group_id.setter
75
+ def group_id(self, other: str | None) -> None:
76
+ """
77
+ Sets :py:attr:`group_id` to ``other``.
78
+
79
+ :param other: A message group id.
80
+ :type other: :py:obj:`str` | :py:obj:`None`
81
+ :returns: Nothing.
82
+ :rtype: :py:obj:`None`
83
+
84
+ """
85
+ if not other:
86
+ other = str(uuid.uuid4())
87
+ self._group_id = other
88
+
89
+ async def send_push_batch(self, target_arns: Sequence[str], message: str) -> None:
90
+ """
91
+ Sends a push notification to each AWS resource by ARN in ``target_arns``.
92
+
93
+ :param target_arns: A sequence of AWS resource ARNs.
94
+ :type target_arns: :py:obj:`~collections.abc.Sequence`
95
+ :param message: A message body.
96
+ :type message: :py:obj:`str`
97
+ :returns: Nothing.
98
+ :rtype: :py:obj:`None`
99
+
100
+ """
101
+ await asyncio.gather(
102
+ *[
103
+ self.send_push(
104
+ target_arn=arn, message=message, message_id=str(uuid.uuid4())
105
+ )
106
+ for arn in target_arns
107
+ ]
108
+ )
109
+
110
+ async def send_sms_batch(self, to_numbers: Sequence[str], message: str) -> None:
111
+ """
112
+ Sends an sms message to each phone number in ``to_numbers``.
113
+
114
+ :param to_numbers: A sequence of phone numbers.
115
+ :type to_numbers: :py:obj:`~collections.abc.Sequence`
116
+ :param message: A message body.
117
+ :type message: :py:obj:`str`
118
+ :raises ValidationError: If a ``to_number`` wasn't a valid E.164 formatted phone number.
119
+ :returns: Nothing.
120
+ :rtype: :py:obj:`None`
121
+
122
+ """
123
+ for to_number in to_numbers:
124
+ validate_e164_phone_number(to_number)
125
+
126
+ await asyncio.gather(
127
+ *[
128
+ self.send_sms(
129
+ to_number=num, message=message, message_id=str(uuid.uuid4())
130
+ )
131
+ for num in to_numbers
132
+ ]
133
+ )
134
+
135
+ async def send_sms(self, to_number: str, message: str, message_id: str) -> None:
136
+ """
137
+ Sends an sms to ``to_number``.
138
+
139
+ :param to_number: A destination phone number.
140
+ :type to_number: :py:obj:`str`
141
+ :param message: A message body.
142
+ :type message: :py:obj:`str`
143
+ :param message_id: A message deduplication id.
144
+ :type message_id: :py:obj:`str`
145
+ :raises ValidationError: If ``to_number`` wasn't a valid E.164 formatted phone number.
146
+ :returns: Nothing.
147
+ :rtype: :py:obj:`None`
148
+
149
+ """
150
+ validate_e164_phone_number(to_number)
151
+
152
+ await self._sns_client.publish(
153
+ **{
154
+ "PhoneNumber": to_number,
155
+ "Message": message,
156
+ "MessageDeduplicationId": message_id,
157
+ "MessageGroupId": self.group_id,
158
+ }
159
+ )
160
+
161
+ async def send_push(self, target_arn: str, message: str, message_id: str) -> None:
162
+ """
163
+ Sends a push notification to ``target_arn``.
164
+
165
+ :param target_arn: An AWS resource ARN.
166
+ :type target_arn: :py:obj:`str`
167
+ :param message: A message body.
168
+ :type message: :py:obj:`str`
169
+ :param message_id: A message deduplication id.
170
+ :type message_id: :py:obj:`str`
171
+ :returns: Nothing.
172
+ :rtype: :py:obj:`None`
173
+
174
+ """
175
+ await self._sns_client.publish(
176
+ **{
177
+ "TargetArn": target_arn,
178
+ "Message": message,
179
+ "MessageDeduplicationId": message_id,
180
+ "MessageGroupId": self.group_id,
181
+ }
182
+ )
183
+
184
+
185
+ async def main() -> None:
186
+ async with AsyncNotificationManager(str(uuid.uuid4())) as manager:
187
+ await manager.send_sms_batch(
188
+ ["+17133049421", "+18324667085", "+18322835634"], "This is a test message."
189
+ )
190
+
191
+
192
+ if __name__ == "__main__":
193
+ asyncio.run(main())
File without changes
File without changes
File without changes
File without changes
@@ -1,49 +0,0 @@
1
- import asyncio
2
- import uuid
3
- from contextlib import AsyncExitStack
4
-
5
- from aiobotocore.session import AioSession
6
-
7
- from terminusgps.django.validators import validate_e164_phone_number
8
-
9
-
10
- class AWSNotifier:
11
- def __init__(self, region: str = "us-east-1") -> None:
12
- self._client = None
13
- self._region = region
14
- self._exit_stack = AsyncExitStack()
15
-
16
- async def __aenter__(self):
17
- session = AioSession()
18
- self._client = await self._exit_stack.enter_async_context(
19
- session.create_client("sns")
20
- )
21
-
22
- async def __aexit__(self, exc_type, exc_val, exc_tb):
23
- await self._exit_stack.__aexit__(exc_type, exc_val, exc_tb)
24
-
25
- async def send_sms(
26
- self, phone_number: str, message: str, message_id: str, group_id: str
27
- ) -> dict:
28
- validate_e164_phone_number(phone_number)
29
- await self._client.publish(
30
- **{
31
- "PhoneNumber": phone_number,
32
- "Message": message,
33
- "MessageDeduplicationId": message_id,
34
- "MessageGroupId": group_id,
35
- }
36
- )
37
-
38
-
39
- async def main() -> None:
40
- notifier = AWSNotifier()
41
- message_id = str(uuid.uuid4())
42
- await notifier.send_sms(
43
- "+17133049421", "This is a test message", message_id, "message-group"
44
- )
45
- return
46
-
47
-
48
- if __name__ == "__main__":
49
- asyncio.run(main())