Skip to content

Commit 5cd553b

Browse files
committed
feat: Add allow_deletes option to QuickbaseTableClient (#56)
Also makes the QuickbaseApiClient rf (RequestFactory) attribute private, and removes unused "default_select" from QuickbaseTableClient (which was accidentally lingering). Lastly, forwards arguments from the .client factory method in QuickbaseTable classes.
1 parent 0c9b867 commit 5cd553b

10 files changed

Lines changed: 64 additions & 30 deletions

File tree

CHANGELOG.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
CHANGELOG
33
==========
44

5+
`0.6.0`_ (2022-5-2)
6+
---------------------
7+
8+
* Add ``allow_deletes`` option to ``QuickbaseTableClient`` (`#56`_)
9+
* Forward kwargs from ``QuickbaseTable.client`` to ``QuickbaseTableClient`` (`#56`_)
10+
* Make the ``rf`` prop of ``QuickbaseApiClient`` private as it is not really part of the API
11+
12+
513
`0.5.2`_ (2022-4-14)
614
---------------------
715

@@ -74,6 +82,9 @@ CHANGELOG
7482
.. _`0.3.1`: https://github.com/tkutcher/quickbase-client/releases/tag/v0.3.1
7583
.. _`0.4.0`: https://github.com/tkutcher/quickbase-client/releases/tag/v0.4.0
7684
.. _`0.5.0`: https://github.com/tkutcher/quickbase-client/releases/tag/v0.5.0
85+
.. _`0.5.1`: https://github.com/tkutcher/quickbase-client/releases/tag/v0.5.1
86+
.. _`0.5.2`: https://github.com/tkutcher/quickbase-client/releases/tag/v0.5.2
87+
.. _`0.6.0`: https://github.com/tkutcher/quickbase-client/releases/tag/v0.6.0
7788

7889

7990
..
@@ -91,6 +102,7 @@ CHANGELOG
91102
.. _`#52`: https://github.com/tkutcher/quickbase-client/issues/52
92103
.. _`#53`: https://github.com/tkutcher/quickbase-client/issues/53
93104
.. _`#54`: https://github.com/tkutcher/quickbase-client/issues/54
105+
.. _`#56`: https://github.com/tkutcher/quickbase-client/issues/56
94106

95107

96108
..

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "quickbase-client"
3-
version = "0.5.3"
3+
version = "0.6.0"
44
description = "A Quickbase Python API Client Generator"
55
authors = ["Tim Kutcher <tim@tkutcher.com>"]
66
maintainers = ["Tim Kutcher <tim@tkutcher.com>"]

src/quickbase_client/client/api.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,49 +21,49 @@ class QuickbaseApiClient(object):
2121
"""
2222

2323
def __init__(self, user_token, realm_hostname, agent="python", allow_deletes=False):
24-
self.rf = QuickbaseRequestFactory(
24+
self._rf = QuickbaseRequestFactory(
2525
user_token, realm_hostname, agent, allow_deletes=allow_deletes
2626
)
2727
self.legacy_api = QuickbaseLegacyApiClient(user_token, realm_hostname)
2828

2929
def request(self, *args, **kwargs):
30-
return self.rf.make_request(*args, **kwargs)
30+
return self._rf.make_request(*args, **kwargs)
3131

3232
# FUTURE - Can add more of these methods, even refactoring in to separate classes
3333
# for each main endpoint. Initially just including some of the more common
3434
# functions.
3535

3636
def get_app(self, app_id):
37-
return self.rf.get(f"/apps/{app_id}")
37+
return self._rf.get(f"/apps/{app_id}")
3838

3939
def get_tables_for_app(self, app_id):
40-
return self.rf.get("/tables", params={"appId": app_id})
40+
return self._rf.get("/tables", params={"appId": app_id})
4141

4242
def get_table(self, app_id, table_id):
43-
return self.rf.get(f"/tables/{table_id}", params={"appId": app_id})
43+
return self._rf.get(f"/tables/{table_id}", params={"appId": app_id})
4444

4545
def get_fields_for_table(self, table_id):
46-
return self.rf.get("/fields", params={"tableId": table_id})
46+
return self._rf.get("/fields", params={"tableId": table_id})
4747

4848
def get_field(self, field_id, table_id):
49-
return self.rf.get(f"/fields/{field_id}", params={"tableId": table_id})
49+
return self._rf.get(f"/fields/{field_id}", params={"tableId": table_id})
5050

5151
def get_reports_for_table(self, table_id):
52-
return self.rf.get("/reports", params={"tableId": table_id})
52+
return self._rf.get("/reports", params={"tableId": table_id})
5353

5454
def get_report(self, report_id, table_id):
55-
return self.rf.get(f"/reports/{report_id}", params={"tableId": table_id})
55+
return self._rf.get(f"/reports/{report_id}", params={"tableId": table_id})
5656

5757
def run_report(self, report_id, table_id, skip=None, top=None):
5858
payload = make_payload({"skip": skip, "top": top})
59-
return self.rf.post(
59+
return self._rf.post(
6060
f"/reports/{report_id}/run", params={"tableId": table_id}, data=payload
6161
)
6262

6363
def add_records(
6464
self, table_id, data=None, merge_field_id=None, fields_to_return=None
6565
):
66-
return self.rf.post(
66+
return self._rf.post(
6767
"/records",
6868
data=make_payload(
6969
{
@@ -84,7 +84,7 @@ def query(
8484
group_by=None,
8585
options=None,
8686
):
87-
return self.rf.post(
87+
return self._rf.post(
8888
"/records/query",
8989
data=make_payload(
9090
{

src/quickbase_client/client/table_client.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ class QuickbaseTableClient(object):
3939
:param normalize_unicode:
4040
Whether the JSON Serializer should normalize accented characters so that they
4141
can be encoded in Quickbase.
42+
43+
:param bool allow_deletes:
44+
Whether the client should be allowed to perform delete requests. Defaulted to
45+
False for now. But note that this is subject to change in 1.0 if there is a
46+
different general preference.
4247
"""
4348

4449
def __init__(
@@ -47,14 +52,18 @@ def __init__(
4752
user_token,
4853
agent="python",
4954
normalize_unicode=True,
50-
default_select=None,
55+
allow_deletes=False,
5156
):
5257
self.table = table
5358
self.serializer = RecordJsonSerializer(
5459
table_cls=self.table, normalize_unicode=normalize_unicode
5560
)
56-
self.api = QuickbaseApiClient(user_token, table.realm_hostname(), agent=agent)
57-
self._default_select = default_select
61+
self.api = QuickbaseApiClient(
62+
user_token,
63+
table.realm_hostname(),
64+
agent=agent,
65+
allow_deletes=allow_deletes,
66+
)
5867

5968
@property
6069
def app_id(self):

src/quickbase_client/orm/table.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,15 @@ def get_attr_from_fid(cls, fid: int):
113113
return cls.__fidmap__[fid] # noqa
114114

115115
@classmethod
116-
def client(cls, user_token: str):
116+
def client(cls, user_token: str, **kwargs):
117117
"""Factory method to create a :class:`~QuickbaseTableClient` for this table.
118118
119119
:param user_token: The user token for authentication.
120+
:param kwargs: Forwarded to :class:`~QuickbaseTableClient`.
120121
"""
121122
from quickbase_client.client.table_client import QuickbaseTableClient
122123

123-
return QuickbaseTableClient(cls, user_token)
124+
return QuickbaseTableClient(cls, user_token, **kwargs)
124125

125126

126127
QuickBaseTable = QuickbaseTable # alias - TODO - delete in future.

src/quickbase_client/query/query_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class QuickbaseQuery(object):
44
.. note::
55
Current alias of ``QuickbaseQuery`` for backwards compatibility.
66
7-
:param str where: The where string, e.g. ``"{7.EX.'18'}"``
7+
:param Optional[str] where: The where string, e.g. ``"{7.EX.'18'}"``
88
99
:param dict options:
1010
Additional options to pass to the Quickbase runQuery endpoint.

tests/test_client/test_api.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ def test_makes_request_factory(self):
1212
client = QuickbaseApiClient(
1313
user_token="foo", realm_hostname="dicorp.quickbase.com"
1414
)
15-
assert client.rf.user_token == "foo"
16-
assert client.rf.realm_hostname == "dicorp.quickbase.com"
15+
assert client._rf.user_token == "foo"
16+
assert client._rf.realm_hostname == "dicorp.quickbase.com"
1717

1818
def test_request_alias(self, mocker):
1919
client = QuickbaseApiClient(
2020
user_token="foo", realm_hostname="dicorp.quickbase.com"
2121
)
22-
spy = mocker.spy(client.rf.session, "request")
22+
spy = mocker.spy(client._rf.session, "request")
2323
client.request(method="POST", endpoint="/blah")
2424
_, kwargs = spy.call_args
2525
assert kwargs["method"] == "POST"
@@ -30,7 +30,7 @@ def test_class_is_aliases(self, mocker):
3030
client = QuickBaseApiClient(
3131
user_token="foo", realm_hostname="dicorp.quickbase.com"
3232
)
33-
spy = mocker.spy(client.rf.session, "request")
33+
spy = mocker.spy(client._rf.session, "request")
3434
client.request(method="POST", endpoint="/blah")
3535
_, kwargs = spy.call_args
3636
assert kwargs["method"] == "POST"
@@ -39,7 +39,7 @@ def test_query(self, mocker):
3939
client = QuickbaseApiClient(
4040
user_token="foo", realm_hostname="dicorp.quickbase.com"
4141
)
42-
spy = mocker.spy(client.rf.session, "request")
42+
spy = mocker.spy(client._rf.session, "request")
4343
client.query(table_id="aaaaaa", where_str="{'18'.EX.19}")
4444
_, kwargs = spy.call_args
4545
assert "{'18'.EX.19}" in json.dumps(kwargs["json"])

tests/test_client/test_table_client.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def test_makes_api_request_to_correct_url(
4444
)
4545
def test_request_includes_proper_headers(self, mocker, debugs_table, header, val):
4646
client = QuickbaseTableClient(debugs_table, user_token="myusertoken")
47-
spy = mocker.spy(client.api.rf.session, "request")
47+
spy = mocker.spy(client.api._rf.session, "request")
4848
client.get_table()
4949
args, kwargs = spy.call_args
5050
headers = kwargs["headers"]
@@ -56,7 +56,7 @@ def test_add_record_posts_data_as_list(self, requests_mock, mocker, debugs_table
5656
"https://api.quickbase.com/v1/records", json={"blah": "bleh"}
5757
)
5858
client = QuickbaseTableClient(debugs_table, user_token="doesnotmatter")
59-
spy = mocker.spy(client.api.rf.session, "request")
59+
spy = mocker.spy(client.api._rf.session, "request")
6060
record = debugs_table(some_basic_text_field="hi", some_checkbox=False)
6161
client.add_record(record)
6262
args, kwargs = spy.call_args
@@ -69,7 +69,7 @@ def test_serializes_dates(self, requests_mock, mocker, debugs_table):
6969
"https://api.quickbase.com/v1/records", json={"blah": "bleh"}
7070
)
7171
client = QuickbaseTableClient(debugs_table, user_token="doesnotmatter")
72-
spy = mocker.spy(client.api.rf.session, "request")
72+
spy = mocker.spy(client.api._rf.session, "request")
7373
record = debugs_table(
7474
some_basic_text_field="hi", just_a_date=date(year=2020, month=2, day=7)
7575
)
@@ -80,7 +80,7 @@ def test_serializes_dates(self, requests_mock, mocker, debugs_table):
8080

8181
def test_add_record_does_not_post_null_values(self, mocker, debugs_table):
8282
client = QuickbaseTableClient(debugs_table, user_token="doesnotmatter")
83-
spy = mocker.spy(client.api.rf.session, "request")
83+
spy = mocker.spy(client.api._rf.session, "request")
8484
record = debugs_table(some_basic_text_field="hi", some_checkbox=False)
8585
client.add_record(record)
8686
args, kwargs = spy.call_args
@@ -107,3 +107,11 @@ def test_query_with_pager(self, debugs_table, qb_api_mock):
107107
client.query(pager=pager)
108108
assert pager.total_records == 4
109109
assert not pager.more_remaining()
110+
111+
def test_wrapped_request_factory_forwards_allow_deletes(
112+
self, debugs_table, qb_api_mock
113+
):
114+
client = QuickbaseTableClient(debugs_table, user_token="doesnotmatter")
115+
assert not client.api._rf.allow_deletes
116+
client = QuickbaseTableClient(debugs_table, user_token="a", allow_deletes=True)
117+
assert client.api._rf.allow_deletes

tests/test_orm/test_table.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,7 @@ def test_get_report(self, example_table):
6060
def test_make_client(self, example_table):
6161
c = example_table.client("foo")
6262
assert isinstance(c, QuickbaseTableClient)
63+
64+
def test_make_client_forwards_kwargs(self, example_table):
65+
c = example_table.client("foo", agent="foo")
66+
assert c.api._rf.agent == "foo"

tests/test_tools/test_log_handler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ def test_requires_correct_properties_if_default_record_factory(self):
4949
def test_posts_log_record(self, mocker):
5050
client = _MyLogsTable.client("foo")
5151
handler = QuickbaseLogHandler(client)
52-
spy = mocker.spy(client.api.rf.session, "request")
52+
spy = mocker.spy(client.api._rf.session, "request")
5353
handler._do_emit(MOCK_LOG)
5454
_, k = spy.call_args
5555
fid = str(_MyLogsTable.schema.level.fid)
5656
assert k["json"]["data"][0][fid]["value"] == MOCK_LOG_LEVEL
5757

5858
def test_create_with_record_factory(self, mocker):
5959
client = _MyLogsTable.client("foo")
60-
spy = mocker.spy(client.api.rf.session, "request")
60+
spy = mocker.spy(client.api._rf.session, "request")
6161

6262
def _mock_rf(record):
6363
return _MyLogsTable(message=record.msg)

0 commit comments

Comments
 (0)