pyapiary 2.3.0__tar.gz → 2.3.1__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 (66) hide show
  1. {pyapiary-2.3.0 → pyapiary-2.3.1}/PKG-INFO +1 -1
  2. {pyapiary-2.3.0 → pyapiary-2.3.1}/pyproject.toml +1 -1
  3. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/dbms_connectors/trino.py +2 -6
  4. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_trino/test_unit_trino.py +46 -33
  5. {pyapiary-2.3.0 → pyapiary-2.3.1}/README.md +0 -0
  6. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/__init__.py +0 -0
  7. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/api_connectors/__init__.py +0 -0
  8. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/api_connectors/broker.py +0 -0
  9. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/api_connectors/domaintools.py +0 -0
  10. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/api_connectors/flashpoint.py +0 -0
  11. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/api_connectors/generic.py +0 -0
  12. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/api_connectors/ipqs.py +0 -0
  13. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/api_connectors/spycloud.py +0 -0
  14. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/api_connectors/twilio.py +0 -0
  15. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/api_connectors/urlscan.py +0 -0
  16. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/dbms_connectors/__init__.py +0 -0
  17. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/dbms_connectors/elasticsearch.py +0 -0
  18. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/dbms_connectors/mongo.py +0 -0
  19. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/dbms_connectors/mongo_async.py +0 -0
  20. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/dbms_connectors/odbc.py +0 -0
  21. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/dbms_connectors/postgres.py +0 -0
  22. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/dbms_connectors/splunk.py +0 -0
  23. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/helpers.py +0 -0
  24. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/__init__.py +0 -0
  25. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/conftest.py +0 -0
  26. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_broker/test_integration_broker.py +0 -0
  27. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_broker/test_unit_asyncbroker.py +0 -0
  28. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_broker/test_unit_broker.py +0 -0
  29. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_domaintools/cassettes/.gitkeep +0 -0
  30. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_domaintools/cassettes/test_domaintools_iris_investigate_vcr.yaml +0 -0
  31. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_domaintools/cassettes/test_domaintools_parsed_whois_vcr.yaml +0 -0
  32. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_domaintools/test_integration_domaintools.py +0 -0
  33. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_domaintools/test_unit_async_domaintools.py +0 -0
  34. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_domaintools/test_unit_domaintools.py +0 -0
  35. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_elasticsearch/test_unit_elasticsearch.py +0 -0
  36. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_flashpoint/cassettes/test_flashpoint_search_fraud_vcr.yaml +0 -0
  37. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_flashpoint/test_integration_flashpoint.py +0 -0
  38. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_flashpoint/test_unit_async_flashpoint.py +0 -0
  39. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_flashpoint/test_unit_flashpoint.py +0 -0
  40. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_generic/cassettes/test_generic_get_github_api.yaml +0 -0
  41. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_generic/test_integration_generic_connector.py +0 -0
  42. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_generic/test_unit_async_generic_connector.py +0 -0
  43. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_generic/test_unit_generic_connector.py +0 -0
  44. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_ipqs/__init__.py +0 -0
  45. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_ipqs/cassettes/test_ipqs_malicious_url_vcr.yaml +0 -0
  46. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_ipqs/cassettes/test_ipqs_phone_validation_vcr.yaml +0 -0
  47. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_ipqs/test_integration_ipqs.py +0 -0
  48. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_ipqs/test_unit_async_ipqs.py +0 -0
  49. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_ipqs/test_unit_ipqs.py +0 -0
  50. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_mongodb/test_unit_async_mongo.py +0 -0
  51. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_mongodb/test_unit_mongo.py +0 -0
  52. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_odbc/test_unit_odbc.py +0 -0
  53. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_postgres/test_unit_postgres.py +0 -0
  54. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_splunk/test_unit_splunk.py +0 -0
  55. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_spycloud/cassettes/test_spycloud_ato_search_vcr.yaml +0 -0
  56. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_spycloud/test_integration_spycloud.py +0 -0
  57. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_spycloud/test_unit_async_spycloud.py +0 -0
  58. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_spycloud/test_unit_spycloud.py +0 -0
  59. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_twilio/cassettes/test_lookup_phone_vcr.yaml +0 -0
  60. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_twilio/test_integration_twilio.py +0 -0
  61. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_twilio/test_unit_async_twilio.py +0 -0
  62. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_twilio/test_unit_twilio.py +0 -0
  63. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_urlscan/cassettes/test_urlscan_results_vcr.yaml +0 -0
  64. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_urlscan/test_integration_urlscan.py +0 -0
  65. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_urlscan/test_unit_async_urlscan.py +0 -0
  66. {pyapiary-2.3.0 → pyapiary-2.3.1}/src/pyapiary/tests/test_urlscan/test_unit_urlscan.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyapiary
