strideutils 0.7.7__tar.gz → 0.7.9__tar.gz

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 (44) hide show
  1. {strideutils-0.7.7 → strideutils-0.7.9}/.bumpversion.cfg +1 -1
  2. {strideutils-0.7.7 → strideutils-0.7.9}/.github/workflows/publish.yml +4 -2
  3. {strideutils-0.7.7 → strideutils-0.7.9}/.github/workflows/test.yml +3 -1
  4. strideutils-0.7.9/MANIFEST.in +1 -0
  5. {strideutils-0.7.7 → strideutils-0.7.9}/Makefile +0 -3
  6. {strideutils-0.7.7 → strideutils-0.7.9}/PKG-INFO +1 -1
  7. {strideutils-0.7.7 → strideutils-0.7.9}/pyproject.toml +1 -1
  8. strideutils-0.7.9/strideutils/exec_tx.py +62 -0
  9. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/redis_connector.py +7 -14
  10. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/stride_config.py +0 -12
  11. strideutils-0.7.9/strideutils/strideutils/__init__.pyi +0 -0
  12. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils.egg-info/PKG-INFO +1 -1
  13. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils.egg-info/SOURCES.txt +2 -0
  14. {strideutils-0.7.7 → strideutils-0.7.9}/tests/test_sheets_connector.py +1 -1
  15. strideutils-0.7.9/tests/test_twilio_connector.py +92 -0
  16. strideutils-0.7.7/strideutils/exec_tx.py +0 -62
  17. strideutils-0.7.7/tests/test_twilio_connector.py +0 -80
  18. {strideutils-0.7.7 → strideutils-0.7.9}/.github/workflows/lint.yml +0 -0
  19. {strideutils-0.7.7 → strideutils-0.7.9}/.github/workflows/version.yaml +0 -0
  20. {strideutils-0.7.7 → strideutils-0.7.9}/.gitignore +0 -0
  21. {strideutils-0.7.7 → strideutils-0.7.9}/LICENSE +0 -0
  22. {strideutils-0.7.7 → strideutils-0.7.9}/README.md +0 -0
  23. {strideutils-0.7.7 → strideutils-0.7.9}/setup.cfg +0 -0
  24. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/Makefile +0 -0
  25. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/__init__.py +0 -0
  26. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/coingecko.py +0 -0
  27. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/config_examples/env.local.example +0 -0
  28. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/config_examples/strideutils_config.yaml.example +0 -0
  29. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/cryptography.py +0 -0
  30. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/invariant_helpers.py +0 -0
  31. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/run_safely.py +0 -0
  32. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/sheets_connector.py +0 -0
  33. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/slack_connector.py +0 -0
  34. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/stride_alerts.py +0 -0
  35. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/stride_requests.py +0 -0
  36. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/twilio_connector.py +0 -0
  37. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils/types.py +0 -0
  38. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils.egg-info/dependency_links.txt +0 -0
  39. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils.egg-info/requires.txt +0 -0
  40. {strideutils-0.7.7 → strideutils-0.7.9}/strideutils.egg-info/top_level.txt +0 -0
  41. {strideutils-0.7.7 → strideutils-0.7.9}/tests/test_config.py +0 -0
  42. {strideutils-0.7.7 → strideutils-0.7.9}/tests/test_encryption.py +0 -0
  43. {strideutils-0.7.7 → strideutils-0.7.9}/tests/test_redis_connector.py +0 -0
  44. {strideutils-0.7.7 → strideutils-0.7.9}/tests/test_slack_connector.py +0 -0
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 0.7.7
2
+ current_version = 0.7.9
3
3
  commit = False
4
4
  tag = False
5
5
 
@@ -23,7 +23,7 @@ jobs:
23
23
  - name: setup
24
24
  run: |
25
25
  python -m pip install -U pip
26
- pip install --upgrade build setuptools twine wheel bump2version toml-cli
26
+ pip install --upgrade build setuptools twine wheel bump2version toml-cli mypy
27
27
  git config user.name "GitHub Actions"
