Skip to content

Commit 7fb8604

Browse files
committed
Tech Debt: Upgrading boto to boto3 for api & ingester. Needed to use newer moto needed by client.
1 parent 31f5104 commit 7fb8604

File tree

15 files changed

+264
-205
lines changed

15 files changed

+264
-205
lines changed

.github/workflows/actions.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ on: [push, pull_request]
33

44
jobs:
55
test-client:
6-
runs-on: ubuntu-20.04
6+
runs-on: ubuntu-latest
7+
timeout-minutes: 30
78
strategy:
89
matrix:
910
python: [3.8, 3.9, "3.10", 3.12]
1011
extras: ["test", "test,queuable,sentry"]
1112
steps:
1213
- name: Setup Python
13-
uses: actions/setup-python@v2.2.2
14+
uses: actions/setup-python@v5
1415
with:
1516
python-version: ${{ matrix.python }}
1617
- name: Check out repository code
@@ -20,13 +21,14 @@ jobs:
2021
- name: Test
2122
working-directory: ./client
2223
run: |
23-
pip install -e .[${{ matrix.extras }}]
24-
py.test
24+
pip --version
25+
pip install --verbose .[${{ matrix.extras }}]
26+
python -m pytest --import-mode=importlib ./datalake/tests/
2527
test-docker:
2628
runs-on: ubuntu-latest
2729
steps:
2830
- name: Check out repository code
29-
uses: actions/checkout@v2
31+
uses: actions/checkout@v4
3032
with:
3133
fetch-depth: 0
3234
- name: Test

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,6 @@ target/
5858

5959
# build artifacts
6060
version.txt
61-
.claude/settings.local.json
61+
62+
# Claude Code
63+
.claude/

Dockerfile

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,33 @@ ENV LC_ALL C.UTF-8
77

88
# TODO: keep requirements in one place
99
RUN pip install \
10-
blinker>=1.4 \
11-
boto3>=1.1.3 \
12-
click>=5.1 \
13-
Flask>=0.10.1 \
14-
flask-swagger>=0.2.14 \
15-
memoized_property>=1.0.1 \
16-
python-dateutil>=2.4.2 \
17-
python-dotenv>=0.1.3 \
18-
pytz>=2015.4 \
19-
sentry-sdk[flask]>=0.19.5 \
20-
requests>=2.5 \
21-
simplejson>=3.3.1 \
22-
six>=1.10.0 \
10+
'blinker>=1.4' \
11+
'boto3==1.35.41' \
12+
'botocore==1.35.64' \
13+
'click>=5.1' \
14+
'datalake<2' \
15+
'Flask>=0.10.1' \
16+
'flask-swagger>=0.2.14' \
17+
'memoized_property>=1.0.1' \
18+
'pyinotify>=0.9.4' \
19+
'python-dateutil>=2.4.2' \
20+
'python-dotenv>=0.1.3' \
21+
'pytz>=2015.4' \
22+
'raven>=5.0.0' \
23+
'requests>=2.5' \
24+
'sentry-sdk[flask]>=0.19.5' \
25+
'simplejson>=3.3.1' \
26+
'six>=1.10.0' \
2327
# test requirements
2428
'flake8>=2.5.0,<4.1' \
2529
'freezegun<1' \
26-
'moto<3' \
30+
'moto>=5,<6' \
2731
'pytest<8' \
32+
'pytest-cov>=2.5.1,<4' \
33+
'pytest-xdist' \
2834
'responses<0.22.0' \
29-
pyinotify>=0.9.4, \
30-
raven>=5.0.0 \
31-
'tox>4,<5' \
32-
'datalake<2'
35+
'tox>4,<5'
36+
3337

3438
RUN mkdir -p /opt/
3539
COPY . /opt/

api/tests/conftest.py

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
ClientError as BotoClientError,
1919
NoCredentialsError
2020
)
21-
from moto import mock_dynamodb2
21+
from moto import mock_aws
2222

2323
from datalake_api import app as datalake_api
2424
from datalake.tests import * # noqa
@@ -33,30 +33,27 @@
3333
# This will cause moto to fail
3434
# But more critically, may impact production systems
3535
# So we test for real credentials and fail hard if they exist
36-
sts = boto3.client('sts')
37-
try:
38-
sts.get_caller_identity()
39-
pytest.exit("Real AWS credentials detected, aborting", 3)
40-
except NoCredentialsError:
41-
pass # no credentials are good
36+
# Session fixture runs in pytest setup rather than at import time
37+
@pytest.fixture(scope='session', autouse=True)
38+
def verify_no_aws_credentials():
39+
sts = boto3.client('sts')
40+
try:
41+
sts.get_caller_identity()
42+
pytest.exit("Real AWS credentials detected, aborting", 3)
43+
except NoCredentialsError:
44+
pass
4245

4346

4447
def get_client():
4548
from datalake_api import settings
4649
datalake_api.app.config.from_object(settings)
4750

4851
datalake_api.app.config['TESTING'] = True
52+
datalake_api.app.config['AWS_REGION'] = 'us-east-1'
4953
datalake_api.app.config['AWS_ACCESS_KEY_ID'] = 'abc'
5054
datalake_api.app.config['AWS_SECRET_ACCESS_KEY'] = '123'
5155

