Skip to content

Commit 49352e7

Browse files
committed
Refactored code to address review comments
1 parent 36a9d46 commit 49352e7

File tree

7 files changed

+61
-69
lines changed

7 files changed

+61
-69
lines changed

tap_trello/streams/abstracts.py

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
LOGGER = get_logger()
1313

14+
# NB: We've observed that Trello will only return 50 actions, this is to sub-paginate
15+
MAX_API_RESPONSE_SIZE = 50
16+
1417

1518
class OrderChecker:
1619
""" Class with context manager to check ordering of values. """
@@ -56,25 +59,14 @@ def __exit__(self, *args):
5659
""" Required for context manager usage. """
5760

5861

59-
class Mixin:
60-
""" Empty class to mark mixin classes as such. """
61-
62-
63-
class Unsortable(Mixin):
62+
class Unsortable:
6463
"""
65-
Mixin class to mark a Stream subclass as Unsortable
64+
Marker class to identify Stream subclasses that are unsortable.
6665
NB: No current functionality, but we thought it was useful for higher-order declarative behavior.
67-
e.g.:
68-
class MyStream(Unsortable, Stream):
69-
# Specify properties, implement unique things
7066
"""
7167

7268

73-
# NB: We've observed that Trello will only return 50 actions, this is to sub-paginate
74-
MAX_API_RESPONSE_SIZE = 50
75-
76-
77-
class DateWindowPaginated(Mixin):
69+
class DateWindowPaginated:
7870
"""
7971
Mixin class to provide date windowing on the `get_records` requests
8072
"""
@@ -241,48 +233,6 @@ def sync(self):
241233
yield rec
242234

243235