3
- Version: 2.3.0
3
+ Version: 2.3.1
4
4
  Summary: A simple, lightweight set of connectors and functions to various APIs and DBMSs, controlled by a central broker.
5
5
  Author: Rob D'Aveta
6
6
  Author-email: rob.daveta@gmail.com
@@ -1,7 +1,7 @@
1
1
  [tool.poetry]
2
2
  name = "pyapiary"
3
3
  packages = [{ include = "pyapiary", from = "src" }]
4
- version = "2.3.0"
4
+ version = "2.3.1"
5
5
  description = "A simple, lightweight set of connectors and functions to various APIs and DBMSs, controlled by a central broker."
6
6
  authors = ["Rob D'Aveta <rob.daveta@gmail.com>"]
7
7
  readme = "README.md"
@@ -2,13 +2,9 @@ from trino.dbapi import connect
2
2
  from typing import List, Dict, Any
3
3
 
4
4
  class TrinoConnector:
5
- def __init__(self, host, port, user, catalog=None, schema=None):
5
+ def __init__(self, **kwargs):
6
6
  self.conn = connect(
7
- host=host,
8
- port=port,
9
- user=user,
10
- catalog=catalog,
11
- schema=schema
7
+ **kwargs
12
8
  )
13
9
 
14
10
  def query(self, query_str):
@@ -1,5 +1,5 @@
1
1
  import pytest
2
- from unittest.mock import MagicMock, patch, call
2
+ from unittest.mock import MagicMock, patch
3
3
  from pyapiary.dbms_connectors.trino import TrinoConnector
4
4
 
5
5
 
@@ -15,11 +15,12 @@ def mock_connect(mocker):
15
15
  def connector(mock_connect):
16
16
  """Return a TrinoConnector backed by a mocked connection."""
17
17
  return TrinoConnector(
18
- host="localhost",
19
- port=8080,
18
+ host="trino.trashcollector.dev",
19
+ port=443,
20
20
  user="test_user",
21
21
  catalog="hive",
22
22
  schema="default",
23
+ http_scheme="https",
23
24
  )
24
25
 
25
26
 
@@ -28,31 +29,33 @@ def connector(mock_connect):
28
29
  # ---------------------------------------------------------------------------
29
30
 
30
31
  class TestInit:
31
- def test_connect_called_with_correct_args(self, mocker):
32
+ def test_connect_called_with_provided_kwargs(self, mocker):
32
33
  mock_connect = mocker.patch("pyapiary.dbms_connectors.trino.connect")
33
- TrinoConnector(host="myhost", port=9090, user="alice", catalog="iceberg", schema="raw")
34
+ TrinoConnector(host="myhost", port=443, user="alice", http_scheme="https")
34
35
  mock_connect.assert_called_once_with(
35
36
  host="myhost",
36
- port=9090,
37
+ port=443,
37
38
  user="alice",
38
- catalog="iceberg",
39
- schema="raw",
39
+ http_scheme="https",
40
40
  )
41
41
 
42
- def test_connect_called_without_optional_args(self, mocker):
42
+ def test_connect_called_with_minimal_kwargs(self, mocker):
43
43
  mock_connect = mocker.patch("pyapiary.dbms_connectors.trino.connect")
44
- TrinoConnector(host="myhost", port=9090, user="alice")
45
- mock_connect.assert_called_once_with(
46
- host="myhost",
47
- port=9090,
48
- user="alice",
49
- catalog=None,
50
- schema=None,
51
- )
44
+ TrinoConnector(host="myhost", port=8080, user="alice")
45
+ mock_connect.assert_called_once_with(host="myhost", port=8080, user="alice")
52
46
 
53
47
  def test_conn_attribute_set(self, mock_connect, connector):
54
48
  assert connector.conn is mock_connect
55
49
 
50
+ def test_arbitrary_kwargs_forwarded(self, mocker):
51
+ """Any kwarg the trino client supports should be forwarded as-is."""
52
+ mock_connect = mocker.patch("pyapiary.dbms_connectors.trino.connect")
53
+ TrinoConnector(host="h", port=443, user="u", http_scheme="https",
54
+ verify=False, session_properties={"query_max_run_time": "1h"})
55
+ _, call_kwargs = mock_connect.call_args
56
+ assert call_kwargs["verify"] is False
57
+ assert call_kwargs["session_properties"] == {"query_max_run_time": "1h"}
58
+
56
59
 