52-
# TODO: Sigh. The api caches the archive_fetcher and s3_bucket, which is
53-
# the right thing. However, because moto<3 still uses httpretty, and
54-
# because httpretty wreaks havoc on the python socket code, these cached
55-
# parts end up in a bad state after their first use. The right thing to do
56-
# here is to upgrade moto. But for that we will also have to move
57-
# everything from boto to boto3. This is a near-term goal. But first lets
58-
# get everything off of python2.
59-
for a in ('archive_fetcher', 's3_bucket'):
56+
for a in ('archive_fetcher', 's3_bucket', 'dynamodb'):
6057
try:
6158
delattr(datalake_api.app, a)
6259
except AttributeError:
@@ -71,15 +68,15 @@ def client():
7168

7269
@pytest.fixture
7370
def dynamodb(request):
74-
mock = mock_dynamodb2()
71+
mock = mock_aws()
7572
mock.start()
7673

7774
def tear_down():
7875
mock.stop()
7976
request.addfinalizer(tear_down)
8077

8178
return boto3.resource('dynamodb',
82-
region_name='us-west-2',
79+
region_name='us-east-1',
8380
aws_secret_access_key='123',
8481
aws_access_key_id='abc')
8582

client/datalake/tests/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121

2222
try:
23-
from moto import mock_s3
23+
from moto import mock_aws
2424
import boto3
2525
from six.moves.urllib.parse import urlparse
2626
import json
@@ -142,7 +142,7 @@ def tear_down():
142142

143143
@pytest.fixture
144144
def s3_connection(aws_connector):
145-
with mock_s3():
145+
with mock_aws():
146146
yield boto3.resource('s3')
147147

148148

client/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ dynamic = ["version"]
3737
test = [
3838
'pytest<8.0.0',
3939
'pytest-cov>=2.5.1,<4',
40-
'moto[s3]>4,<5',
40+
'moto[s3]>5,<6',
4141
'twine<4.0.0',
4242
'pip>=20.0.0,<22.0.0',
4343
'wheel<0.38.0',
@@ -73,7 +73,7 @@ distance-dirty = "{base_version}+{distance}.{vcs}{rev}.dirty"
7373
# Example formatted version: 1.2.3+42.ge174a1f.dirty
7474

7575
[tool.pytest.ini_options]
76-
addopts = "--cov=planet.mc_client --cov-config .coveragerc"
76+
addopts = "--cov=datalake --cov-config .coveragerc"
7777
markers = [
7878
"slow: marks tests as slow (deselect with '-m \"not slow\"')"
7979
]

ingester/datalake_ingester/queue.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# the License.
1414

1515
from memoized_property import memoized_property
16-
import boto.sqs
16+
import boto3
1717
import simplejson as json
1818
import logging
1919
import os
@@ -39,16 +39,13 @@ def set_handler(self, h):
3939
self.handler = h
4040

4141
@memoized_property
42-
def _queue(self):
43-
return self._connection.get_queue(self.queue_name)
42+
def _connection(self):
43+
region = os.environ.get('AWS_REGION', 'us-east-1')
44+
return boto3.resource('sqs', region_name=region)
4445

4546
@memoized_property
46-
def _connection(self):
47-
region = os.environ.get('AWS_REGION')
48-
if region:
49-
return boto.sqs.connect_to_region(region)
50-
else:
51-
return boto.connect_sqs()
47+
def _queue(self):
48+
return self._connection.get_queue_by_name(QueueName=self.queue_name)
5249

5350
_LONG_POLL_TIMEOUT = 20
5451

@@ -57,17 +54,19 @@ def drain(self, timeout=None):
5754
'''
5855
long_poll_timeout = timeout or self._LONG_POLL_TIMEOUT
5956
while True:
60-
raw_msg = self._queue.read(wait_time_seconds=long_poll_timeout)
61-
if raw_msg is None:
57+
messages = self._queue.receive_messages(
58+
MaxNumberOfMessages=1,
59+
WaitTimeSeconds=long_poll_timeout
60+
)
61+
if not messages:
6262
if timeout:
6363
return
6464
else:
6565
continue
66-
self._handle_raw_message(raw_msg)
66+
self._handle_raw_message(messages[0])
6767

6868
def _handle_raw_message(self, raw_msg):
69-
# eliminate newlines in raw message so it all logs to one line
70-
raw = raw_msg.get_body().replace('\n', ' ')
69+
raw = raw_msg.body.replace('\n', ' ')
7170
if not self.handler:
7271
self.logger.error('NO HANDLER CONFIGURED: %s', raw)
7372
return
@@ -76,4 +75,4 @@ def _handle_raw_message(self, raw_msg):
7675
msg = json.loads(raw)
7776

7877
self.handler(msg)
79-
self._queue.delete_message(raw_msg)
78+
raw_msg.delete()

ingester/datalake_ingester/reporter.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import boto.sns
1+
import boto3
22
import simplejson as json
33
import logging
44
from memoized_property import memoized_property
@@ -25,13 +25,10 @@ def _log_name(self):
2525

2626
@memoized_property
2727
def _connection(self):
28-
region = os.environ.get('AWS_REGION')
29-
if region:
30-
return boto.sns.connect_to_region(region)
31-
else:
32-
return boto.connect_sns()
28+
region = os.environ.get('AWS_REGION', 'us-east-1')
29+
return boto3.client('sns', region_name=region)
3330

3431
def report(self, ingestion_report):
3532
message = json.dumps(ingestion_report)
3633
self.logger.info('REPORTING: %s', message)
37-
self._connection.publish(topic=self.report_key, message=message)
34+
self._connection.publish(TopicArn=self.report_key, Message=message)

0 commit comments

Comments
 (0)