Skip to content

Commit 11c6b5d

Browse files
authored
Support QLDB shell migration (#43)
Add support for QLDB shell migration
1 parent 06c8146 commit 11c6b5d

File tree

7 files changed

+33
-30
lines changed

7 files changed

+33
-30
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ __pycache__/
1717
/doc/_apidoc/
1818
/docs/build/*
1919
/build
20-
/dist
20+
/dist
21+
/venv

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Add support for obtaining basic server-side statistics on individual statement e
66
* `get_consumed_ios` returns a dictionary containing the number of read IO requests for a statement execution.
77
* `get_timing_information` returns a dictionary containing the server side processing time in milliseconds for a statement execution.
88
* `get_consumed_ios` and `get_timing_information` methods in the `StreamCursor` class are stateful, meaning the statistics returned by them reflect the state at the time of method execution.
9+
* Add `transaction_id` property in `Executor` to provide the Transaction ID if needed.
10+
* The `Config` parameter of `QldbDriver` now appends the `user_agent_extra` value instead of overwriting it.
911

1012
### Release 3.0.0 (August 20, 2020)
1113
This is a public and generally available(GA) release of the driver, and this version can be used in production applications.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ to write software that makes use of AmazonQLDB.
55

66
[![Latest Version](https://img.shields.io/pypi/v/pyqldb.svg)](https://pypi.python.org/pypi/pyqldb)
77
[![Documentation Status](https://readthedocs.org/projects/amazon-qldb-driver-python/badge/?version=latest)](https://amazon-qldb-driver-python.readthedocs.io/en/latest/?badge=latest)
8+
[![Build Status](https://github.com/awslabs/amazon-qldb-driver-python/workflows/Python%20application/badge.svg)](https://github.com/awslabs/amazon-qldb-driver-python/actions?query=workflow%3A%22Python+application%22)
89

910
For our tutorial, see [Python and Amazon QLDB](https://docs.aws.amazon.com/qldb/latest/developerguide/getting-started.python.html).
1011

pyqldb/driver/qldb_driver.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
SERVICE_DESCRIPTION = 'QLDB Driver for Python v{}'.format(__version__)
3232
SERVICE_NAME = 'qldb-session'
3333
SERVICE_RETRY = {'max_attempts': 0}
34-
DEFAULT_CONFIG = Config(user_agent_extra=SERVICE_DESCRIPTION, retries=SERVICE_RETRY)
3534
DEFAULT_RETRY_CONFIG = RetryConfig()
3635

3736

@@ -74,7 +73,7 @@ class QldbDriver:
7473
:param aws_session_token: See [1].
7574
7675
:type config: :py:class:`botocore.config.Config`
77-
:param config: See [2]. Note that parameter user_agent_extra will be overwritten.
76+
:param config: See [2]. Note that parameter user_agent_extra will be appended and retries will be overwritten.
7877
7978
:type boto3_session: :py:class:`boto3.session.Session`
8079
:param boto3_session: The boto3 session to create the client with (see [1]). The boto3 session is expected to be
@@ -116,9 +115,14 @@ def __init__(self, ledger_name, retry_config=None, read_ahead=0, executor=None,
116115
if not isinstance(config, Config):
117116
raise TypeError('config must be of type botocore.config.Config. Found: {}'
118117
.format(type(config).__name__))
119-
self._config = config.merge(DEFAULT_CONFIG)
118+
self._config = config
119+
self._config.retries = SERVICE_RETRY
120+
if self._config.user_agent_extra:
121+
self._config.user_agent_extra = ' '.join([SERVICE_DESCRIPTION, self._config.user_agent_extra])
122+
else:
123+
self._config.user_agent_extra = SERVICE_DESCRIPTION
120124
else:
121-
self._config = DEFAULT_CONFIG
125+
self._config = Config(user_agent_extra=SERVICE_DESCRIPTION, retries=SERVICE_RETRY)
122126

123127
if retry_config is not None:
124128
if not isinstance(retry_config, RetryConfig):

pyqldb/execution/executor.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ class Executor:
2525
def __init__(self, transaction):
2626
self._transaction = transaction
2727

28+
@property
29+
def transaction_id(self):
30+
"""
31+
The **read-only** ID of this transaction.
32+
"""
33+
return self._transaction.transaction_id
34+
2835
def abort(self):
2936
"""
3037
Abort the transaction and roll back any changes.

tests/unit/test_executor.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
class TestExecutor(TestCase):
2727

2828
def test_Executor(self, mock_transaction):
29+
mock_transaction.transaction_id = 'txnId'
2930
executor = Executor(mock_transaction)
3031

3132
self.assertEqual(executor._transaction, mock_transaction)
33+
self.assertEqual(executor.transaction_id, 'txnId')
3234

3335
def test_abort(self, mock_transaction):
3436
executor = Executor(mock_transaction)

tests/unit/test_qldb_driver.py

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from botocore.config import Config
1717
from boto3.session import Session
1818

19-
from pyqldb.driver.qldb_driver import QldbDriver
19+
from pyqldb.driver.qldb_driver import QldbDriver, SERVICE_DESCRIPTION
2020
from pyqldb.errors import DriverClosedError
2121
from pyqldb.session.qldb_session import QldbSession
2222

@@ -27,7 +27,7 @@
2727
DEFAULT_BACKOFF_BASE = 10
2828
DEFAULT_TIMEOUT_SECONDS = 0.001
2929
EMPTY_STRING = ''
30-
MOCK_CONFIG = Config()
30+
MOCK_CONFIG = Config(user_agent_extra='user_agent')
3131
MOCK_LEDGER_NAME = 'QLDB'
3232
MOCK_MESSAGE = 'message'
3333
MOCK_BOTO3_SESSION = Session()
@@ -39,22 +39,18 @@ class TestQldbDriver(TestCase):
3939
@patch('pyqldb.driver.qldb_driver.AtomicInteger')
4040
@patch('pyqldb.driver.qldb_driver.BoundedSemaphore')
4141
@patch('pyqldb.driver.qldb_driver.client')
42-
@patch('pyqldb.driver.qldb_driver.Config.merge')
43-
def test_constructor_with_valid_config(self, mock_config_merge, mock_client, mock_bounded_semaphore,
42+
def test_constructor_with_valid_config(self, mock_client, mock_bounded_semaphore,
4443
mock_atomic_integer, mock_queue):
4544
mock_queue.return_value = mock_queue
4645
mock_atomic_integer.return_value = mock_atomic_integer
4746
mock_bounded_semaphore.return_value = mock_bounded_semaphore
4847
mock_client.return_value = mock_client
49-
mock_config_merge.return_value = mock_config_merge
50-
mock_config_merge.max_pool_connections = DEFAULT_MAX_CONCURRENT_TRANSACTIONS
5148

5249
qldb_driver = QldbDriver(MOCK_LEDGER_NAME, config=MOCK_CONFIG)
5350

54-
mock_config_merge.assert_called_once()
5551
mock_client.assert_called_once_with(DEFAULT_SESSION_NAME, aws_access_key_id=None,
5652
aws_secret_access_key=None, aws_session_token=None,
57-
config=mock_config_merge, endpoint_url=None, region_name=None, verify=None)
53+
config=MOCK_CONFIG, endpoint_url=None, region_name=None, verify=None)
5854
self.assertEqual(qldb_driver._ledger_name, MOCK_LEDGER_NAME)
5955
self.assertEqual(qldb_driver._retry_config.retry_limit, DEFAULT_RETRY_LIMIT)
6056
self.assertEqual(qldb_driver._retry_config.base, DEFAULT_BACKOFF_BASE)
@@ -77,26 +73,22 @@ def test_constructor_with_invalid_config(self, mock_client):
7773
@patch('pyqldb.driver.qldb_driver.AtomicInteger')
7874
@patch('pyqldb.driver.qldb_driver.BoundedSemaphore')
7975
@patch('pyqldb.driver.qldb_driver.client')
80-
@patch('pyqldb.driver.qldb_driver.Config.merge')
81-
def test_default_constructor_with_parameters(self, mock_config_merge, mock_client, mock_bounded_semaphore,
76+
def test_default_constructor_with_parameters(self, mock_client, mock_bounded_semaphore,
8277
mock_atomic_integer, mock_queue):
8378
mock_queue.return_value = mock_queue
8479
mock_atomic_integer.return_value = mock_atomic_integer
8580
mock_bounded_semaphore.return_value = mock_bounded_semaphore
8681
mock_client.return_value = mock_client
87-
mock_config_merge.return_value = mock_config_merge
88-
mock_config_merge.max_pool_connections = DEFAULT_MAX_CONCURRENT_TRANSACTIONS
8982

9083
qldb_driver = QldbDriver(MOCK_LEDGER_NAME, region_name=EMPTY_STRING, verify=EMPTY_STRING,
9184
endpoint_url=EMPTY_STRING, aws_access_key_id=EMPTY_STRING,
9285
aws_secret_access_key=EMPTY_STRING, aws_session_token=EMPTY_STRING,
9386
config=MOCK_CONFIG)
9487

95-
mock_config_merge.assert_called_once()
9688
mock_client.assert_called_once_with(DEFAULT_SESSION_NAME, region_name=EMPTY_STRING, verify=EMPTY_STRING,
9789
endpoint_url=EMPTY_STRING, aws_access_key_id=EMPTY_STRING,
9890
aws_secret_access_key=EMPTY_STRING, aws_session_token=EMPTY_STRING,
99-
config=mock_config_merge)
91+
config=MOCK_CONFIG)
10092
self.assertEqual(qldb_driver._ledger_name, MOCK_LEDGER_NAME)
10193
self.assertEqual(qldb_driver._retry_config.retry_limit, DEFAULT_RETRY_LIMIT)
10294
self.assertEqual(qldb_driver._retry_config.base, DEFAULT_BACKOFF_BASE)
@@ -108,28 +100,22 @@ def test_default_constructor_with_parameters(self, mock_config_merge, mock_clien
108100
mock_atomic_integer.assert_called_once_with(DEFAULT_MAX_CONCURRENT_TRANSACTIONS)
109101
mock_queue.assert_called_once_with()
110102

111-
@patch('pyqldb.driver.qldb_driver.Config.merge')
112-
def test_constructor_with_boto3_session(self, mock_config_merge):
103+
def test_constructor_with_boto3_session(self):
113104
mock_session = Mock(spec=MOCK_BOTO3_SESSION)
114-
mock_config_merge.return_value = mock_config_merge
115-
mock_config_merge.max_pool_connections = DEFAULT_MAX_CONCURRENT_TRANSACTIONS
116105

117106
qldb_driver = QldbDriver(MOCK_LEDGER_NAME, boto3_session=mock_session, config=MOCK_CONFIG)
118-
mock_session.client.assert_called_once_with(DEFAULT_SESSION_NAME, config=mock_config_merge, endpoint_url=None,
107+
mock_session.client.assert_called_once_with(DEFAULT_SESSION_NAME, config=MOCK_CONFIG, endpoint_url=None,
119108
verify=None)
120109
self.assertEqual(qldb_driver._client, mock_session.client())
110+
self.assertTrue(SERVICE_DESCRIPTION in qldb_driver._config.user_agent_extra)
121111

122112
@patch('pyqldb.driver.qldb_driver.logger.warning')
123-
@patch('pyqldb.driver.qldb_driver.Config.merge')
124-
def test_constructor_with_boto3_session_and_parameters_that_may_overwrite(self, mock_config_merge,
125-
mock_logger_warning):
113+
def test_constructor_with_boto3_session_and_parameters_that_may_overwrite(self, mock_logger_warning):
126114
mock_session = Mock(spec=MOCK_BOTO3_SESSION)
127-
mock_config_merge.return_value = mock_config_merge
128-
mock_config_merge.max_pool_connections = DEFAULT_MAX_CONCURRENT_TRANSACTIONS
129115
region_name = 'region_name'
130116
qldb_driver = QldbDriver(MOCK_LEDGER_NAME, boto3_session=mock_session, config=MOCK_CONFIG,
131117
region_name=region_name)
132-
mock_session.client.assert_called_once_with(DEFAULT_SESSION_NAME, config=mock_config_merge, endpoint_url=None,
118+
mock_session.client.assert_called_once_with(DEFAULT_SESSION_NAME, config=MOCK_CONFIG, endpoint_url=None,
133119
verify=None)
134120
self.assertEqual(qldb_driver._client, mock_session.client())
135121
mock_logger_warning.assert_called_once()

0 commit comments

Comments
 (0)