28
28
  git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
29
29
 
@@ -55,5 +55,7 @@ jobs:
55
55
  TWINE_USERNAME: "__token__"
56
56
  TWINE_PASSWORD: "${{ secrets.PYPI_TOKEN }}"
57
57
  run: |
58
+ stubgen -m strideutils -o ./strideutils
59
+ echo "include strideutils/*.pyi" >> MANIFEST.in
58
60
  python -m build
59
- twine upload dist/*
61
+ twine upload dist/*
@@ -12,6 +12,8 @@ on:
12
12
  jobs:
13
13
  test:
14
14
  runs-on: ubuntu-latest
15
+ env:
16
+ ENV: DEV
15
17
  steps:
16
18
  - uses: actions/checkout@v3
17
19
 
@@ -26,4 +28,4 @@ jobs:
26
28
  pip install -e .[dev]
27
29
 
28
30
  - name: Run tests
29
- run: pytest tests -v
31
+ run: pytest tests -v
@@ -0,0 +1 @@
1
+ include strideutils/*.pyi
@@ -21,9 +21,6 @@ format:
21
21
 
22
22
  tidy: lint type-check format
23
23
 
24
- stub-gen:
25
- $(PYTHON) run stubgen -p strideutils -o pyi
26
-
27
24
  test:
28
25
  @echo "Running unit tests..."
29
26
  @$(VENV_BIN)/pytest . -v
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: strideutils
3
- Version: 0.7.7
3
+ Version: 0.7.9
4
4
  Summary: Utility functions for monitoring the Stride blockchain
5
5
  Author-email: Stride Labs <hello@stridelabs.co>
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "strideutils"
7
- version = "0.7.7"
7
+ version = "0.7.9"
8
8
  authors = [
9
9
  {name = "Stride Labs", email = "hello@stridelabs.co"},
10
10
  ]
@@ -0,0 +1,62 @@
1
+ import json
2
+ import re
3
+ import subprocess
4
+ import time
5
+ from dataclasses import dataclass
6
+ from typing import Optional
7
+
8
+ from strideutils import stride_requests
9
+ from strideutils.stride_config import config
10
+
11
+
12
+ @dataclass
13
+ class TxResponse:
14
+ stdout: dict
15
+ stderr: str
16
+ tx_hash: str = ""
17
+ success: bool = False
18
+ code: Optional[int] = None
19
+ tx_response: Optional[dict] = None
20
+ raw_log: Optional[str] = None
21
+
22
+
23
+ def execute_tx(command: str, api_endpoint: str = config.stride.api_endpoint) -> TxResponse:
24
+ """
25
+ Execute a tx and query the tx hash
26
+ """
27
+ # Tack on the auto-confirm if it's not already in the command and capture the output as JSON
28
+ if "-y" not in command:
29
+ command += " -y"
30
+ command += " --output json"
31
+
32
+ # Run the command in the shell and store the response
33
+ output = subprocess.run(command, shell=True, capture_output=True, text=True)
34
+
35
+ # If there was stderr, return the response as failed
36
+ if not output.stdout or output.stderr:
37
+ return TxResponse(stdout={}, stderr=output.stderr, raw_log=output.stderr)
38
+
39
+ # Cast the stdout and build the response
40
+ response = TxResponse(stdout=json.loads(output.stdout), stderr=output.stderr)
41
+
42
+ # Get the tx hash or return an error if one was not generated
43
+ response.tx_hash = response.stdout.get("txhash", "")
44
+ if response.tx_hash == "":
45
+ response.raw_log = "Tx hash not found after running tx"
46
+ return response
47
+
48
+ # Poll the tx hash for the codeID and raw log
49
+ for _ in range(30):
50
+ response_data = stride_requests.get_tx(response.tx_hash, api_endpoint=api_endpoint)
51
+ if not response_data.get("tx_response"):
52
+ time.sleep(2)
53
+ continue
54
+
55
+ response.code = int(response_data["tx_response"]["code"])
56
+ response.raw_log = response_data["tx_response"]["raw_log"]
57
+ response.success = response.code == 0
58
+ return response
59
+
60
+ # If the tx was never found on chain, return an error
61
+ response.raw_log = "Transaction not found on chain after one minute"
62
+ return response
@@ -14,6 +14,8 @@ import redis
14
14
  from strideutils.stride_config import Environment as e
15
15
  from strideutils.stride_config import get_env_or_raise
16
16
 
17
+ # TODO: add SSL option flag, defaulting to false
18
+
17
19
  # TODO: Remove and use from environment variables
18
20
  DATABASE_HOSTS = {
19
21
  "public": "usw1-certain-beagle-33773.upstash.io",
@@ -61,22 +63,12 @@ ALL_DATABASE_NAMES = list(DATABASE_ENVIRONMENT_CONFIGS.keys())
61
63
 
62
64
 
63
65
  class RedisClient:
64
- """Singleton client used to interact with Redis databases."""
66
+ """Redis client to connect to mulitple databases at once"""
65
67
 
66
- _instance = None
68
+ # Mapping of database name to redis client
67
69
  _dbs: Dict[str, redis.Redis] = {}
68
70
 
69
- def __new__(cls, db_names: Optional[List[str] | str] = None):
70
- if cls._instance is None:
71
- cls._instance = super(RedisClient, cls).__new__(cls)
72
- cls._instance.__init__(db_names)
73
- return cls._instance
74
-
75
- def __init__(self, db_names: Optional[List[str] | str] = None):
76
- if len(self._dbs) == 0:
77
- self._init_dbs(db_names)
78
-
79
- def _init_dbs(self, db_name_or_names: Optional[List[str] | str] = None):
71
+ def __init__(self, db_name_or_names: Optional[List[str] | str] = None):
80
72
  """
81
73
  Initializes Redis database connections.
82
74
 
@@ -117,6 +109,7 @@ class RedisClient:
117
109
  host = DATABASE_HOSTS.get(database_name)
118
110
  port = DATABASE_PORTS.get(database_name)
119
111
  password = get_env_or_raise(password_env)
112
+ ssl = database_name != "public"
120
113
 
121
114
  if not host or not port:
122
115
  raise ValueError(f"Host or port not known for database {database_name}")
@@ -125,7 +118,7 @@ class RedisClient:
125
118
  "host": host,
126
119
  "port": port,
127
120
  "password": password,
128
- "ssl": True,
121
+ "ssl": ssl,
129
122
  "decode_responses": True,
130
123
  }
131
124
 
@@ -218,9 +218,6 @@ class Config(ConfigObj):
218
218
  ENV: str
219
219
  timezone: str = "US/Eastern"
220
220
 
221
- # Gsheets - loads from str env var in PROD
222
- PUBLICSHEETS_AUTH: Union[str, ConfigDict] = field(default_factory=ConfigDict)
223
-
224
221
  # Coingecko
225
222
  COINGECKO_API_TOKEN: str = ""
226
223
 
@@ -231,15 +228,6 @@ class Config(ConfigObj):
231
228
  alerts_playbook: str = ""
232
229
  slack_channels: ConfigDict = field(default_factory=ConfigDict)
233
230
 
234
- # Upstash
235
- UPSTASH_PUBLIC_PASSWORD: str = ""
236
- UPSTASH_STRIDE_FRONTEND_PASSWORD: str = ""
237
- UPSTASH_STRIDE_BACKEND_PASSWORD: str = ""
238
- UPSTASH_STRIDE_DYDX_PUBLIC_PASSWORD: str = ""
239
- UPSTASH_STRIDE_DYDX_AIRDROP_PASSWORD: str = ""
240
- UPSTASH_STRIDE_SAGA_AIRDROP_PASSWORD: str = ""
241
- UPSTASH_STRIDE_MILESTONES_PASSWORD: str = ""
242
-
243
231
  # Stride internal secrets
244
232
  SLACK_BEARER_TOKEN: str = ""
245
233
  SLACK_SUCCESS_CHANNEL_ID: str = ""
File without changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: strideutils
3
- Version: 0.7.7
3
+ Version: 0.7.9
4
4
  Summary: Utility functions for monitoring the Stride blockchain
5
5
  Author-email: Stride Labs <hello@stridelabs.co>
6
6
  License: MIT License
@@ -1,6 +1,7 @@
1
1
  .bumpversion.cfg
2
2
  .gitignore
3
3
  LICENSE
4
+ MANIFEST.in
4
5
  Makefile
5
6
  README.md
6
7
  pyproject.toml
@@ -30,6 +31,7 @@ strideutils.egg-info/requires.txt
30
31
  strideutils.egg-info/top_level.txt
31
32
  strideutils/config_examples/env.local.example
32
33
  strideutils/config_examples/strideutils_config.yaml.example
34
+ strideutils/strideutils/__init__.pyi
33
35
  tests/test_config.py
34
36
  tests/test_encryption.py
35
37
  tests/test_redis_connector.py
@@ -58,7 +58,7 @@ def test_sheets_write_sheet_new_worksheet(sheets_client):
58
58
  df = pd.DataFrame({'A': [1, 3], 'B': [2, 4]})
59
59
  sheets_client.write_sheet(df, 'sheet_id', 'new_sheet')
60
60
 
61
- mock_spreadsheet.add_worksheet.assert_called_once_with(title='new_sheet', rows="1", cols="1")
61
+ mock_spreadsheet.add_worksheet.assert_called_once_with(title='new_sheet', rows=1, cols=1)
62
62
 
63
63
  def test_sheets_reorder_sheet(sheets_client):
64
64
  mock_spreadsheet = MagicMock()
@@ -0,0 +1,92 @@
1
+ import pytest
2
+ from unittest.mock import patch, MagicMock
3
+ from twilio.rest import Client as TwilioRestClient
4
+ from strideutils.twilio_connector import TwilioClient
5
+ from strideutils.stride_config import Environment as e
6
+
7
+ @pytest.fixture(autouse=True)
8
+ def reset_twilio_client():
9
+ TwilioClient._instance = None
10
+ yield
11
+ TwilioClient._instance = None
12
+
13
+ @pytest.fixture
14
+ def mock_twilio_rest_client():
15
+ with patch('strideutils.twilio_connector.Client') as mock:
16
+ mock_instance = MagicMock()
17
+ mock.return_value = mock_instance
18
+ yield mock_instance
19
+
20
+ @pytest.fixture(autouse=True)
21
+ def mock_env_vars():
22
+ with patch('strideutils.twilio_connector.get_env_or_raise') as mock_get_env:
23
+ def side_effect(arg):
24
+ if arg == e.TWILIO_ACCOUNT_ID:
25
+ return 'fake_account_id'
26
+ elif arg == e.TWILIO_API_TOKEN:
27
+ return 'fake_api_token'
28
+ elif arg == e.TWILIO_ALERTS_NUMBER:
29
+ return 'fake_alert_numbers'
30
+ return 'dummy_value'
31
+ mock_get_env.side_effect = side_effect
32
+ yield mock_get_env
33
+
34
+ @pytest.fixture
35
+ def twilio_client(mock_twilio_rest_client, mock_env_vars):
36
+ client = TwilioClient()
37
+ return client
38
+
39
+ def test_twilio_client_singleton():
40
+ client1 = TwilioClient()
41
+ client2 = TwilioClient()
42
+ assert client1 is client2
43
+
44
+ def test_twilio_client_initialization(twilio_client, mock_env_vars):
45
+ assert twilio_client.account_id == 'fake_account_id'
46
+ assert twilio_client.api_token == 'fake_api_token'
47
+ assert twilio_client.alert_numbers == 'fake_alert_numbers'
48
+ assert isinstance(twilio_client.client, MagicMock)
49
+
50
+ def test_call_single_recipient(twilio_client, mock_twilio_rest_client):
51
+ with patch('strideutils.twilio_connector.config') as mock_config:
52
+ mock_config.PHONE_NUMBERS = {'recipient': '+12223334444'}
53
+ mock_config.TWILIO_ALERTS_NUMBER = '+15556667777'
54
+
55
+ twilio_client.call("Test message", "recipient")
56
+
57
+ expected_twiml = "<Response><Say>Test message</Say></Response>"
58
+ mock_twilio_rest_client.calls.create.assert_called_once_with(
59
+ to='+12223334444',
60
+ from_='+15556667777',
61
+ twiml=expected_twiml
62
+ )
63
+
64
+ def test_call_multiple_recipients(twilio_client, mock_twilio_rest_client):
65
+ with patch('strideutils.twilio_connector.config') as mock_config:
66
+ mock_config.PHONE_NUMBERS = {
67
+ 'recipient1': '+12223334444',
68
+ 'recipient2': '+13334445555'
69
+ }
70
+ mock_config.TWILIO_ALERTS_NUMBER = '+15556667777'
71
+
72
+ twilio_client.call("Test message", ["recipient1", "recipient2"])
73
+
74
+ expected_twiml = "<Response><Say>Test message</Say></Response>"
75
+ assert mock_twilio_rest_client.calls.create.call_count == 2
76
+ mock_twilio_rest_client.calls.create.assert_any_call(
77
+ to='+12223334444',
78
+ from_='+15556667777',
79
+ twiml=expected_twiml
80
+ )
81
+ mock_twilio_rest_client.calls.create.assert_any_call(
82
+ to='+13334445555',
83
+ from_='+15556667777',
84
+ twiml=expected_twiml
85
+ )
86
+
87
+ def test_call_invalid_recipient(twilio_client, mock_twilio_rest_client):
88
+ with patch('strideutils.twilio_connector.config') as mock_config:
89
+ mock_config.PHONE_NUMBERS = {}
90
+
91
+ with pytest.raises(KeyError):
92
+ twilio_client.call("Test message", "invalid_recipient")
@@ -1,62 +0,0 @@
1
- import re
2
- import subprocess
3
- import time
4
- from dataclasses import dataclass
5
- from typing import Optional
6
-
7
- from strideutils import stride_requests
8
- from strideutils.stride_config import config
9
-
10
-
11
- @dataclass
12
- class TxResponse:
13
- stdout: str
14
- stderr: str
15
- tx_response: Optional[dict] = None
16
- tx_hash: Optional[str] = None
17
- success: bool = False
18
- raw_log: Optional[str] = None
19
-
20
-
21
- def execute_tx(command: str, api_endpoint: str = config.stride.api_endpoint, verbose=False) -> TxResponse:
22
- """
23
- Execute a tx and query the tx hash
24
- """
25
- output = subprocess.run(command, shell=True, capture_output=True)
26
- standard_out = re.sub(r'\x1b\[[0-9;]*[mGKH]', '', output.stdout.decode('utf-8'))
27
- error_out = re.sub(r'\x1b\[[0-9;]*[mGKH]', '', output.stderr.decode('utf-8'))
28
- if verbose:
29
- print("Standard Out: ", standard_out)
30
- print("Error Out: ", error_out)
31
- tx_hash = ""
32
- for output_line in standard_out.split('\n'):
33
- if 'txhash' in output_line:
34
- tx_hash = output_line.split(': ')[-1]
35
-
36
- tx_response = None
37
- response_success = False
38
- raw_log = "Transaction not found on chain after one minute" # default message
39
- if not error_out:
40
- event_filters = [(f"tx.hash='{tx_hash}'")]
41
- for _ in range(30):
42
- time.sleep(2)
43
- tx_response = stride_requests.get_txs(event_filters, api_endpoint)
44
- if tx_response.get('tx_responses'):
45
- try:
46
- response_code = tx_response['tx_responses'][0]['code']
47
- raw_log = tx_response['tx_responses'][0]['raw_log']
48
- response_success = response_code == 0
49
- except KeyError:
50
- response_success = False
51
- break
52
-
53
- success = response_success and not error_out
54
- response = TxResponse(
55
- stdout=standard_out,
56
- stderr=error_out,
57
- tx_response=tx_response,
58
- success=success,
59
- tx_hash=tx_hash,
60
- raw_log=raw_log,
61
- )
62
- return response
@@ -1,80 +0,0 @@
1
- import pytest
2
- from unittest.mock import patch, MagicMock
3
- from twilio.rest import Client as TwilioRestClient
4
-
5
- from strideutils.twilio_connector import TwilioClient
6
-
7
- @pytest.fixture
8
- def mock_twilio_client():
9
- with patch('strideutils.twilio_connector.Client') as mock_client:
10
- yield mock_client.return_value
11
-
12
- @pytest.fixture
13
- def twilio_client(mock_twilio_client):
14
- with patch('strideutils.twilio_connector.get_env_or_raise') as mock_get_env:
15
- mock_get_env.side_effect = ['fake_account_id', 'fake_api_token', 'fake_alert_numbers']
16
- client = TwilioClient()
17
- client.client = mock_twilio_client # Replaced the real Twilio client with a mock, to not send to the real.
18
- yield client
19
-
20
- def test_twilio_client_singleton():
21
- with patch('strideutils.twilio_connector.Client'):
22
- with patch('strideutils.twilio_connector.get_env_or_raise'):
23
- client1 = TwilioClient()
24
- client2 = TwilioClient()
25
- assert client1 is client2
26
-
27
- def test_call_single_recipient(twilio_client, mock_twilio_client):
28
- with patch('strideutils.twilio_connector.config') as mock_config:
29
- mock_config.PHONE_NUMBERS = {'recipient': '+12223334444'}
30
- mock_config.TWILIO_ALERTS_NUMBER = '+15556667777'
31
-
32
- twilio_client.call("Test message", "recipient")
33
-
34
- expected_twiml = "<Response><Say>Test message</Say></Response>"
35
- mock_twilio_client.calls.create.assert_called_once_with(
36
- to='+12223334444',
37
- from_='+15556667777',
38
- twiml=expected_twiml
39
- )
40
-
41
- def test_call_multiple_recipients(twilio_client, mock_twilio_client):
42
- with patch('strideutils.twilio_connector.config') as mock_config:
43
- mock_config.PHONE_NUMBERS = {
44
- 'recipient1': '+12223334444',
45
- 'recipient2': '+13334445555'
46
- }
47
- mock_config.TWILIO_ALERTS_NUMBER = '+15556667777'
48
-
49
- twilio_client.call("Test message", ["recipient1", "recipient2"])
50
-
51
- expected_twiml = "<Response><Say>Test message</Say></Response>"
52
- assert mock_twilio_client.calls.create.call_count == 2
53
- mock_twilio_client.calls.create.assert_any_call(
54
- to='+12223334444',
55
- from_='+15556667777',
56
- twiml=expected_twiml
57
- )
58
- mock_twilio_client.calls.create.assert_any_call(
59
- to='+13334445555',
60
- from_='+15556667777',
61
- twiml=expected_twiml
62
- )
63
-
64
- def test_call_invalid_recipient(twilio_client, mock_twilio_client):
65
- with patch('strideutils.twilio_connector.config') as mock_config:
66
- mock_config.PHONE_NUMBERS = {}
67
-
68
- with pytest.raises(KeyError):
69
- twilio_client.call("Test message", "invalid_recipient")
70
-
71
- @patch('strideutils.twilio_connector.get_env_or_raise')
72
- def test_twilio_client_initialization(mock_get_env):
73
- mock_get_env.side_effect = ['fake_account_id', 'fake_api_token', 'fake_alert_numbers'] # just dummy values, so this should fail.
74
-
75
- client = TwilioClient()
76
-
77
- assert client.account_id == 'fake_account_id'
78
- assert client.api_token == 'fake_api_token'
79
- assert client.alert_numbers == 'fake_alert_numbers'
80
- assert isinstance(client.client, TwilioRestClient)
File without changes
File without changes
File without changes
File without changes