244-
class AddCustomFields(Mixin):
245-
def _get_dropdown_option_key(self, field_id, option_id):
246-
return field_id + '_' + option_id
247-
248-
def build_custom_fields_maps(self, **kwargs):
249-
custom_fields_map = {}
250-
dropdown_options_map = {}
251-
board_id_list = kwargs['parent_id_list']
252-
# The custom fields are defined on the board level, so this function is called on a per-board basis
253-
# Therefore, we assert that only one board is being passed in
254-
assert len(board_id_list) == 1
255-
custom_fields = self.client.get('/boards/{}/customFields'.format(board_id_list[0])) # pylint: disable=no-member
256-
for custom_field in custom_fields:
257-
custom_fields_map[custom_field['id']] = custom_field['name']
258-
if custom_field['type'] == 'list':
259-
for dropdown_option in custom_field['options']:
260-
dropdown_option_key = self._get_dropdown_option_key(dropdown_option['idCustomField'], dropdown_option['id'])
261-
dropdown_options_map[dropdown_option_key] = dropdown_option['value']['text']
262-
263-
return custom_fields_map, dropdown_options_map
264-
265-
266-
def modify_record(self, record, **kwargs):
267-
custom_fields_map = kwargs['custom_fields_map']
268-
dropdown_options_map = kwargs['dropdown_options_map']
269-
for custom_field in record['customFieldItems']:
270-
custom_field['name'] = custom_fields_map[custom_field['idCustomField']]
271-
if custom_field.get('idValue', None):
272-
dropdown_option_key = self._get_dropdown_option_key(custom_field['idCustomField'], custom_field['idValue'])
273-
custom_field['value'] = {'option': dropdown_options_map[dropdown_option_key]}
274-
275-
return record
276-
277-
278-
class AddBoardId(Mixin):
279-
def modify_record(self, record, **kwargs):
280-
board_id_list = kwargs['parent_id_list']
281-
assert len(board_id_list) == 1
282-
record["boardId"] = board_id_list[0]
283-
return record
284-
285-
286236
class LegacyChildStream(LegacyStream):
287237
"""
288238
Legacy base class for child streams (pre-refactor).

tap_trello/streams/actions.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44

55
class Actions(DateWindowPaginated, ChildStream):
6-
# TODO: If an action is completed on a board, does the board's dateLastActivity get updated?
76
stream_id = "actions"
87
stream_name = "actions"
98
endpoint = "/boards/{}/actions"
Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
from tap_trello.streams.abstracts import AddBoardId, FullTableStream
1+
from tap_trello.streams.abstracts import FullTableStream
22

3-
class BoardMemberships(FullTableStream, AddBoardId):
3+
class BoardMemberships(FullTableStream):
44
tap_stream_id = "board_memberships"
55
key_properties = ["id", "boardId"]
66
replication_method = "FULL_TABLE"
77
path = "/boards/{id}/memberships"
88
parent = "boards"
9+
10+
def modify_object(self, record, parent_record=None):
11+
"""Add boardId to board membership records."""
12+
if parent_record and 'id' in parent_record:
13+
record["boardId"] = parent_record['id']
14+
return record

tap_trello/streams/boards.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22

33

44
class Boards(Unsortable, Stream):
5-
# TODO: Should boards respect the start date? i.e., not emit records from before the configured start?
6-
# TODO: Is this also limited to 50 records per response? If so, might need paginated...
75
stream_id = "boards"
86
stream_name = "boards"
97
endpoint = "/members/{}/boards"
108
key_properties = ["id"]
119
replication_method = "FULL_TABLE"
1210

13-
1411
def get_format_values(self):
1512
return [self.client.member_id]

tap_trello/streams/cards.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import singer
22

3-
from tap_trello.streams.abstracts import AddCustomFields, ChildStream
3+
from tap_trello.streams.abstracts import ChildStream
44
from tap_trello.streams.boards import Boards
55

66
LOGGER = singer.get_logger()
77

88

9-
class Cards(AddCustomFields, ChildStream):
9+
class Cards(ChildStream):
1010
stream_id = "cards"
1111
stream_name = "cards"
1212
endpoint = "/boards/{}/cards/all"
@@ -15,6 +15,41 @@ class Cards(AddCustomFields, ChildStream):
1515
parent = Boards
1616
MAX_API_RESPONSE_SIZE = 1000
1717

18+
def _get_dropdown_option_key(self, field_id, option_id):
19+
"""Generate a unique key for dropdown options."""
20+
return field_id + '_' + option_id
21+
22+
def build_custom_fields_maps(self, **kwargs):
23+
"""Build maps of custom field IDs to names and dropdown option IDs to values."""
24+
custom_fields_map = {}
25+
dropdown_options_map = {}
26+
board_id_list = kwargs['parent_id_list']
27+
# The custom fields are defined on the board level, so this function is called on a per-board basis
28+
# Therefore, we validate that only one board is being passed in
29+
if len(board_id_list) != 1:
30+
raise ValueError(f"Expected exactly one board ID, got {len(board_id_list)}")
31+
custom_fields = self.client.get('/boards/{}/customFields'.format(board_id_list[0]))
32+
for custom_field in custom_fields:
33+
custom_fields_map[custom_field['id']] = custom_field['name']
34+
if custom_field['type'] == 'list':
35+
for dropdown_option in custom_field['options']:
36+
dropdown_option_key = self._get_dropdown_option_key(dropdown_option['idCustomField'], dropdown_option['id'])
37+
dropdown_options_map[dropdown_option_key] = dropdown_option['value']['text']
38+
39+
return custom_fields_map, dropdown_options_map
40+
41+
def modify_record(self, record, **kwargs):
42+
"""Add custom field names and dropdown values to card records."""
43+
custom_fields_map = kwargs['custom_fields_map']
44+
dropdown_options_map = kwargs['dropdown_options_map']
45+
for custom_field in record['customFieldItems']:
46+
custom_field['name'] = custom_fields_map[custom_field['idCustomField']]
47+
if custom_field.get('idValue', None):
48+
dropdown_option_key = self._get_dropdown_option_key(custom_field['idCustomField'], custom_field['idValue'])
49+
custom_field['value'] = {'option': dropdown_options_map[dropdown_option_key]}
50+
51+
return record
52+
1853
def get_records(self, format_values, additional_params=None):
1954
# Get max_api_response_size from config and set to parameter
2055
cards_response_size = int(self.config.get('cards_response_size') or self.MAX_API_RESPONSE_SIZE)

tap_trello/streams/lists.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44

55
class Lists(Unsortable, ChildStream):
6-
# TODO: If a list is added to a board, does the board's dateLastActivity get updated?
76
stream_id = "lists"
87
stream_name = "lists"
98
endpoint = "/boards/{}/lists"

tap_trello/streams/users.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
1-
from tap_trello.streams.abstracts import Unsortable, AddBoardId, ChildStream
1+
from tap_trello.streams.abstracts import Unsortable, ChildStream
22
from tap_trello.streams.boards import Boards
33

44

5-
class Users(Unsortable, AddBoardId, ChildStream):
6-
# TODO: If a user is added to a board, does the board's dateLastActivity get updated?
7-
# TODO: Should this assoc the board_id to the user records? Seems pretty useless without it
5+
class Users(Unsortable, ChildStream):
86
stream_id = "users"
97
stream_name = "users"
108
endpoint = "/boards/{}/members"
119
key_properties = ["id", "boardId"]
1210
replication_method = "FULL_TABLE"
1311
parent = Boards
12+
13+
def modify_record(self, record, **kwargs):
14+
"""Add boardId to user records."""
15+
board_id_list = kwargs['parent_id_list']
16+
if len(board_id_list) != 1:
17+
raise ValueError(f"Expected exactly one board ID, got {len(board_id_list)}")
18+
record["boardId"] = board_id_list[0]
19+
return record

0 commit comments

Comments
 (0)