57
60
  # ---------------------------------------------------------------------------
58
61
  # query()
@@ -108,7 +111,17 @@ class TestQuery:
108
111
  mock_connect.cursor.return_value.__enter__.return_value = mock_cursor
109
112
 
110
113
  with pytest.raises(RuntimeError, match="syntax error"):
111
- connector.query("SELECT bad syntax %%")
114
+ connector.query("SELECT bad %%")
115
+
116
+ def test_show_catalogs(self, mock_connect, connector):
117
+ mock_cursor = MagicMock()
118
+ mock_cursor.description = [("Catalog",)]
119
+ mock_cursor.fetchall.return_value = [("hive",), ("iceberg",), ("tpch",)]
120
+ mock_connect.cursor.return_value.__enter__.return_value = mock_cursor
121
+
122
+ result = connector.query("SHOW CATALOGS")
123
+
124
+ assert result == [("hive",), ("iceberg",), ("tpch",)]
112
125
 
113
126
 
114
127
  # ---------------------------------------------------------------------------
@@ -123,27 +136,18 @@ class TestBulkInsert:
123
136
  result = connector.bulk_insert("my_table", [{"id": 1, "name": "alice"}])
124
137
 
125
138
  expected_query = "INSERT INTO my_table (id, name) VALUES (?, ?)"
126
- mock_cursor.executemany.assert_called_once_with(
127
- expected_query, [(1, "alice")]
128
- )
139
+ mock_cursor.executemany.assert_called_once_with(expected_query, [(1, "alice")])
129
140
  assert result is True
130
141
 
131
142
  def test_inserts_multiple_rows(self, mock_connect, connector):
132
143
  mock_cursor = MagicMock()
133
144
  mock_connect.cursor.return_value.__enter__.return_value = mock_cursor
134
145
 
135
- data = [
136
- {"id": 1, "val": "a"},
137
- {"id": 2, "val": "b"},
138
- {"id": 3, "val": "c"},
139
- ]
146
+ data = [{"id": 1, "val": "a"}, {"id": 2, "val": "b"}, {"id": 3, "val": "c"}]
140
147
  result = connector.bulk_insert("my_table", data)
141
148
 
142
- expected_values = [(1, "a"), (2, "b"), (3, "c")]
143
- _, call_values = mock_cursor.executemany.call_args
144
- # positional args
145
149
  actual_values = mock_cursor.executemany.call_args[0][1]
146
- assert actual_values == expected_values
150
+ assert actual_values == [(1, "a"), (2, "b"), (3, "c")]
147
151
  assert result is True
148
152
 
149
153
  def test_returns_none_for_empty_list(self, mock_connect, connector, capsys):
@@ -165,10 +169,10 @@ class TestBulkInsert:
165
169
  mock_cursor = MagicMock()
166
170
  mock_connect.cursor.return_value.__enter__.return_value = mock_cursor
167
171
 
168
- connector.bulk_insert("schema.target_table", [{"x": 99}])
172
+ connector.bulk_insert("hive.default.target_table", [{"x": 99}])
169
173
 
170
174
  actual_query = mock_cursor.executemany.call_args[0][0]
171
- assert "schema.target_table" in actual_query
175
+ assert "hive.default.target_table" in actual_query
172
176
 
173
177
  def test_column_order_matches_first_row_keys(self, mock_connect, connector):
174
178
  mock_cursor = MagicMock()
@@ -178,10 +182,19 @@ class TestBulkInsert:
178
182
  connector.bulk_insert("t", data)
179
183
 
180
184
  actual_query = mock_cursor.executemany.call_args[0][0]
181
- # columns in query should match key order of first dict
182
185
  for col in ["z", "a", "m"]:
183
186
  assert col in actual_query
184
187
 
188
+ def test_placeholder_count_matches_column_count(self, mock_connect, connector):
189
+ mock_cursor = MagicMock()
190
+ mock_connect.cursor.return_value.__enter__.return_value = mock_cursor
191
+
192
+ data = [{"a": 1, "b": 2, "c": 3, "d": 4}]
193
+ connector.bulk_insert("t", data)
194
+
195
+ actual_query = mock_cursor.executemany.call_args[0][0]
196
+ assert actual_query.count("?") == 4
197
+
185
198
  def test_propagates_executemany_exception(self, mock_connect, connector):
186
199
  mock_cursor = MagicMock()
187
200
  mock_cursor.executemany.side_effect = RuntimeError("DB write error")
File without changes