Skip to content

Commit 0bb4dff

Browse files
authored
[TOOLSLIBS-2387] Add file_data to EmailAttachment (#218)
* adds file_data to email attachment * update for version bump * fix some typing issues * additional type checks * true up local and CI mypy runs * mypy issues * fix or ignore mypy issues * more ci mypy fixes * more typing return fixes * mypy thrashin
1 parent 312c20f commit 0bb4dff

File tree

21 files changed

+350
-309
lines changed

21 files changed

+350
-309
lines changed

.github/workflows/test_runner.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
python -m pip install -r requirements-dev.txt
2222
- name: Type check with mypy
2323
run: |
24-
mypy urbanairship/
24+
mypy --config-file=pyproject.toml --ignore-missing-imports --disable-error-code=no-any-return urbanairship/
2525
- name: Test with pytest
2626
run: |
2727
python -m pytest

.pre-commit-config.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@ repos:
4545
rev: v1.9.0
4646
hooks:
4747
- id: mypy
48+
args: [--config-file=pyproject.toml, --ignore-missing-imports, --disable-error-code=no-any-return]
49+
files: ^urbanairship/
50+
exclude: ^docs/
4851
additional_dependencies:
4952
- types-requests>=2.31.0.20240311
5053
- types-six>=1.16.21.20240311
5154
- types-mock>=5.1.0.20240311
5255
- types-urllib3
53-
exclude: ^(docs/|tests/)

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# urbanairship changelog
22

3+
## 7.1.0
4+
5+
- Adds file_data argument to the EmailAttachment class fir passing stringified file data.
6+
37
## 7.0.0
48

59
- Adds package type annotations

pyproject.toml

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ include = '\.pyi?$'
4242
[tool.isort]
4343
profile = "black"
4444
multi_line_output = 3
45-
line-length = 99
4645
include_trailing_comma = true
4746
force_grid_wrap = 0
4847
use_parentheses = true
@@ -84,3 +83,28 @@ omit = [
8483
"tests/*",
8584
"setup.py",
8685
]
86+
87+
[tool.mypy]
88+
python_version = "3.10"
89+
warn_return_any = true
90+
warn_unused_configs = true
91+
disallow_untyped_defs = false
92+
disallow_incomplete_defs = false
93+
check_untyped_defs = false
94+
disallow_untyped_decorators = false
95+
no_implicit_optional = true
96+
warn_redundant_casts = true
97+
warn_unused_ignores = true
98+
warn_no_return = true
99+
warn_unreachable = true
100+
strict_equality = true
101+
show_error_codes = true
102+
ignore_missing_imports = true
103+
disable_error_code = "unreachable"
104+
105+
[[tool.mypy.overrides]]
106+
module = [
107+
"tests.*",
108+
"docs.*",
109+
]
110+
ignore_errors = true

tests/devices/test_email.py

Lines changed: 81 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ def test_email_update_payload(self):
8181
def test_email_reg(self):
8282
with mock.patch.object(ua.Airship, "_request") as mock_request:
8383
response = requests.Response()
84-
response._content = json.dumps(
85-
{"ok": True, "channel_id": self.channel_id}
86-
).encode("utf-8")
84+
response._content = json.dumps({"ok": True, "channel_id": self.channel_id}).encode(
85+
"utf-8"
86+
)
8787
response.status_code = 201
8888
mock_request.return_value = response
8989

@@ -98,9 +98,9 @@ def test_email_w_opt_dates(self):
9898
test_date = "2018-11-06T12:00:00Z"
9999
with mock.patch.object(ua.Airship, "_request") as mock_request:
100100
response = requests.Response()
101-
response._content = json.dumps(
102-
{"ok": True, "channel_id": self.channel_id}
103-
).encode("utf-8")
101+
response._content = json.dumps({"ok": True, "channel_id": self.channel_id}).encode(
102+
"utf-8"
103+
)
104104
response.status_code = 201
105105
mock_request.return_value = response
106106

@@ -121,9 +121,9 @@ def test_email_w_opt_dates(self):
121121
def test_email_update(self):
122122
with mock.patch.object(ua.Airship, "_request") as mock_request:
123123
response = requests.Response()
124-
response._content = json.dumps(
125-
{"ok": True, "channel_id": self.channel_id}
126-
).encode("utf-8")
124+
response._content = json.dumps({"ok": True, "channel_id": self.channel_id}).encode(
125+
"utf-8"
126+
)
127127
response.status_code = 200
128128
mock_request.return_value = response
129129

@@ -137,9 +137,9 @@ def test_email_update(self):
137137
def test_email_reg_w_opts(self):
138138
with mock.patch.object(ua.Airship, "_request") as mock_request:
139139
response = requests.Response()
140-
response._content = json.dumps(
141-
{"ok": True, "channel_id": self.channel_id}
142-
).encode("utf-8")
140+
response._content = json.dumps({"ok": True, "channel_id": self.channel_id}).encode(
141+
"utf-8"
142+
)
143143
response.status_code = 201
144144
mock_request.return_value = response
145145

@@ -161,9 +161,9 @@ def test_email_reg_w_opts(self):
161161
def test_email_uninstall(self):
162162
with mock.patch.object(ua.Airship, "_request") as mock_request:
163163
response = requests.Response()
164-
response._content = json.dumps(
165-
{"ok": True, "channel_id": self.channel_id}
166-
).encode("utf-8")
164+
response._content = json.dumps({"ok": True, "channel_id": self.channel_id}).encode(
165+
"utf-8"
166+
)
167167
response.status_code = 200
168168
mock_request.return_value = response
169169

@@ -188,9 +188,7 @@ def test_email_lookup(self):
188188
lookup = ua.Email.lookup(airship=self.airship, address=self.address)
189189

190190
self.assertEqual(200, lookup.status_code)
191-
self.assertEqual(
192-
"email", json.loads(lookup.content)["channel"]["device_type"]
193-
)
191+
self.assertEqual("email", json.loads(lookup.content)["channel"]["device_type"])
194192

195193

196194
class TestEmailTags(unittest.TestCase):
@@ -256,19 +254,30 @@ def testSetWithAddAndRemove(self):
256254

257255
class TestEmailAttachment(unittest.TestCase):
258256
def setUp(self):
257+
with open("tests/data/logo.png", "rb") as f:
258+
self.file_bytes = f.read()
259+
self.encoded = str(base64.urlsafe_b64encode(self.file_bytes))
260+
259261
self.attachment = ua.EmailAttachment(
260262
airship=ua.Airship(TEST_KEY, TEST_SECRET),
261263
filename="test_file.png",
262264
content_type='image/png; charset="UTF-8"',
263265
filepath="tests/data/logo.png",
264266
)
265-
file = open("tests/data/logo.png", "rb").read()
266-
self.encoded = str(base64.urlsafe_b64encode(file))
267267

268-
def test_encoding(self):
268+
def test_encoding_with_filepath(self):
269269
self.assertEqual(self.encoded, self.attachment.req_payload.get("data"))
270270

271-
def test_payload(self):
271+
def test_encoding_with_file_data(self):
272+
attachment_with_data = ua.EmailAttachment(
273+
airship=ua.Airship(TEST_KEY, TEST_SECRET),
274+
filename="test_file.png",
275+
content_type='image/png; charset="UTF-8"',
276+
file_data=self.file_bytes,
277+
)
278+
self.assertEqual(self.encoded, attachment_with_data.req_payload.get("data"))
279+
280+
def test_payload_with_filepath(self):
272281
self.assertDictEqual(
273282
self.attachment.req_payload,
274283
{
@@ -277,3 +286,53 @@ def test_payload(self):
277286
"data": self.encoded,
278287
},
279288
)
289+
290+
def test_payload_with_file_data(self):
291+
attachment_with_data = ua.EmailAttachment(
292+
airship=ua.Airship(TEST_KEY, TEST_SECRET),
293+
filename="test_file.png",
294+
content_type='image/png; charset="UTF-8"',
295+
file_data=self.file_bytes,
296+
)
297+
self.assertDictEqual(
298+
attachment_with_data.req_payload,
299+
{
300+
"filename": "test_file.png",
301+
"content_type": 'image/png; charset="UTF-8"',
302+
"data": self.encoded,
303+
},
304+
)
305+
306+
def test_validation_no_parameters(self):
307+
with self.assertRaises(ValueError) as context:
308+
ua.EmailAttachment(
309+
airship=ua.Airship(TEST_KEY, TEST_SECRET),
310+
filename="test_file.png",
311+
content_type='image/png; charset="UTF-8"',
312+
)
313+
self.assertIn("filepath or file_data must be provided", str(context.exception))
314+
315+
def test_validation_both_parameters(self):
316+
with self.assertRaises(ValueError) as context:
317+
ua.EmailAttachment(
318+
airship=ua.Airship(TEST_KEY, TEST_SECRET),
319+
filename="test_file.png",
320+
content_type='image/png; charset="UTF-8"',
321+
filepath="tests/data/logo.png",
322+
file_data=self.file_bytes,
323+
)
324+
self.assertIn("filepath and file_data cannot both be provided", str(context.exception))
325+
326+
def test_post_method(self):
327+
with mock.patch.object(ua.Airship, "_request") as mock_request:
328+
response = requests.Response()
329+
response._content = json.dumps({"ok": True, "attachment_ids": ["test-id"]}).encode(
330+
"utf-8"
331+
)
332+
response.status_code = 200
333+
mock_request.return_value = response
334+
335+
result = self.attachment.post()
336+
337+
self.assertEqual({"ok": True, "attachment_ids": ["test-id"]}, result)
338+
mock_request.assert_called_once()

urbanairship/__about__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "7.0.0"
1+
__version__ = "7.1.0"

0 commit comments

Comments
 (0)