From 03e5dcebb5974ec6652e89395bc2f49dda369417 Mon Sep 17 00:00:00 2001
From: Miguel Gagliardo
Date: Mon, 30 Aug 2021 10:05:03 +0200
Subject: [PATCH 01/36] add endpoint for config service (#32)
---
README.md | 2 ++
localstack_client/config.py | 1 +
setup.py | 2 +-
3 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index f6c6f48..8a807a9 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,8 @@ make test
## Changelog
+* v1.24: Add endpoints for Config Service
+* v1.23: Add endpoints for QLDB Session
* v1.22: Add endpoints for LakeFormation and WAF/WAFv2
* v1.21: Add endpoint for AWS Backup API
* v1.20: Add endpoint for Resource Groups API
diff --git a/localstack_client/config.py b/localstack_client/config.py
index cecf63c..e43d18a 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -101,6 +101,7 @@
'lakeformation': '{proto}://{host}:4639',
'waf': '{proto}://{host}:4640',
'wafv2': '{proto}://{host}:4640',
+ 'config': '{proto}://{host}:4641',
}
# TODO remove service port mapping above entirely
diff --git a/setup.py b/setup.py
index b8ba1b0..f5469d4 100755
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setup(
name='localstack-client',
- version='1.23',
+ version='1.24',
description='A lightweight Python client for LocalStack.',
author='Waldemar Hummer',
author_email='waldemar.hummer@gmail.com',
From 58b19f61f582c29818aa7ebfde9c2aae0f942d0e Mon Sep 17 00:00:00 2001
From: Joe Pohlmann <73117648+josephpohlmann@users.noreply.github.com>
Date: Mon, 30 Aug 2021 06:20:31 -0400
Subject: [PATCH 02/36] add ability to specify region and kwargs when creating
boto3 client sessions (#31)
---
localstack_client/session.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/localstack_client/session.py b/localstack_client/session.py
index 83cdaa6..2415383 100644
--- a/localstack_client/session.py
+++ b/localstack_client/session.py
@@ -82,8 +82,12 @@ def _get_default_session():
def client(*args, **kwargs):
+ if kwargs:
+ return Session(**kwargs).client(*args, **kwargs)
return _get_default_session().client(*args, **kwargs)
def resource(*args, **kwargs):
+ if kwargs:
+ return Session(**kwargs).resource(*args, **kwargs)
return _get_default_session().resource(*args, **kwargs)
From a84823f1ec624919228965fb01c7b9f325446fa5 Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Wed, 22 Sep 2021 21:13:49 +0200
Subject: [PATCH 03/36] Remove mapping for deprecated/disabled Web UI on port
8080
---
README.md | 1 +
localstack_client/config.py | 1 -
setup.py | 2 +-
3 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 8a807a9..adcab41 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ make test
## Changelog
+* v1.25: Remove mapping for deprecated/disabled Web UI on port 8080
* v1.24: Add endpoints for Config Service
* v1.23: Add endpoints for QLDB Session
* v1.22: Add endpoints for LakeFormation and WAF/WAFv2
diff --git a/localstack_client/config.py b/localstack_client/config.py
index e43d18a..f05a310 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -8,7 +8,6 @@
# NOTE: The endpoints below will soon become deprecated/removed, as the default in the
# latest version is to access all services via a single "edge service" (port 4566 by default)
_service_endpoints_template = {
- 'dashboard': '{proto}://{host}:8080',
'edge': '{proto}://{host}:4566',
'apigateway': '{proto}://{host}:4567',
'apigatewayv2': '{proto}://{host}:4567',
diff --git a/setup.py b/setup.py
index f5469d4..095280d 100755
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setup(
name='localstack-client',
- version='1.24',
+ version='1.25',
description='A lightweight Python client for LocalStack.',
author='Waldemar Hummer',
author_email='waldemar.hummer@gmail.com',
From 08eb3e66fbac3bc35bda4cbd824efc19ff5b47a5 Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Wed, 13 Oct 2021 18:51:49 +0200
Subject: [PATCH 04/36] add endpoint/alias for configservice
---
localstack_client/config.py | 1 +
setup.py | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/localstack_client/config.py b/localstack_client/config.py
index f05a310..9359f6c 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -101,6 +101,7 @@
'waf': '{proto}://{host}:4640',
'wafv2': '{proto}://{host}:4640',
'config': '{proto}://{host}:4641',
+ 'configservice': '{proto}://{host}:4641',
}
# TODO remove service port mapping above entirely
diff --git a/setup.py b/setup.py
index 095280d..598ca8d 100755
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setup(
name='localstack-client',
- version='1.25',
+ version='1.26',
description='A lightweight Python client for LocalStack.',
author='Waldemar Hummer',
author_email='waldemar.hummer@gmail.com',
From ff63a15c2668ca77276c2968ea4a11ef9a6acb8f Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Thu, 18 Nov 2021 14:39:59 +0100
Subject: [PATCH 05/36] add endpoint for SESv2
---
README.md | 1 +
localstack_client/config.py | 1 +
setup.py | 6 +++---
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index adcab41..f6623e3 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ make test
## Changelog
+* v1.27: Add endpoint for SESv2
* v1.25: Remove mapping for deprecated/disabled Web UI on port 8080
* v1.24: Add endpoints for Config Service
* v1.23: Add endpoints for QLDB Session
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 9359f6c..03db306 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -24,6 +24,7 @@
'redshift-data': '{proto}://{host}:4577',
'es': '{proto}://{host}:4578',
'ses': '{proto}://{host}:4579',
+ 'sesv2': '{proto}://{host}:4579',
'route53': '{proto}://{host}:4580',
'cloudformation': '{proto}://{host}:4581',
'cloudwatch': '{proto}://{host}:4582',
diff --git a/setup.py b/setup.py
index 598ca8d..b046438 100755
--- a/setup.py
+++ b/setup.py
@@ -6,10 +6,10 @@
setup(
name='localstack-client',
- version='1.26',
+ version='1.27',
description='A lightweight Python client for LocalStack.',
- author='Waldemar Hummer',
- author_email='waldemar.hummer@gmail.com',
+ author='LocalStack Team',
+ author_email='info@localstack.cloud',
url='https://github.com/localstack/localstack-python-client',
packages=['localstack_client'],
package_data={},
From 9feddf30161bca2d17fc5d0e6266667513887b06 Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Sun, 5 Dec 2021 18:29:47 +0100
Subject: [PATCH 06/36] add endpoint for Route53Resolver
---
README.md | 1 +
localstack_client/config.py | 1 +
setup.py | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index f6623e3..5c1cb65 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ make test
## Changelog
+* v1.28: Add endpoint for Route53Resolver
* v1.27: Add endpoint for SESv2
* v1.25: Remove mapping for deprecated/disabled Web UI on port 8080
* v1.24: Add endpoints for Config Service
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 03db306..45c1f94 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -26,6 +26,7 @@
'ses': '{proto}://{host}:4579',
'sesv2': '{proto}://{host}:4579',
'route53': '{proto}://{host}:4580',
+ 'route53resolver': '{proto}://{host}:4580',
'cloudformation': '{proto}://{host}:4581',
'cloudwatch': '{proto}://{host}:4582',
'ssm': '{proto}://{host}:4583',
diff --git a/setup.py b/setup.py
index b046438..ad3221a 100755
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setup(
name='localstack-client',
- version='1.27',
+ version='1.28',
description='A lightweight Python client for LocalStack.',
author='LocalStack Team',
author_email='info@localstack.cloud',
From c2c102f520ffef3baffa44080a24d0228544532d Mon Sep 17 00:00:00 2001
From: Alexander Rashed <2796604+alexrashed@users.noreply.github.com>
Date: Tue, 21 Dec 2021 11:42:02 +0100
Subject: [PATCH 07/36] add endpoint for OpenSearch (#33)
---
README.md | 1 +
localstack_client/config.py | 1 +
setup.py | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 5c1cb65..8799111 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ make test
## Changelog
+* v1.29: Add endpoint for OpenSearch
* v1.28: Add endpoint for Route53Resolver
* v1.27: Add endpoint for SESv2
* v1.25: Remove mapping for deprecated/disabled Web UI on port 8080
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 45c1f94..d25f974 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -15,6 +15,7 @@
'dynamodb': '{proto}://{host}:4569',
'dynamodbstreams': '{proto}://{host}:4570',
'elasticsearch': '{proto}://{host}:4571',
+ 'opensearch': '{proto}://{host}:4571',
's3': '{proto}://{host}:4572',
'firehose': '{proto}://{host}:4573',
'lambda': '{proto}://{host}:4574',
diff --git a/setup.py b/setup.py
index ad3221a..3fcf65c 100755
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setup(
name='localstack-client',
- version='1.28',
+ version='1.29',
description='A lightweight Python client for LocalStack.',
author='LocalStack Team',
author_email='info@localstack.cloud',
From 5c1a99a654817081f2b4b8f6ba1292946fa3fdd3 Mon Sep 17 00:00:00 2001
From: Alexander Rashed <2796604+alexrashed@users.noreply.github.com>
Date: Thu, 23 Dec 2021 16:55:02 +0100
Subject: [PATCH 08/36] infrastructure cleanup: refactor dependencies, linter
configuration (#34)
---
Makefile | 4 ++--
requirements.txt | 2 --
setup.cfg | 36 ++++++++++++++++++++++++++++++++++++
setup.py | 31 +------------------------------
4 files changed, 39 insertions(+), 34 deletions(-)
delete mode 100644 requirements.txt
create mode 100644 setup.cfg
diff --git a/Makefile b/Makefile
index 3a88810..3b043d2 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ install: ## Install dependencies in local virtualenv folder
(test `which virtualenv` || $(PIP_CMD) install --user virtualenv) && \
(test -e $(VENV_DIR) || virtualenv $(VENV_OPTS) $(VENV_DIR)) && \
($(VENV_RUN) && $(PIP_CMD) install --upgrade pip) && \
- (test ! -e requirements.txt || ($(VENV_RUN); $(PIP_CMD) install -r requirements.txt))
+ (test ! -e setup.cfg || ($(VENV_RUN); $(PIP_CMD) install .))
publish: ## Publish the library to the central PyPi repository
# build and upload archive
@@ -21,7 +21,7 @@ test: ## Run automated tests
$(VENV_RUN); DEBUG=$(DEBUG) PYTHONPATH=`pwd` nosetests --with-coverage --logging-level=WARNING --nocapture --no-skip --exe --cover-erase --cover-tests --cover-inclusive --cover-package=localstack_client --with-xunit --exclude='$(VENV_DIR).*' .
lint: ## Run code linter to check code style
- ($(VENV_RUN); pep8 --max-line-length=100 --ignore=E128 --exclude=node_modules,legacy,$(VENV_DIR),dist .)
+ ($(VENV_RUN); pycodestyle --max-line-length=100 --ignore=E128 --exclude=node_modules,legacy,$(VENV_DIR),dist .)
clean: ## Clean up virtualenv
rm -rf $(VENV_DIR)
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 578709f..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-boto3
-six
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..ce1e055
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,36 @@
+[metadata]
+name = localstack-client
+version = 1.29
+url = https://github.com/localstack/localstack-python-client
+author = LocalStack Team
+author_email = info@localstack.cloud
+description = A lightweight Python client for LocalStack.
+license = Apache License 2.0
+classifiers =
+ Programming Language :: Python :: 2
+ Programming Language :: Python :: 2.6
+ Programming Language :: Python :: 2.7
+ Programming Language :: Python :: 3
+ Programming Language :: Python :: 3.3
+ Programming Language :: Python :: 3.4
+ Programming Language :: Python :: 3.6
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+ Programming Language :: Python :: 3.9
+ License :: OSI Approved :: Apache Software License
+ Topic :: Software Development :: Testing
+
+[options]
+packages =
+ localstack_client
+
+install_requires =
+ boto3
+ six
+
+[options.extras_require]
+# Dependencies to run the tests
+test =
+ coverage
+ pycodestyle
+ nose
diff --git a/setup.py b/setup.py
index 3fcf65c..ac42fe2 100755
--- a/setup.py
+++ b/setup.py
@@ -1,33 +1,4 @@
#!/usr/bin/env python
from setuptools import setup
-
-if __name__ == '__main__':
-
- setup(
- name='localstack-client',
- version='1.29',
- description='A lightweight Python client for LocalStack.',
- author='LocalStack Team',
- author_email='info@localstack.cloud',
- url='https://github.com/localstack/localstack-python-client',
- packages=['localstack_client'],
- package_data={},
- data_files={},
- install_requires=["boto3"],
- license="Apache License 2.0",
- classifiers=[
- "Programming Language :: Python :: 2",
- "Programming Language :: Python :: 2.6",
- "Programming Language :: Python :: 2.7",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.3",
- 'Programming Language :: Python :: 3.4',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: 3.8',
- 'Programming Language :: Python :: 3.9',
- "License :: OSI Approved :: Apache Software License",
- "Topic :: Software Development :: Testing",
- ]
- )
+setup()
From 75d75e77315b9535143833c2919260b97a0d3068 Mon Sep 17 00:00:00 2001
From: Harsh Mishra
Date: Thu, 23 Dec 2021 21:39:42 +0530
Subject: [PATCH 09/36] add GitHub Actions CI to install, test and lint (#35)
---
.github/workflows/ci.yml | 46 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 .github/workflows/ci.yml
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..f78de62
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,46 @@
+name: LocalStack Python Client CI
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version:
+ - "3.9"
+ - "3.8"
+ - "3.7"
+ - "3.6"
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Upgrade pip version
+ run: |
+ python3 -m pip install --upgrade pip
+
+ - name: Install Dependencies
+ run: |
+ make install
+
+ - name: Test
+ run: |
+ pip install pep8 nose boto3 localstack
+ docker pull localstack/localstack
+ localstack start -d
+ make test
+
+ - name: Lint
+ run: |
+ make lint
From 7a7e2af8415a396ca138a76368903407bd7a93b4 Mon Sep 17 00:00:00 2001
From: Harsh Mishra
Date: Thu, 23 Dec 2021 22:30:17 +0530
Subject: [PATCH 10/36] Enhancing LocalStack Python client `README.md` (#36)
* FIX: Fix the GHA CI
* DOCS: Enhance the README.md
* DOCS: Add a CONTRIBUTNG.md
---
.github/workflows/ci.yml | 1 +
CHANGELOG.md | 43 +++++++++++++++++++++++
CONTRIBUTING.md | 11 ++++++
README.md | 76 +++++++++-------------------------------
4 files changed, 72 insertions(+), 59 deletions(-)
create mode 100644 CHANGELOG.md
create mode 100644 CONTRIBUTING.md
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f78de62..4947a2e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -43,4 +43,5 @@ jobs:
- name: Lint
run: |
+ pip install pycodestyle
make lint
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..9df2ef4
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,43 @@
+# LocalStack Python Client Change Log
+
+* v1.29: Add endpoint for OpenSearch
+* v1.28: Add endpoint for Route53Resolver
+* v1.27: Add endpoint for SESv2
+* v1.25: Remove mapping for deprecated/disabled Web UI on port 8080
+* v1.24: Add endpoints for Config Service
+* v1.23: Add endpoints for QLDB Session
+* v1.22: Add endpoints for LakeFormation and WAF/WAFv2
+* v1.21: Add endpoint for AWS Backup API
+* v1.20: Add endpoint for Resource Groups API
+* v1.19: Add endpoints for Resource Groups Tagging API
+* v1.18: Add endpoints for AppConfig, CostExplorer, MediaConvert
+* v1.17: Add endpoint for ServerlessApplicationRepository
+* v1.16: Add endpoints for AWS Support and ServiceDiscovery (CloudMap)
+* v1.14: Add endpoint for IoT Wireless
+* v1.13: Add endpoints for NeptuneDB and DocumentDB
+* v1.10: Add endpoint for ELBv2
+* v1.7: Add endpoints for AWS API GW Management, Timestream, S3 Control, and others
+* v1.5: Add endpoint for AWS Application Autoscaling, Kafka (MSK)
+* v1.4: Configure USE_LEGACY_PORTS=0 by default to accommodate upstream changes
+* v1.2: Add endpoint for AWS Amplify
+* v1.1: Add USE_LEGACY_PORTS config to disable using legacy ports
+* v1.0: Switch to using edge port for all service endpoints by default
+* v0.25: Add endpoint for AWS Kinesis Analytics; prepare for replacing service ports with edge port
+* v0.24: Add endpoints for AWS Transfer, ACM, and CodeCommit
+* v0.23: Add endpoints for AWS Autoscaling and MediaStore
+* v0.22: Import boto3 under different name to simplify mocking
+* v0.20: Add endpoints for AWS CloudTrail, Glacier, Batch, Organizations
+* v0.19: Add endpoints for AWS ECR and QLDB
+* v0.18: Add endpoint for AWS API Gateway V2
+* v0.16: Add endpoint for AWS SageMaker
+* v0.15: Add endpoint for AWS Glue
+* v0.14: Add endpoint for AWS Athena
+* v0.13: Add endpoint for AWS CloudFront
+* v0.8: Add more service endpoint mappings that will be implemented in the near future
+* v0.7: Add endpoint for AWS Step Functions
+* v0.6: Add endpoint for AWS Secrets Manager
+* v0.5: Fix passing of credentials to client session
+* v0.4: Add functions to retrieve service port mappings
+* v0.3: Add new service endpoints
+* v0.2: Add missing service endpoints; enable SSL connections; put default endpoints into `config.py`
+* v0.1: Initial version
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..aaec6c9
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,11 @@
+# Contributing
+
+We welcome feedback, bug reports, and pull requests!
+
+For pull requests, please stick to the following guidelines:
+
+- Add tests for any new features and bug fixes.
+- Follow the existing code style. Run `make lint` before checking in your code.
+- Put a reasonable amount of comments into the code.
+- Fork `localstack-python-client` on your GitHub user account, do your changes there and then create a PR against main `localstack-python-client` repository.
+- Separate unrelated changes into multiple pull requests.
diff --git a/README.md b/README.md
index 8799111..8371dce 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,12 @@
# LocalStack Python Client
+
+
+
+
+
+
+
This is an easy-to-use Python client for [LocalStack](https://github.com/localstack/localstack).
The client library provides a thin wrapper around [boto3](https://github.com/boto/boto3) which
automatically configures the target endpoints to use LocalStack for your local cloud
@@ -7,8 +14,7 @@ application development.
## Prerequisites
-To make use of this library, you need to have [LocalStack](https://github.com/localstack/localstack)
-installed on your local machine. In particular, the `localstack` command needs to be available.
+To make use of this library, you need to have [LocalStack](https://github.com/localstack/localstack) installed on your local machine. In particular, the `localstack` command needs to be available.
## Installation
@@ -20,11 +26,11 @@ pip install localstack-client
## Usage
-This library provides an API that is identical to `boto3`'s. A minimal way to try it out is to replace
-`import boto3` with `import localstack_client.session as boto3`. This will allow your boto3 calls to work as normal.
+This library provides an API that is identical to `boto3`'s. A minimal way to try it out is to replace `import boto3` with `import localstack_client.session as boto3`. This will allow your boto3 calls to work as normal.
+
For example, to list all s3 buckets in localstack:
-```
+```python
import localstack_client.session as boto3
client = boto3.client('s3')
response = client.list_buckets()
@@ -33,7 +39,7 @@ response = client.list_buckets()
Another example below shows using `localstack_client` directly. To list the SQS queues
in your local (LocalStack) environment, use the following code:
-```
+```python
import localstack_client.session
session = localstack_client.session.Session()
@@ -43,7 +49,7 @@ assert sqs.list_queues() is not None
If you use `boto3.client` directly in your code, you can mock it.
-```
+```python
import localstack_client.session
import pytest
@@ -55,66 +61,18 @@ def boto3_localstack_patch(monkeypatch):
monkeypatch.setattr(boto3, "resource", session_ls.resource)
```
-```
+```python
sqs = boto3.client('sqs')
assert sqs.list_queues() is not None # list SQS in localstack
```
+## Contributing
-## Developing
-
-We welcome feedback, bug reports, and pull requests!
-
-Use these commands to get you started and test your code:
-
-```
-make install
-make test
-```
+If you are interested in contributing to LocalStack Python Client, start by reading our [`CONTRIBUTING.md`](CONTRIBUTING.md) guide. You can further navigate our codebase and [open issues](https://github.com/localstack/localstack-python-client/issues). We are thankful for all the contributions and feedback we receive.
## Changelog
-* v1.29: Add endpoint for OpenSearch
-* v1.28: Add endpoint for Route53Resolver
-* v1.27: Add endpoint for SESv2
-* v1.25: Remove mapping for deprecated/disabled Web UI on port 8080
-* v1.24: Add endpoints for Config Service
-* v1.23: Add endpoints for QLDB Session
-* v1.22: Add endpoints for LakeFormation and WAF/WAFv2
-* v1.21: Add endpoint for AWS Backup API
-* v1.20: Add endpoint for Resource Groups API
-* v1.19: Add endpoints for Resource Groups Tagging API
-* v1.18: Add endpoints for AppConfig, CostExplorer, MediaConvert
-* v1.17: Add endpoint for ServerlessApplicationRepository
-* v1.16: Add endpoints for AWS Support and ServiceDiscovery (CloudMap)
-* v1.14: Add endpoint for IoT Wireless
-* v1.13: Add endpoints for NeptuneDB and DocumentDB
-* v1.10: Add endpoint for ELBv2
-* v1.7: Add endpoints for AWS API GW Management, Timestream, S3 Control, and others
-* v1.5: Add endpoint for AWS Application Autoscaling, Kafka (MSK)
-* v1.4: Configure USE_LEGACY_PORTS=0 by default to accommodate upstream changes
-* v1.2: Add endpoint for AWS Amplify
-* v1.1: Add USE_LEGACY_PORTS config to disable using legacy ports
-* v1.0: Switch to using edge port for all service endpoints by default
-* v0.25: Add endpoint for AWS Kinesis Analytics; prepare for replacing service ports with edge port
-* v0.24: Add endpoints for AWS Transfer, ACM, and CodeCommit
-* v0.23: Add endpoints for AWS Autoscaling and MediaStore
-* v0.22: Import boto3 under different name to simplify mocking
-* v0.20: Add endpoints for AWS CloudTrail, Glacier, Batch, Organizations
-* v0.19: Add endpoints for AWS ECR and QLDB
-* v0.18: Add endpoint for AWS API Gateway V2
-* v0.16: Add endpoint for AWS SageMaker
-* v0.15: Add endpoint for AWS Glue
-* v0.14: Add endpoint for AWS Athena
-* v0.13: Add endpoint for AWS CloudFront
-* v0.8: Add more service endpoint mappings that will be implemented in the near future
-* v0.7: Add endpoint for AWS Step Functions
-* v0.6: Add endpoint for AWS Secrets Manager
-* v0.5: Fix passing of credentials to client session
-* v0.4: Add functions to retrieve service port mappings
-* v0.3: Add new service endpoints
-* v0.2: Add missing service endpoints; enable SSL connections; put default endpoints into `config.py`
-* v0.1: Initial version
+Please refer to [`CHANGELOG.md`](CHANGELOG.md) to see the complete list of changes for each release.
## License
From 1bfe21616200e7ef9dcc596e76ae291e44463316 Mon Sep 17 00:00:00 2001
From: Alexander Rashed <2796604+alexrashed@users.noreply.github.com>
Date: Wed, 12 Jan 2022 16:08:04 +0100
Subject: [PATCH 11/36] allow legacy port handling for OpenSearch (to support
`OPENSEARCH_ENDPOINT_STRATEGY=off`), cleanup pipeline (#37)
---
.github/workflows/ci.yml | 20 ++++++--------------
CHANGELOG.md | 1 +
Makefile | 7 +++----
localstack_client/config.py | 2 +-
setup.cfg | 3 ++-
tests/client/__init__.py | 9 +++------
6 files changed, 16 insertions(+), 26 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4947a2e..02c29aa 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -27,21 +27,13 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Upgrade pip version
- run: |
- python3 -m pip install --upgrade pip
+ run: python3 -m pip install --upgrade pip
- name: Install Dependencies
- run: |
- make install
-
- - name: Test
- run: |
- pip install pep8 nose boto3 localstack
- docker pull localstack/localstack
- localstack start -d
- make test
+ run: make install
- name: Lint
- run: |
- pip install pycodestyle
- make lint
+ run: make lint
+
+ - name: Test
+ run: make test
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9df2ef4..13a6ff9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v1.30: Allow legacy port handling for OpenSearch (to support `OPENSEARCH_ENDPOINT_STRATEGY=off`)
* v1.29: Add endpoint for OpenSearch
* v1.28: Add endpoint for Route53Resolver
* v1.27: Add endpoint for SESv2
diff --git a/Makefile b/Makefile
index 3b043d2..73f592e 100644
--- a/Makefile
+++ b/Makefile
@@ -9,16 +9,15 @@ install: ## Install dependencies in local virtualenv folder
(test `which virtualenv` || $(PIP_CMD) install --user virtualenv) && \
(test -e $(VENV_DIR) || virtualenv $(VENV_OPTS) $(VENV_DIR)) && \
($(VENV_RUN) && $(PIP_CMD) install --upgrade pip) && \
- (test ! -e setup.cfg || ($(VENV_RUN); $(PIP_CMD) install .))
+ (test ! -e setup.cfg || ($(VENV_RUN); $(PIP_CMD) install .[test]))
publish: ## Publish the library to the central PyPi repository
# build and upload archive
($(VENV_RUN) && ./setup.py sdist upload)
test: ## Run automated tests
- make lint && \
- ($(VENV_RUN); test `which localstack` || pip install localstack) && \
- $(VENV_RUN); DEBUG=$(DEBUG) PYTHONPATH=`pwd` nosetests --with-coverage --logging-level=WARNING --nocapture --no-skip --exe --cover-erase --cover-tests --cover-inclusive --cover-package=localstack_client --with-xunit --exclude='$(VENV_DIR).*' .
+ ($(VENV_RUN); test `which localstack` || pip install .[test]) && \
+ $(VENV_RUN); DEBUG=$(DEBUG) PYTHONPATH=`pwd` nosetests --with-coverage --logging-level=WARNING --nocapture --no-skip --exe --cover-erase --cover-tests --cover-inclusive --cover-package=localstack_client --with-xunit --exclude='$(VENV_DIR).*' .
lint: ## Run code linter to check code style
($(VENV_RUN); pycodestyle --max-line-length=100 --ignore=E128 --exclude=node_modules,legacy,$(VENV_DIR),dist .)
diff --git a/localstack_client/config.py b/localstack_client/config.py
index d25f974..021f8bc 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -110,7 +110,7 @@
# TODO remove service port mapping above entirely
if os.environ.get('USE_LEGACY_PORTS') not in ['1', 'true']:
for key, value in _service_endpoints_template.items():
- if key not in ['dashboard', 'elasticsearch']:
+ if key not in ['dashboard', 'elasticsearch', 'opensearch']:
_service_endpoints_template[key] = '%s:%s' % (value.rpartition(':')[0], EDGE_PORT)
diff --git a/setup.cfg b/setup.cfg
index ce1e055..cfd7fa3 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 1.29
+version = 1.30
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
@@ -34,3 +34,4 @@ test =
coverage
pycodestyle
nose
+ localstack
diff --git a/tests/client/__init__.py b/tests/client/__init__.py
index 1eeef8c..b75e802 100644
--- a/tests/client/__init__.py
+++ b/tests/client/__init__.py
@@ -7,12 +7,9 @@
def setup_package():
if STATE.get('process'):
return
- STATE['process'] = subprocess.Popen(['localstack', 'start'])
- time.sleep(10)
+ STATE['process'] = subprocess.Popen(['localstack', 'start', '-d'])
+ subprocess.Popen(['localstack', 'wait']).wait()
def teardown_package():
- # TODO implement "stop" command in LocalStack!
- # subprocess.check_call('localstack stop', shell=True)
- STATE['process'].terminate()
- time.sleep(2)
+ subprocess.Popen(['localstack', 'stop']).wait()
From 7a5a3c06e625935b6fcf6bab8c7867ecbafebf56 Mon Sep 17 00:00:00 2001
From: Alexander Rashed
Date: Wed, 12 Jan 2022 17:11:44 +0100
Subject: [PATCH 12/36] disable legacy port handling for opensearch
---
CHANGELOG.md | 1 +
localstack_client/config.py | 4 ++--
setup.cfg | 2 +-
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 13a6ff9..8fe7cd3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v1.31: Revert mapping for OpenSearch (drop support for `OPENSEARCH_ENDPOINT_STRATEGY=off`)
* v1.30: Allow legacy port handling for OpenSearch (to support `OPENSEARCH_ENDPOINT_STRATEGY=off`)
* v1.29: Add endpoint for OpenSearch
* v1.28: Add endpoint for Route53Resolver
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 021f8bc..f133b84 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -15,7 +15,6 @@
'dynamodb': '{proto}://{host}:4569',
'dynamodbstreams': '{proto}://{host}:4570',
'elasticsearch': '{proto}://{host}:4571',
- 'opensearch': '{proto}://{host}:4571',
's3': '{proto}://{host}:4572',
'firehose': '{proto}://{host}:4573',
'lambda': '{proto}://{host}:4574',
@@ -24,6 +23,7 @@
'redshift': '{proto}://{host}:4577',
'redshift-data': '{proto}://{host}:4577',
'es': '{proto}://{host}:4578',
+ 'opensearch': '{proto}://{host}:4578',
'ses': '{proto}://{host}:4579',
'sesv2': '{proto}://{host}:4579',
'route53': '{proto}://{host}:4580',
@@ -110,7 +110,7 @@
# TODO remove service port mapping above entirely
if os.environ.get('USE_LEGACY_PORTS') not in ['1', 'true']:
for key, value in _service_endpoints_template.items():
- if key not in ['dashboard', 'elasticsearch', 'opensearch']:
+ if key not in ['dashboard', 'elasticsearch']:
_service_endpoints_template[key] = '%s:%s' % (value.rpartition(':')[0], EDGE_PORT)
diff --git a/setup.cfg b/setup.cfg
index cfd7fa3..6fb7743 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 1.30
+version = 1.31
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 0d928057a5f375252a23821d1c8d544facc7fb3c Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Fri, 25 Feb 2022 09:34:10 +0100
Subject: [PATCH 13/36] add endpoint for KinesisAnalyticsV2
---
CHANGELOG.md | 1 +
localstack_client/config.py | 1 +
setup.cfg | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8fe7cd3..b5ac6ef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v1.32: Add endpoint for KinesisAnalyticsV2
* v1.31: Revert mapping for OpenSearch (drop support for `OPENSEARCH_ENDPOINT_STRATEGY=off`)
* v1.30: Allow legacy port handling for OpenSearch (to support `OPENSEARCH_ENDPOINT_STRATEGY=off`)
* v1.29: Add endpoint for OpenSearch
diff --git a/localstack_client/config.py b/localstack_client/config.py
index f133b84..d87e98f 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -79,6 +79,7 @@
'acm': '{proto}://{host}:4619',
'codecommit': '{proto}://{host}:4620',
'kinesisanalytics': '{proto}://{host}:4621',
+ 'kinesisanalyticsv2': '{proto}://{host}:4621',
'amplify': '{proto}://{host}:4622',
'application-autoscaling': '{proto}://{host}:4623',
'kafka': '{proto}://{host}:4624',
diff --git a/setup.cfg b/setup.cfg
index 6fb7743..8db7984 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 1.31
+version = 1.32
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 064f09250c7e5eff72e9533eb49a21bc5d3a4b61 Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Wed, 23 Mar 2022 11:23:19 +0100
Subject: [PATCH 14/36] patch botocore to skip adding `data-` host prefixes to
endpoint URLs; remove six dependency
---
CHANGELOG.md | 1 +
Makefile | 3 ++-
localstack_client/config.py | 18 +++++++++++++++++-
setup.cfg | 3 +--
4 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b5ac6ef..d349455 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v1.33: Patch botocore to skip adding `data-` host prefixes to endpoint URLs; remove six dependency
* v1.32: Add endpoint for KinesisAnalyticsV2
* v1.31: Revert mapping for OpenSearch (drop support for `OPENSEARCH_ENDPOINT_STRATEGY=off`)
* v1.30: Allow legacy port handling for OpenSearch (to support `OPENSEARCH_ENDPOINT_STRATEGY=off`)
diff --git a/Makefile b/Makefile
index 73f592e..c13b208 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,7 @@
VENV_DIR ?= .venv
VENV_RUN = . $(VENV_DIR)/bin/activate
PIP_CMD ?= pip
+BUILD_DIR ?= dist
usage: ## Show this help
@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'
@@ -13,7 +14,7 @@ install: ## Install dependencies in local virtualenv folder
publish: ## Publish the library to the central PyPi repository
# build and upload archive
- ($(VENV_RUN) && ./setup.py sdist upload)
+ ($(VENV_RUN); ./setup.py sdist && twine upload $(BUILD_DIR)/*.tar.gz)
test: ## Run automated tests
($(VENV_RUN); test `which localstack` || pip install .[test]) && \
diff --git a/localstack_client/config.py b/localstack_client/config.py
index d87e98f..7c743e5 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -1,8 +1,10 @@
import os
import json
-from six.moves.urllib.parse import urlparse
+from botocore.serialize import Serializer
# central entrypoint port for all LocalStack API endpoints
+from urllib.parse import urlparse
+
EDGE_PORT = int(os.environ.get('EDGE_PORT') or 4566)
# NOTE: The endpoints below will soon become deprecated/removed, as the default in the
@@ -140,3 +142,17 @@ def get_service_ports():
for service, url in endpoints.items():
result[service] = urlparse(url).port
return result
+
+
+def patch_expand_host_prefix():
+ """Apply a patch to botocore, to skip adding `data-` host prefixes to endpoint URLs"""
+
+ def _expand_host_prefix(self, parameters, operation_model, *args, **kwargs):
+ result = _expand_host_prefix_orig(self, parameters, operation_model, *args, **kwargs)
+ # skip adding data- prefix, to avoid making requests to http://data-localhost:4566
+ if operation_model.name == "DiscoverInstances" and result == "data-":
+ return None
+ return result
+
+ _expand_host_prefix_orig = Serializer._expand_host_prefix
+ Serializer._expand_host_prefix = _expand_host_prefix
diff --git a/setup.cfg b/setup.cfg
index 8db7984..bd97c92 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 1.32
+version = 1.33
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
@@ -26,7 +26,6 @@ packages =
install_requires =
boto3
- six
[options.extras_require]
# Dependencies to run the tests
From 4de1648209ca8909be1537c74bb0d9ee965f48ae Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Sat, 9 Apr 2022 19:20:43 +0200
Subject: [PATCH 15/36] add endpoint for Amazon Managed Workflows for Apache
Airflow (MWAA)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 9 ++++++---
setup.cfg | 2 +-
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d349455..046ae21 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v1.35: Add endpoint for Amazon Managed Workflows for Apache Airflow (MWAA)
* v1.33: Patch botocore to skip adding `data-` host prefixes to endpoint URLs; remove six dependency
* v1.32: Add endpoint for KinesisAnalyticsV2
* v1.31: Revert mapping for OpenSearch (drop support for `OPENSEARCH_ENDPOINT_STRATEGY=off`)
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 7c743e5..4e4f375 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -108,6 +108,7 @@
'wafv2': '{proto}://{host}:4640',
'config': '{proto}://{host}:4641',
'configservice': '{proto}://{host}:4641',
+ 'mwaa': '{proto}://{host}:4642',
}
# TODO remove service port mapping above entirely
@@ -145,12 +146,14 @@ def get_service_ports():
def patch_expand_host_prefix():
- """Apply a patch to botocore, to skip adding `data-` host prefixes to endpoint URLs"""
+ """Apply a patch to botocore, to skip adding host prefixes to endpoint URLs"""
def _expand_host_prefix(self, parameters, operation_model, *args, **kwargs):
result = _expand_host_prefix_orig(self, parameters, operation_model, *args, **kwargs)
- # skip adding data- prefix, to avoid making requests to http://data-localhost:4566
- if operation_model.name == "DiscoverInstances" and result == "data-":
+ # skip adding host prefixes, to avoid making requests to, e.g., http://data-localhost:4566
+ if operation_model.service_model.service_name == "servicediscovery" and result == "data-":
+ return None
+ if operation_model.service_model.service_name == "mwaa" and result == "api.":
return None
return result
diff --git a/setup.cfg b/setup.cfg
index bd97c92..6d56630 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 1.33
+version = 1.35
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 92229c02c5b3cd0cef006e99c3d47db15aefcb4f Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Mon, 8 Aug 2022 14:28:20 +0200
Subject: [PATCH 16/36] add endpoints for Fault Injection Service (FIS) and
Marketplace Metering
---
CHANGELOG.md | 1 +
localstack_client/config.py | 2 ++
setup.cfg | 2 +-
3 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 046ae21..82b6f8e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v1.36: Add endpoints for Fault Injection Service (FIS) and Marketplace Metering
* v1.35: Add endpoint for Amazon Managed Workflows for Apache Airflow (MWAA)
* v1.33: Patch botocore to skip adding `data-` host prefixes to endpoint URLs; remove six dependency
* v1.32: Add endpoint for KinesisAnalyticsV2
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 4e4f375..8db62d8 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -109,6 +109,8 @@
'config': '{proto}://{host}:4641',
'configservice': '{proto}://{host}:4641',
'mwaa': '{proto}://{host}:4642',
+ 'fis': '{proto}://{host}:4643',
+ 'meteringmarketplace': '{proto}://{host}:4644',
}
# TODO remove service port mapping above entirely
diff --git a/setup.cfg b/setup.cfg
index 6d56630..c730d3e 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 1.35
+version = 1.36
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 3304193f0765628f7e3b69d1d5ae75d3cc7b6127 Mon Sep 17 00:00:00 2001
From: Viren Nadkarni
Date: Tue, 30 Aug 2022 10:06:49 +0530
Subject: [PATCH 17/36] Add support for AWS Transcribe (#39)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 1 +
setup.cfg | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 82b6f8e..9390993 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v1.37: Add endpoint for Amazon Transcribe
* v1.36: Add endpoints for Fault Injection Service (FIS) and Marketplace Metering
* v1.35: Add endpoint for Amazon Managed Workflows for Apache Airflow (MWAA)
* v1.33: Patch botocore to skip adding `data-` host prefixes to endpoint URLs; remove six dependency
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 8db62d8..939f366 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -111,6 +111,7 @@
'mwaa': '{proto}://{host}:4642',
'fis': '{proto}://{host}:4643',
'meteringmarketplace': '{proto}://{host}:4644',
+ 'transcribe': '{proto}://{host}:4566',
}
# TODO remove service port mapping above entirely
diff --git a/setup.cfg b/setup.cfg
index c730d3e..aceab8d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 1.36
+version = 1.37
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 6c1b213dfed5c8c4d16f7ce33f0928be84b94dab Mon Sep 17 00:00:00 2001
From: Harsh Mishra
Date: Wed, 31 Aug 2022 16:32:48 +0530
Subject: [PATCH 18/36] ci: drop support for python 3.6 (#41)
---
.github/workflows/ci.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 02c29aa..72ce939 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,7 +16,6 @@ jobs:
- "3.9"
- "3.8"
- "3.7"
- - "3.6"
steps:
- uses: actions/checkout@v2
From 6972c42b30e32a9f661243172192cf123620abfa Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Wed, 31 Aug 2022 18:03:36 +0200
Subject: [PATCH 19/36] add util function to enable transparent local boto3
endpoints (#40)
---
.github/workflows/ci.yml | 1 +
CHANGELOG.md | 1 +
Makefile | 11 +-
README.md | 21 +++
localstack_client/config.py | 269 ++++++++++++++---------------
localstack_client/patch.py | 151 ++++++++++++++++
localstack_client/session.py | 62 ++++---
setup.cfg | 13 +-
tests/client/__init__.py | 15 --
tests/client/conftest.py | 13 ++
tests/client/test_patches.py | 36 ++++
tests/client/test_python_client.py | 37 ++--
12 files changed, 426 insertions(+), 204 deletions(-)
create mode 100644 localstack_client/patch.py
create mode 100644 tests/client/conftest.py
create mode 100644 tests/client/test_patches.py
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 72ce939..d48bbf3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -13,6 +13,7 @@ jobs:
fail-fast: false
matrix:
python-version:
+ - "3.10"
- "3.9"
- "3.8"
- "3.7"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9390993..f755514 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v1.38: Add `enable_local_endpoints()` util function; slight project refactoring, migrate from `nose` to `pytests`
* v1.37: Add endpoint for Amazon Transcribe
* v1.36: Add endpoints for Fault Injection Service (FIS) and Marketplace Metering
* v1.35: Add endpoint for Amazon Managed Workflows for Apache Airflow (MWAA)
diff --git a/Makefile b/Makefile
index c13b208..150194b 100644
--- a/Makefile
+++ b/Makefile
@@ -14,16 +14,19 @@ install: ## Install dependencies in local virtualenv folder
publish: ## Publish the library to the central PyPi repository
# build and upload archive
- ($(VENV_RUN); ./setup.py sdist && twine upload $(BUILD_DIR)/*.tar.gz)
+ $(VENV_RUN); ./setup.py sdist && twine upload $(BUILD_DIR)/*.tar.gz
test: ## Run automated tests
($(VENV_RUN); test `which localstack` || pip install .[test]) && \
- $(VENV_RUN); DEBUG=$(DEBUG) PYTHONPATH=`pwd` nosetests --with-coverage --logging-level=WARNING --nocapture --no-skip --exe --cover-erase --cover-tests --cover-inclusive --cover-package=localstack_client --with-xunit --exclude='$(VENV_DIR).*' .
+ $(VENV_RUN); DEBUG=$(DEBUG) PYTHONPATH=. pytest -sv $(PYTEST_ARGS) tests
lint: ## Run code linter to check code style
- ($(VENV_RUN); pycodestyle --max-line-length=100 --ignore=E128 --exclude=node_modules,legacy,$(VENV_DIR),dist .)
+ $(VENV_RUN); flake8 --ignore=E501 localstack_client tests
+
+format: ## Run code formatter (black)
+ $(VENV_RUN); black localstack_client tests; isort localstack_client tests
clean: ## Clean up virtualenv
rm -rf $(VENV_DIR)
-.PHONY: usage install clean publish test lint
+.PHONY: usage install clean publish test lint format
diff --git a/README.md b/README.md
index 8371dce..5a4922d 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,27 @@ sqs = boto3.client('sqs')
assert sqs.list_queues() is not None # list SQS in localstack
```
+### Enabling Transparent Local Endpoints
+
+The library contains a small `enable_local_endpoints()` util function that can be used to transparently run all `boto3` requests against the local endpoints.
+
+The following sample illustrates how it can be used - after calling `enable_local_endpoints()`, the S3 `ListBuckets` call will be run against LocalStack, even though we're using the default boto3 module.
+```
+import boto3
+from localstack_client.patch import enable_local_endpoints()
+enable_local_endpoints()
+# the call below will automatically target the LocalStack endpoints
+buckets = boto3.client("s3").list_buckets()
+```
+
+The patch can also be unapplied by calling `disable_local_endpoints()`:
+```
+from localstack_client.patch import disable_local_endpoints()
+disable_local_endpoints()
+# the call below will target the real AWS cloud again
+buckets = boto3.client("s3").list_buckets()
+```
+
## Contributing
If you are interested in contributing to LocalStack Python Client, start by reading our [`CONTRIBUTING.md`](CONTRIBUTING.md) guide. You can further navigate our codebase and [open issues](https://github.com/localstack/localstack-python-client/issues). We are thankful for all the contributions and feedback we receive.
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 939f366..ca689c3 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -1,164 +1,161 @@
-import os
import json
-from botocore.serialize import Serializer
-
-# central entrypoint port for all LocalStack API endpoints
+import os
+from typing import Dict
from urllib.parse import urlparse
-EDGE_PORT = int(os.environ.get('EDGE_PORT') or 4566)
+# note: leave this import here for now, as some upstream code is depending on it (TODO needs to be updated)
+from localstack_client.patch import patch_expand_host_prefix # noqa
+
+# central entrypoint port for all LocalStack API endpoints
+EDGE_PORT = int(os.environ.get("EDGE_PORT") or 4566)
# NOTE: The endpoints below will soon become deprecated/removed, as the default in the
# latest version is to access all services via a single "edge service" (port 4566 by default)
_service_endpoints_template = {
- 'edge': '{proto}://{host}:4566',
- 'apigateway': '{proto}://{host}:4567',
- 'apigatewayv2': '{proto}://{host}:4567',
- 'kinesis': '{proto}://{host}:4568',
- 'dynamodb': '{proto}://{host}:4569',
- 'dynamodbstreams': '{proto}://{host}:4570',
- 'elasticsearch': '{proto}://{host}:4571',
- 's3': '{proto}://{host}:4572',
- 'firehose': '{proto}://{host}:4573',
- 'lambda': '{proto}://{host}:4574',
- 'sns': '{proto}://{host}:4575',
- 'sqs': '{proto}://{host}:4576',
- 'redshift': '{proto}://{host}:4577',
- 'redshift-data': '{proto}://{host}:4577',
- 'es': '{proto}://{host}:4578',
- 'opensearch': '{proto}://{host}:4578',
- 'ses': '{proto}://{host}:4579',
- 'sesv2': '{proto}://{host}:4579',
- 'route53': '{proto}://{host}:4580',
- 'route53resolver': '{proto}://{host}:4580',
- 'cloudformation': '{proto}://{host}:4581',
- 'cloudwatch': '{proto}://{host}:4582',
- 'ssm': '{proto}://{host}:4583',
- 'secretsmanager': '{proto}://{host}:4584',
- 'stepfunctions': '{proto}://{host}:4585',
- 'logs': '{proto}://{host}:4586',
- 'events': '{proto}://{host}:4587',
- 'elb': '{proto}://{host}:4588',
- 'iot': '{proto}://{host}:4589',
- 'iotanalytics': '{proto}://{host}:4589',
- 'iotevents': '{proto}://{host}:4589',
- 'iotevents-data': '{proto}://{host}:4589',
- 'iotwireless': '{proto}://{host}:4589',
- 'iot-data': '{proto}://{host}:4589',
- 'iot-jobs-data': '{proto}://{host}:4589',
- 'cognito-idp': '{proto}://{host}:4590',
- 'cognito-identity': '{proto}://{host}:4591',
- 'sts': '{proto}://{host}:4592',
- 'iam': '{proto}://{host}:4593',
- 'rds': '{proto}://{host}:4594',
- 'rds-data': '{proto}://{host}:4594',
- 'cloudsearch': '{proto}://{host}:4595',
- 'swf': '{proto}://{host}:4596',
- 'ec2': '{proto}://{host}:4597',
- 'elasticache': '{proto}://{host}:4598',
- 'kms': '{proto}://{host}:4599',
- 'emr': '{proto}://{host}:4600',
- 'ecs': '{proto}://{host}:4601',
- 'eks': '{proto}://{host}:4602',
- 'xray': '{proto}://{host}:4603',
- 'elasticbeanstalk': '{proto}://{host}:4604',
- 'appsync': '{proto}://{host}:4605',
- 'cloudfront': '{proto}://{host}:4606',
- 'athena': '{proto}://{host}:4607',
- 'glue': '{proto}://{host}:4608',
- 'sagemaker': '{proto}://{host}:4609',
- 'sagemaker-runtime': '{proto}://{host}:4609',
- 'ecr': '{proto}://{host}:4610',
- 'qldb': '{proto}://{host}:4611',
- 'qldb-session': '{proto}://{host}:4611',
- 'cloudtrail': '{proto}://{host}:4612',
- 'glacier': '{proto}://{host}:4613',
- 'batch': '{proto}://{host}:4614',
- 'organizations': '{proto}://{host}:4615',
- 'autoscaling': '{proto}://{host}:4616',
- 'mediastore': '{proto}://{host}:4617',
- 'mediastore-data': '{proto}://{host}:4617',
- 'transfer': '{proto}://{host}:4618',
- 'acm': '{proto}://{host}:4619',
- 'codecommit': '{proto}://{host}:4620',
- 'kinesisanalytics': '{proto}://{host}:4621',
- 'kinesisanalyticsv2': '{proto}://{host}:4621',
- 'amplify': '{proto}://{host}:4622',
- 'application-autoscaling': '{proto}://{host}:4623',
- 'kafka': '{proto}://{host}:4624',
- 'apigatewaymanagementapi': '{proto}://{host}:4625',
- 'timestream': '{proto}://{host}:4626',
- 'timestream-query': '{proto}://{host}:4626',
- 'timestream-write': '{proto}://{host}:4626',
- 's3control': '{proto}://{host}:4627',
- 'elbv2': '{proto}://{host}:4628',
- 'support': '{proto}://{host}:4629',
- 'neptune': '{proto}://{host}:4594',
- 'docdb': '{proto}://{host}:4594',
- 'servicediscovery': '{proto}://{host}:4630',
- 'serverlessrepo': '{proto}://{host}:4631',
- 'appconfig': '{proto}://{host}:4632',
- 'ce': '{proto}://{host}:4633',
- 'mediaconvert': '{proto}://{host}:4634',
- 'resourcegroupstaggingapi': '{proto}://{host}:4635',
- 'resource-groups': '{proto}://{host}:4636',
- 'efs': '{proto}://{host}:4637',
- 'backup': '{proto}://{host}:4638',
- 'lakeformation': '{proto}://{host}:4639',
- 'waf': '{proto}://{host}:4640',
- 'wafv2': '{proto}://{host}:4640',
- 'config': '{proto}://{host}:4641',
- 'configservice': '{proto}://{host}:4641',
- 'mwaa': '{proto}://{host}:4642',
- 'fis': '{proto}://{host}:4643',
- 'meteringmarketplace': '{proto}://{host}:4644',
- 'transcribe': '{proto}://{host}:4566',
+ "edge": "{proto}://{host}:4566",
+ "apigateway": "{proto}://{host}:4567",
+ "apigatewayv2": "{proto}://{host}:4567",
+ "kinesis": "{proto}://{host}:4568",
+ "dynamodb": "{proto}://{host}:4569",
+ "dynamodbstreams": "{proto}://{host}:4570",
+ "elasticsearch": "{proto}://{host}:4571",
+ "s3": "{proto}://{host}:4572",
+ "firehose": "{proto}://{host}:4573",
+ "lambda": "{proto}://{host}:4574",
+ "sns": "{proto}://{host}:4575",
+ "sqs": "{proto}://{host}:4576",
+ "redshift": "{proto}://{host}:4577",
+ "redshift-data": "{proto}://{host}:4577",
+ "es": "{proto}://{host}:4578",
+ "opensearch": "{proto}://{host}:4578",
+ "ses": "{proto}://{host}:4579",
+ "sesv2": "{proto}://{host}:4579",
+ "route53": "{proto}://{host}:4580",
+ "route53resolver": "{proto}://{host}:4580",
+ "cloudformation": "{proto}://{host}:4581",
+ "cloudwatch": "{proto}://{host}:4582",
+ "ssm": "{proto}://{host}:4583",
+ "secretsmanager": "{proto}://{host}:4584",
+ "stepfunctions": "{proto}://{host}:4585",
+ "logs": "{proto}://{host}:4586",
+ "events": "{proto}://{host}:4587",
+ "elb": "{proto}://{host}:4588",
+ "iot": "{proto}://{host}:4589",
+ "iotanalytics": "{proto}://{host}:4589",
+ "iotevents": "{proto}://{host}:4589",
+ "iotevents-data": "{proto}://{host}:4589",
+ "iotwireless": "{proto}://{host}:4589",
+ "iot-data": "{proto}://{host}:4589",
+ "iot-jobs-data": "{proto}://{host}:4589",
+ "cognito-idp": "{proto}://{host}:4590",
+ "cognito-identity": "{proto}://{host}:4591",
+ "sts": "{proto}://{host}:4592",
+ "iam": "{proto}://{host}:4593",
+ "rds": "{proto}://{host}:4594",
+ "rds-data": "{proto}://{host}:4594",
+ "cloudsearch": "{proto}://{host}:4595",
+ "swf": "{proto}://{host}:4596",
+ "ec2": "{proto}://{host}:4597",
+ "elasticache": "{proto}://{host}:4598",
+ "kms": "{proto}://{host}:4599",
+ "emr": "{proto}://{host}:4600",
+ "ecs": "{proto}://{host}:4601",
+ "eks": "{proto}://{host}:4602",
+ "xray": "{proto}://{host}:4603",
+ "elasticbeanstalk": "{proto}://{host}:4604",
+ "appsync": "{proto}://{host}:4605",
+ "cloudfront": "{proto}://{host}:4606",
+ "athena": "{proto}://{host}:4607",
+ "glue": "{proto}://{host}:4608",
+ "sagemaker": "{proto}://{host}:4609",
+ "sagemaker-runtime": "{proto}://{host}:4609",
+ "ecr": "{proto}://{host}:4610",
+ "qldb": "{proto}://{host}:4611",
+ "qldb-session": "{proto}://{host}:4611",
+ "cloudtrail": "{proto}://{host}:4612",
+ "glacier": "{proto}://{host}:4613",
+ "batch": "{proto}://{host}:4614",
+ "organizations": "{proto}://{host}:4615",
+ "autoscaling": "{proto}://{host}:4616",
+ "mediastore": "{proto}://{host}:4617",
+ "mediastore-data": "{proto}://{host}:4617",
+ "transfer": "{proto}://{host}:4618",
+ "acm": "{proto}://{host}:4619",
+ "codecommit": "{proto}://{host}:4620",
+ "kinesisanalytics": "{proto}://{host}:4621",
+ "kinesisanalyticsv2": "{proto}://{host}:4621",
+ "amplify": "{proto}://{host}:4622",
+ "application-autoscaling": "{proto}://{host}:4623",
+ "kafka": "{proto}://{host}:4624",
+ "apigatewaymanagementapi": "{proto}://{host}:4625",
+ "timestream": "{proto}://{host}:4626",
+ "timestream-query": "{proto}://{host}:4626",
+ "timestream-write": "{proto}://{host}:4626",
+ "s3control": "{proto}://{host}:4627",
+ "elbv2": "{proto}://{host}:4628",
+ "support": "{proto}://{host}:4629",
+ "neptune": "{proto}://{host}:4594",
+ "docdb": "{proto}://{host}:4594",
+ "servicediscovery": "{proto}://{host}:4630",
+ "serverlessrepo": "{proto}://{host}:4631",
+ "appconfig": "{proto}://{host}:4632",
+ "ce": "{proto}://{host}:4633",
+ "mediaconvert": "{proto}://{host}:4634",
+ "resourcegroupstaggingapi": "{proto}://{host}:4635",
+ "resource-groups": "{proto}://{host}:4636",
+ "efs": "{proto}://{host}:4637",
+ "backup": "{proto}://{host}:4638",
+ "lakeformation": "{proto}://{host}:4639",
+ "waf": "{proto}://{host}:4640",
+ "wafv2": "{proto}://{host}:4640",
+ "config": "{proto}://{host}:4641",
+ "configservice": "{proto}://{host}:4641",
+ "mwaa": "{proto}://{host}:4642",
+ "fis": "{proto}://{host}:4643",
+ "meteringmarketplace": "{proto}://{host}:4644",
+ "transcribe": "{proto}://{host}:4566",
}
# TODO remove service port mapping above entirely
-if os.environ.get('USE_LEGACY_PORTS') not in ['1', 'true']:
+if os.environ.get("USE_LEGACY_PORTS") not in ["1", "true"]:
for key, value in _service_endpoints_template.items():
- if key not in ['dashboard', 'elasticsearch']:
- _service_endpoints_template[key] = '%s:%s' % (value.rpartition(':')[0], EDGE_PORT)
-
-
-def get_service_endpoint(service, localstack_host=None):
+ if key not in ["dashboard", "elasticsearch"]:
+ _service_endpoints_template[key] = f"{value.rpartition(':')[0]}:{EDGE_PORT}"
+
+
+def get_service_endpoint(service: str, localstack_host: str = None) -> str:
+ """
+ Return the local endpoint URL for the given boto3 service (e.g., "s3").
+ If $AWS_ENDPOINT_URL is configured in the environment, it is returned directly.
+ Otherwise, the service endpoint is constructed from the dict of service ports (usually http://localhost:4566).
+ """
+ env_endpoint_url = os.environ.get("AWS_ENDPOINT_URL", "").strip()
+ if env_endpoint_url:
+ return env_endpoint_url
endpoints = get_service_endpoints(localstack_host=localstack_host)
return endpoints.get(service)
-def get_service_endpoints(localstack_host=None):
+def get_service_endpoints(localstack_host: str = None) -> Dict[str, str]:
if localstack_host is None:
- localstack_host = os.environ.get('LOCALSTACK_HOST', 'localhost')
- protocol = 'https' if os.environ.get('USE_SSL') in ('1', 'true') else 'http'
+ localstack_host = os.environ.get("LOCALSTACK_HOST", "localhost")
+ protocol = "https" if os.environ.get("USE_SSL") in ("1", "true") else "http"
- return json.loads(json.dumps(_service_endpoints_template)
- .replace('{proto}', protocol).replace('{host}', localstack_host))
+ return json.loads(
+ json.dumps(_service_endpoints_template)
+ .replace("{proto}", protocol)
+ .replace("{host}", localstack_host)
+ )
-def get_service_port(service):
+def get_service_port(service: str) -> int:
ports = get_service_ports()
return ports.get(service)
-def get_service_ports():
+def get_service_ports() -> Dict[str, int]:
endpoints = get_service_endpoints()
result = {}
for service, url in endpoints.items():
result[service] = urlparse(url).port
return result
-
-
-def patch_expand_host_prefix():
- """Apply a patch to botocore, to skip adding host prefixes to endpoint URLs"""
-
- def _expand_host_prefix(self, parameters, operation_model, *args, **kwargs):
- result = _expand_host_prefix_orig(self, parameters, operation_model, *args, **kwargs)
- # skip adding host prefixes, to avoid making requests to, e.g., http://data-localhost:4566
- if operation_model.service_model.service_name == "servicediscovery" and result == "data-":
- return None
- if operation_model.service_model.service_name == "mwaa" and result == "api.":
- return None
- return result
-
- _expand_host_prefix_orig = Serializer._expand_host_prefix
- Serializer._expand_host_prefix = _expand_host_prefix
diff --git a/localstack_client/patch.py b/localstack_client/patch.py
new file mode 100644
index 0000000..b8b9f39
--- /dev/null
+++ b/localstack_client/patch.py
@@ -0,0 +1,151 @@
+import types
+
+import boto3
+from boto3.session import Session
+from botocore.serialize import Serializer
+
+_state = {}
+
+DEFAULT_ACCESS_KEY_ID = "test"
+DEFAULT_SECRET_ACCESS_KEY = "test"
+
+
+def enable_local_endpoints():
+ """Patch the boto3 library to transparently use the LocalStack endpoints by default."""
+ from localstack_client.config import get_service_endpoint
+
+ def _add_custom_kwargs(
+ kwargs,
+ service_name,
+ endpoint_url=None,
+ aws_access_key_id=None,
+ aws_secret_access_key=None,
+ ):
+ kwargs["endpoint_url"] = endpoint_url or get_service_endpoint(service_name)
+ kwargs["aws_access_key_id"] = aws_access_key_id or DEFAULT_ACCESS_KEY_ID
+ kwargs["aws_secret_access_key"] = (
+ aws_secret_access_key or DEFAULT_SECRET_ACCESS_KEY
+ )
+
+ def _client(
+ self,
+ service_name,
+ region_name=None,
+ api_version=None,
+ use_ssl=True,
+ verify=None,
+ endpoint_url=None,
+ aws_access_key_id=None,
+ aws_secret_access_key=None,
+ **kwargs,
+ ):
+ _add_custom_kwargs(
+ kwargs,
+ service_name,
+ endpoint_url=endpoint_url,
+ aws_access_key_id=aws_access_key_id,
+ aws_secret_access_key=aws_secret_access_key,
+ )
+ return _client_orig(
+ self,
+ service_name,
+ region_name=region_name,
+ api_version=api_version,
+ use_ssl=use_ssl,
+ verify=verify,
+ **kwargs,
+ )
+
+ def _resource(
+ self,
+ service_name,
+ region_name=None,
+ api_version=None,
+ use_ssl=True,
+ verify=None,
+ endpoint_url=None,
+ aws_access_key_id=None,
+ aws_secret_access_key=None,
+ **kwargs,
+ ):
+ _add_custom_kwargs(
+ kwargs,
+ service_name,
+ endpoint_url=endpoint_url,
+ aws_access_key_id=aws_access_key_id,
+ aws_secret_access_key=aws_secret_access_key,
+ )
+ return _resource_orig(
+ self,
+ service_name,
+ region_name=region_name,
+ api_version=api_version,
+ use_ssl=use_ssl,
+ verify=verify,
+ **kwargs,
+ )
+
+ if _state.get("_client_orig"):
+ # patch already applied -> return
+ return
+
+ # patch boto3 default session (if available)
+ try:
+ session = boto3._get_default_session()
+ _state["_default_client_orig"] = session.client
+ session.client = types.MethodType(_client, session)
+ _state["_default_resource_orig"] = session.resource
+ session.resource = types.MethodType(_resource, session)
+ except Exception:
+ # swallowing for now - looks like the default session is not available (yet)
+ pass
+
+ # patch session.client(..)
+ _client_orig = Session.client
+ _state["_client_orig"] = _client_orig
+ Session.client = _client
+
+ # patch session.resource(..)
+ _resource_orig = Session.resource
+ _state["_resource_orig"] = _resource_orig
+ Session.resource = _resource
+
+
+def disable_local_endpoints():
+ """Disable the boto3 patches and revert to using the default endpoints against real AWS."""
+
+ _client = _state.pop("_client_orig", None)
+ if _client:
+ Session.client = _client
+ _resource = _state.pop("_resource_orig", None)
+ if _resource:
+ Session.resource = _resource
+
+ # undo patches for boto3 default session
+ try:
+ session = boto3._get_default_session()
+ if _state.get("_default_client_orig"):
+ session.client = _state["_default_client_orig"]
+ if _state.get("_default_resource_orig"):
+ session.resource = _state["_default_resource_orig"]
+ except Exception:
+ pass
+
+
+def patch_expand_host_prefix():
+ """Apply a patch to botocore, to skip adding host prefixes to endpoint URLs"""
+
+ def _expand_host_prefix(self, parameters, operation_model, *args, **kwargs):
+ result = _expand_host_prefix_orig(
+ self, parameters, operation_model, *args, **kwargs
+ )
+ # skip adding host prefixes, to avoid making requests to, e.g., http://data-localhost:4566
+ is_sd = operation_model.service_model.service_name == "servicediscovery"
+ if is_sd and result == "data-":
+ return None
+ if operation_model.service_model.service_name == "mwaa" and result == "api.":
+ return None
+ return result
+
+ _expand_host_prefix_orig = Serializer._expand_host_prefix
+ Serializer._expand_host_prefix = _expand_host_prefix
diff --git a/localstack_client/session.py b/localstack_client/session.py
index 2415383..9bb7bb5 100644
--- a/localstack_client/session.py
+++ b/localstack_client/session.py
@@ -1,6 +1,7 @@
from boto3 import client as boto3_client
from boto3 import resource as boto3_resource
from botocore.credentials import Credentials
+
from localstack_client import config
DEFAULT_SESSION = None
@@ -12,10 +13,17 @@ class Session(object):
emulate the boto3.session object.
"""
- def __init__(self, aws_access_key_id='accesskey', aws_secret_access_key='secretkey',
- aws_session_token='token', region_name='us-east-1',
- botocore_session=None, profile_name=None, localstack_host=None):
- self.env = 'local'
+ def __init__(
+ self,
+ aws_access_key_id="accesskey",
+ aws_secret_access_key="secretkey",
+ aws_session_token="token",
+ region_name="us-east-1",
+ botocore_session=None,
+ profile_name=None,
+ localstack_host=None,
+ ):
+ self.env = "local"
self.aws_access_key_id = aws_access_key_id
self.aws_secret_access_key = aws_secret_access_key
self.aws_session_token = aws_session_token
@@ -23,19 +31,21 @@ def __init__(self, aws_access_key_id='accesskey', aws_secret_access_key='secretk
self._service_endpoint_mapping = config.get_service_endpoints(localstack_host)
self.common_protected_kwargs = {
- 'aws_access_key_id': self.aws_access_key_id,
- 'aws_secret_access_key': self.aws_secret_access_key,
- 'region_name': self.region_name,
- 'verify': False
+ "aws_access_key_id": self.aws_access_key_id,
+ "aws_secret_access_key": self.aws_secret_access_key,
+ "region_name": self.region_name,
+ "verify": False,
}
def get_credentials(self):
"""
Returns botocore.credential.Credential object.
"""
- return Credentials(access_key=self.aws_access_key_id,
- secret_key=self.aws_secret_access_key,
- token=self.aws_session_token)
+ return Credentials(
+ access_key=self.aws_access_key_id,
+ secret_key=self.aws_secret_access_key,
+ token=self.aws_session_token,
+ )
def client(self, service_name, **kwargs):
"""
@@ -45,12 +55,15 @@ def client(self, service_name, **kwargs):
Returns boto3.resources.factory.s3.ServiceClient object
"""
if service_name not in self._service_endpoint_mapping:
- raise Exception('%s is not supported by this mock session.' % (service_name))
-
- protected_kwargs = {**self.common_protected_kwargs,
- 'service_name': service_name,
- 'endpoint_url': self._service_endpoint_mapping[service_name]
- }
+ raise Exception(
+ "%s is not supported by this mock session." % (service_name)
+ )
+
+ protected_kwargs = {
+ **self.common_protected_kwargs,
+ "service_name": service_name,
+ "endpoint_url": self._service_endpoint_mapping[service_name],
+ }
return boto3_client(**{**kwargs, **protected_kwargs})
@@ -62,12 +75,15 @@ def resource(self, service_name, **kwargs):
Returns boto3.resources.factory.s3.ServiceResource object
"""
if service_name not in self._service_endpoint_mapping:
- raise Exception('%s is not supported by this mock session.' % (service_name))
-
- protected_kwargs = {**self.common_protected_kwargs,
- 'service_name': service_name,
- 'endpoint_url': self._service_endpoint_mapping[service_name]
- }
+ raise Exception(
+ "%s is not supported by this mock session." % (service_name)
+ )
+
+ protected_kwargs = {
+ **self.common_protected_kwargs,
+ "service_name": service_name,
+ "endpoint_url": self._service_endpoint_mapping[service_name],
+ }
return boto3_resource(**{**kwargs, **protected_kwargs})
diff --git a/setup.cfg b/setup.cfg
index aceab8d..21c52c4 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,18 +1,13 @@
[metadata]
name = localstack-client
-version = 1.37
+version = 1.38
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
description = A lightweight Python client for LocalStack.
license = Apache License 2.0
classifiers =
- Programming Language :: Python :: 2
- Programming Language :: Python :: 2.6
- Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
- Programming Language :: Python :: 3.3
- Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
@@ -30,7 +25,9 @@ install_requires =
[options.extras_require]
# Dependencies to run the tests
test =
+ black
coverage
- pycodestyle
- nose
+ flake8
+ isort
localstack
+ pytest
diff --git a/tests/client/__init__.py b/tests/client/__init__.py
index b75e802..e69de29 100644
--- a/tests/client/__init__.py
+++ b/tests/client/__init__.py
@@ -1,15 +0,0 @@
-import time
-import subprocess
-
-STATE = {}
-
-
-def setup_package():
- if STATE.get('process'):
- return
- STATE['process'] = subprocess.Popen(['localstack', 'start', '-d'])
- subprocess.Popen(['localstack', 'wait']).wait()
-
-
-def teardown_package():
- subprocess.Popen(['localstack', 'stop']).wait()
diff --git a/tests/client/conftest.py b/tests/client/conftest.py
new file mode 100644
index 0000000..1919695
--- /dev/null
+++ b/tests/client/conftest.py
@@ -0,0 +1,13 @@
+import subprocess
+
+import pytest
+
+
+@pytest.fixture(scope="session", autouse=True)
+def startup_localstack():
+ subprocess.check_output(["localstack", "start", "-d"])
+ subprocess.check_output(["localstack", "wait"])
+
+ yield
+
+ subprocess.check_output(["localstack", "stop"])
diff --git a/tests/client/test_patches.py b/tests/client/test_patches.py
new file mode 100644
index 0000000..f87f69c
--- /dev/null
+++ b/tests/client/test_patches.py
@@ -0,0 +1,36 @@
+import uuid
+
+import boto3
+import pytest
+
+from localstack_client.patch import (disable_local_endpoints,
+ enable_local_endpoints)
+
+
+def test_enable_local_endpoints(monkeypatch):
+ monkeypatch.setenv("AWS_DEFAULT_REGION", "us-east-1")
+
+ # create default client, requests should fail
+ with pytest.raises(Exception):
+ boto3.client("s3").list_buckets()
+ with pytest.raises(Exception):
+ resource = boto3.resource("s3")
+ bucket_name = str(uuid.uuid4())
+ resource.Bucket(bucket_name).create()
+
+ # enable local endpoints, request should pass
+ enable_local_endpoints()
+ assert "Buckets" in boto3.client("s3").list_buckets()
+ resource = boto3.resource("s3")
+ bucket_name = str(uuid.uuid4())
+ resource.Bucket(bucket_name).create()
+ resource.Bucket(bucket_name).delete()
+
+ # disable local endpoints again, request should fail
+ disable_local_endpoints()
+ with pytest.raises(Exception):
+ boto3.client("s3").list_buckets()
+ with pytest.raises(Exception):
+ resource = boto3.resource("s3")
+ bucket_name = str(uuid.uuid4())
+ resource.Bucket(bucket_name).create()
diff --git a/tests/client/test_python_client.py b/tests/client/test_python_client.py
index 5268d24..83903be 100644
--- a/tests/client/test_python_client.py
+++ b/tests/client/test_python_client.py
@@ -1,40 +1,41 @@
-import localstack_client.session
from botocore.client import Config
+import localstack_client.session
+
def test_session():
session = localstack_client.session.Session()
- sqs = session.client('sqs')
+ sqs = session.client("sqs")
assert sqs.list_queues() is not None
def test_client_kwargs_passed():
- """ Test kwargs passed through to boto3.client creation """
+ """Test kwargs passed through to boto3.client creation"""
session = localstack_client.session.Session()
- kwargs = {'config': Config(signature_version='s3v4')}
- sqs = session.client('sqs', **kwargs)
- assert sqs.meta.config.signature_version == 's3v4'
+ kwargs = {"config": Config(signature_version="s3v4")}
+ sqs = session.client("sqs", **kwargs)
+ assert sqs.meta.config.signature_version == "s3v4"
def test_protected_client_kwargs_not_passed():
- """ Test protected kwargs not overwritten in boto3.client creation """
+ """Test protected kwargs not overwritten in boto3.client creation"""
session = localstack_client.session.Session()
- kwargs = {'region_name': 'another_region'}
- sqs = session.client('sqs', **kwargs)
- assert not sqs.meta.region_name == 'another_region'
+ kwargs = {"region_name": "another_region"}
+ sqs = session.client("sqs", **kwargs)
+ assert not sqs.meta.region_name == "another_region"
def test_resource_kwargs_passed():
- """ Test kwargs passed through to boto3.resource creation """
+ """Test kwargs passed through to boto3.resource creation"""
session = localstack_client.session.Session()
- kwargs = {'config': Config(signature_version='s3v4')}
- sqs = session.resource('sqs', **kwargs)
- assert sqs.meta.client.meta.config.signature_version == 's3v4'
+ kwargs = {"config": Config(signature_version="s3v4")}
+ sqs = session.resource("sqs", **kwargs)
+ assert sqs.meta.client.meta.config.signature_version == "s3v4"
def test_protected_resource_kwargs_not_passed():
- """ Test protected kwargs not overwritten in boto3.resource creation """
+ """Test protected kwargs not overwritten in boto3.resource creation"""
session = localstack_client.session.Session()
- kwargs = {'region_name': 'another_region'}
- sqs = session.resource('sqs', **kwargs)
- assert not sqs.meta.client.meta.region_name == 'another_region'
+ kwargs = {"region_name": "another_region"}
+ sqs = session.resource("sqs", **kwargs)
+ assert not sqs.meta.client.meta.region_name == "another_region"
From f1e538ad23700e5b1afe98720404f4801475e470 Mon Sep 17 00:00:00 2001
From: David <6107913+ackdav@users.noreply.github.com>
Date: Mon, 5 Sep 2022 18:25:23 +0200
Subject: [PATCH 20/36] add endpoint for Amazon MQ service (#42)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 1 +
setup.cfg | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f755514..e45c48b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v1.39: Add endpoint for Amazon MQ
* v1.38: Add `enable_local_endpoints()` util function; slight project refactoring, migrate from `nose` to `pytests`
* v1.37: Add endpoint for Amazon Transcribe
* v1.36: Add endpoints for Fault Injection Service (FIS) and Marketplace Metering
diff --git a/localstack_client/config.py b/localstack_client/config.py
index ca689c3..c5097ea 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -114,6 +114,7 @@
"fis": "{proto}://{host}:4643",
"meteringmarketplace": "{proto}://{host}:4644",
"transcribe": "{proto}://{host}:4566",
+ "mq": "{proto}://{host}:4566"
}
# TODO remove service port mapping above entirely
diff --git a/setup.cfg b/setup.cfg
index 21c52c4..d8b8793 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 1.38
+version = 1.39
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 65109d6ade9b5755de15c4e1ad7190b30afaf0a2 Mon Sep 17 00:00:00 2001
From: Hamish Fagg
Date: Thu, 23 Mar 2023 08:27:05 +1300
Subject: [PATCH 21/36] Document env-var configuration options (#44)
---
README.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/README.md b/README.md
index 5a4922d..5300d4b 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,15 @@ sqs = boto3.client('sqs')
assert sqs.list_queues() is not None # list SQS in localstack
```
+## Configurations
+
+You can use the following environment variables for configuration:
+
+* `LOCALSTACK_HOST`: Set the hostname for the LocalStack instance. Useful when you have
+LocalStack bound to a different host (e.g., within docker-compose).
+* `EDGE_PORT`: Port number to use when connecting to LocalStack services. Defaults to `4566`.
+* `USE_SSL`: Whether to use `https` endpoint URLs. Defaults to `false`.
+
### Enabling Transparent Local Endpoints
The library contains a small `enable_local_endpoints()` util function that can be used to transparently run all `boto3` requests against the local endpoints.
From 14aadb3bad3fb987d50e96b049c97e0bdec75a2e Mon Sep 17 00:00:00 2001
From: Simon Walker
Date: Thu, 23 Mar 2023 11:56:38 +0000
Subject: [PATCH 22/36] New localstack_host format (#45)
* Use new LOCALSTACK_HOST format
This format includes the port number, so the service endpoints have been
re-written as service ports, since we can combine that with the
LOCALSTACK_HOST variable.
---
CHANGELOG.md | 1 +
README.md | 8 +-
localstack_client/config.py | 257 +++++++++++++++++++-----------------
setup.cfg | 2 +-
tests/test_config.py | 20 +++
5 files changed, 163 insertions(+), 125 deletions(-)
create mode 100644 tests/test_config.py
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e45c48b..4b18ebe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.0: Change `LOCALSTACK_HOSTNAME` from `` to `:`; remove `EDGE_PORT` environment variable
* v1.39: Add endpoint for Amazon MQ
* v1.38: Add `enable_local_endpoints()` util function; slight project refactoring, migrate from `nose` to `pytests`
* v1.37: Add endpoint for Amazon Transcribe
diff --git a/README.md b/README.md
index 5300d4b..3fce0b8 100644
--- a/README.md
+++ b/README.md
@@ -66,14 +66,12 @@ sqs = boto3.client('sqs')
assert sqs.list_queues() is not None # list SQS in localstack
```
-## Configurations
+## Configuration
You can use the following environment variables for configuration:
-* `LOCALSTACK_HOST`: Set the hostname for the LocalStack instance. Useful when you have
-LocalStack bound to a different host (e.g., within docker-compose).
-* `EDGE_PORT`: Port number to use when connecting to LocalStack services. Defaults to `4566`.
-* `USE_SSL`: Whether to use `https` endpoint URLs. Defaults to `false`.
+* `LOCALSTACK_HOST`: A `:` variable defining where to find LocalStack (default: `localhost:4566`).
+* `USE_SSL`: Whether to use SSL when connecting to LocalStack (default: `False`).
### Enabling Transparent Local Endpoints
diff --git a/localstack_client/config.py b/localstack_client/config.py
index c5097ea..adbce3f 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -1,130 +1,131 @@
-import json
import os
-from typing import Dict
+from typing import Dict, Optional, Tuple
from urllib.parse import urlparse
# note: leave this import here for now, as some upstream code is depending on it (TODO needs to be updated)
from localstack_client.patch import patch_expand_host_prefix # noqa
# central entrypoint port for all LocalStack API endpoints
-EDGE_PORT = int(os.environ.get("EDGE_PORT") or 4566)
+DEFAULT_EDGE_PORT = 4566
-# NOTE: The endpoints below will soon become deprecated/removed, as the default in the
+# NOTE: The ports listed below will soon become deprecated/removed, as the default in the
# latest version is to access all services via a single "edge service" (port 4566 by default)
-_service_endpoints_template = {
- "edge": "{proto}://{host}:4566",
- "apigateway": "{proto}://{host}:4567",
- "apigatewayv2": "{proto}://{host}:4567",
- "kinesis": "{proto}://{host}:4568",
- "dynamodb": "{proto}://{host}:4569",
- "dynamodbstreams": "{proto}://{host}:4570",
- "elasticsearch": "{proto}://{host}:4571",
- "s3": "{proto}://{host}:4572",
- "firehose": "{proto}://{host}:4573",
- "lambda": "{proto}://{host}:4574",
- "sns": "{proto}://{host}:4575",
- "sqs": "{proto}://{host}:4576",
- "redshift": "{proto}://{host}:4577",
- "redshift-data": "{proto}://{host}:4577",
- "es": "{proto}://{host}:4578",
- "opensearch": "{proto}://{host}:4578",
- "ses": "{proto}://{host}:4579",
- "sesv2": "{proto}://{host}:4579",
- "route53": "{proto}://{host}:4580",
- "route53resolver": "{proto}://{host}:4580",
- "cloudformation": "{proto}://{host}:4581",
- "cloudwatch": "{proto}://{host}:4582",
- "ssm": "{proto}://{host}:4583",
- "secretsmanager": "{proto}://{host}:4584",
- "stepfunctions": "{proto}://{host}:4585",
- "logs": "{proto}://{host}:4586",
- "events": "{proto}://{host}:4587",
- "elb": "{proto}://{host}:4588",
- "iot": "{proto}://{host}:4589",
- "iotanalytics": "{proto}://{host}:4589",
- "iotevents": "{proto}://{host}:4589",
- "iotevents-data": "{proto}://{host}:4589",
- "iotwireless": "{proto}://{host}:4589",
- "iot-data": "{proto}://{host}:4589",
- "iot-jobs-data": "{proto}://{host}:4589",
- "cognito-idp": "{proto}://{host}:4590",
- "cognito-identity": "{proto}://{host}:4591",
- "sts": "{proto}://{host}:4592",
- "iam": "{proto}://{host}:4593",
- "rds": "{proto}://{host}:4594",
- "rds-data": "{proto}://{host}:4594",
- "cloudsearch": "{proto}://{host}:4595",
- "swf": "{proto}://{host}:4596",
- "ec2": "{proto}://{host}:4597",
- "elasticache": "{proto}://{host}:4598",
- "kms": "{proto}://{host}:4599",
- "emr": "{proto}://{host}:4600",
- "ecs": "{proto}://{host}:4601",
- "eks": "{proto}://{host}:4602",
- "xray": "{proto}://{host}:4603",
- "elasticbeanstalk": "{proto}://{host}:4604",
- "appsync": "{proto}://{host}:4605",
- "cloudfront": "{proto}://{host}:4606",
- "athena": "{proto}://{host}:4607",
- "glue": "{proto}://{host}:4608",
- "sagemaker": "{proto}://{host}:4609",
- "sagemaker-runtime": "{proto}://{host}:4609",
- "ecr": "{proto}://{host}:4610",
- "qldb": "{proto}://{host}:4611",
- "qldb-session": "{proto}://{host}:4611",
- "cloudtrail": "{proto}://{host}:4612",
- "glacier": "{proto}://{host}:4613",
- "batch": "{proto}://{host}:4614",
- "organizations": "{proto}://{host}:4615",
- "autoscaling": "{proto}://{host}:4616",
- "mediastore": "{proto}://{host}:4617",
- "mediastore-data": "{proto}://{host}:4617",
- "transfer": "{proto}://{host}:4618",
- "acm": "{proto}://{host}:4619",
- "codecommit": "{proto}://{host}:4620",
- "kinesisanalytics": "{proto}://{host}:4621",
- "kinesisanalyticsv2": "{proto}://{host}:4621",
- "amplify": "{proto}://{host}:4622",
- "application-autoscaling": "{proto}://{host}:4623",
- "kafka": "{proto}://{host}:4624",
- "apigatewaymanagementapi": "{proto}://{host}:4625",
- "timestream": "{proto}://{host}:4626",
- "timestream-query": "{proto}://{host}:4626",
- "timestream-write": "{proto}://{host}:4626",
- "s3control": "{proto}://{host}:4627",
- "elbv2": "{proto}://{host}:4628",
- "support": "{proto}://{host}:4629",
- "neptune": "{proto}://{host}:4594",
- "docdb": "{proto}://{host}:4594",
- "servicediscovery": "{proto}://{host}:4630",
- "serverlessrepo": "{proto}://{host}:4631",
- "appconfig": "{proto}://{host}:4632",
- "ce": "{proto}://{host}:4633",
- "mediaconvert": "{proto}://{host}:4634",
- "resourcegroupstaggingapi": "{proto}://{host}:4635",
- "resource-groups": "{proto}://{host}:4636",
- "efs": "{proto}://{host}:4637",
- "backup": "{proto}://{host}:4638",
- "lakeformation": "{proto}://{host}:4639",
- "waf": "{proto}://{host}:4640",
- "wafv2": "{proto}://{host}:4640",
- "config": "{proto}://{host}:4641",
- "configservice": "{proto}://{host}:4641",
- "mwaa": "{proto}://{host}:4642",
- "fis": "{proto}://{host}:4643",
- "meteringmarketplace": "{proto}://{host}:4644",
- "transcribe": "{proto}://{host}:4566",
- "mq": "{proto}://{host}:4566"
+_service_ports: Dict[str, int] = {
+ "edge": 4566,
+ "apigateway": 4567,
+ "apigatewayv2": 4567,
+ "kinesis": 4568,
+ "dynamodb": 4569,
+ "dynamodbstreams": 4570,
+ "elasticsearch": 4571,
+ "s3": 4572,
+ "firehose": 4573,
+ "lambda": 4574,
+ "sns": 4575,
+ "sqs": 4576,
+ "redshift": 4577,
+ "redshift-data": 4577,
+ "es": 4578,
+ "opensearch": 4578,
+ "ses": 4579,
+ "sesv2": 4579,
+ "route53": 4580,
+ "route53resolver": 4580,
+ "cloudformation": 4581,
+ "cloudwatch": 4582,
+ "ssm": 4583,
+ "secretsmanager": 4584,
+ "stepfunctions": 4585,
+ "logs": 4586,
+ "events": 4587,
+ "elb": 4588,
+ "iot": 4589,
+ "iotanalytics": 4589,
+ "iotevents": 4589,
+ "iotevents-data": 4589,
+ "iotwireless": 4589,
+ "iot-data": 4589,
+ "iot-jobs-data": 4589,
+ "cognito-idp": 4590,
+ "cognito-identity": 4591,
+ "sts": 4592,
+ "iam": 4593,
+ "rds": 4594,
+ "rds-data": 4594,
+ "cloudsearch": 4595,
+ "swf": 4596,
+ "ec2": 4597,
+ "elasticache": 4598,
+ "kms": 4599,
+ "emr": 4600,
+ "ecs": 4601,
+ "eks": 4602,
+ "xray": 4603,
+ "elasticbeanstalk": 4604,
+ "appsync": 4605,
+ "cloudfront": 4606,
+ "athena": 4607,
+ "glue": 4608,
+ "sagemaker": 4609,
+ "sagemaker-runtime": 4609,
+ "ecr": 4610,
+ "qldb": 4611,
+ "qldb-session": 4611,
+ "cloudtrail": 4612,
+ "glacier": 4613,
+ "batch": 4614,
+ "organizations": 4615,
+ "autoscaling": 4616,
+ "mediastore": 4617,
+ "mediastore-data": 4617,
+ "transfer": 4618,
+ "acm": 4619,
+ "codecommit": 4620,
+ "kinesisanalytics": 4621,
+ "kinesisanalyticsv2": 4621,
+ "amplify": 4622,
+ "application-autoscaling": 4623,
+ "kafka": 4624,
+ "apigatewaymanagementapi": 4625,
+ "timestream": 4626,
+ "timestream-query": 4626,
+ "timestream-write": 4626,
+ "s3control": 4627,
+ "elbv2": 4628,
+ "support": 4629,
+ "neptune": 4594,
+ "docdb": 4594,
+ "servicediscovery": 4630,
+ "serverlessrepo": 4631,
+ "appconfig": 4632,
+ "ce": 4633,
+ "mediaconvert": 4634,
+ "resourcegroupstaggingapi": 4635,
+ "resource-groups": 4636,
+ "efs": 4637,
+ "backup": 4638,
+ "lakeformation": 4639,
+ "waf": 4640,
+ "wafv2": 4640,
+ "config": 4641,
+ "configservice": 4641,
+ "mwaa": 4642,
+ "fis": 4643,
+ "meteringmarketplace": 4644,
+ "transcribe": 4566,
+ "mq": 4566,
}
# TODO remove service port mapping above entirely
if os.environ.get("USE_LEGACY_PORTS") not in ["1", "true"]:
- for key, value in _service_endpoints_template.items():
+ for key, value in _service_ports.items():
if key not in ["dashboard", "elasticsearch"]:
- _service_endpoints_template[key] = f"{value.rpartition(':')[0]}:{EDGE_PORT}"
+ _service_ports[key] = DEFAULT_EDGE_PORT
-def get_service_endpoint(service: str, localstack_host: str = None) -> str:
+def get_service_endpoint(
+ service: str, localstack_host: Optional[str] = None
+) -> Optional[str]:
"""
Return the local endpoint URL for the given boto3 service (e.g., "s3").
If $AWS_ENDPOINT_URL is configured in the environment, it is returned directly.
@@ -137,19 +138,37 @@ def get_service_endpoint(service: str, localstack_host: str = None) -> str:
return endpoints.get(service)
-def get_service_endpoints(localstack_host: str = None) -> Dict[str, str]:
+def parse_localstack_host(given: str) -> Tuple[str, int]:
+ parts = given.split(":", 1)
+ if len(parts) == 1:
+ # just hostname
+ return parts[0].strip() or "localhost", DEFAULT_EDGE_PORT
+ elif len(parts) == 2:
+ hostname = parts[0].strip() or "localhost"
+ port_s = parts[1]
+ try:
+ port = int(port_s)
+ return (hostname, port)
+ except Exception:
+ raise RuntimeError(f"could not parse {given} into :")
+ else:
+ raise RuntimeError(f"could not parse {given} into :")
+
+
+def get_service_endpoints(localstack_host: Optional[str] = None) -> Dict[str, str]:
if localstack_host is None:
- localstack_host = os.environ.get("LOCALSTACK_HOST", "localhost")
+ localstack_host = os.environ.get(
+ "LOCALSTACK_HOST", f"localhost:{DEFAULT_EDGE_PORT}"
+ )
+
+ hostname, port = parse_localstack_host(localstack_host)
+
protocol = "https" if os.environ.get("USE_SSL") in ("1", "true") else "http"
- return json.loads(
- json.dumps(_service_endpoints_template)
- .replace("{proto}", protocol)
- .replace("{host}", localstack_host)
- )
+ return {key: f"{protocol}://{hostname}:{port}" for key in _service_ports.keys()}
-def get_service_port(service: str) -> int:
+def get_service_port(service: str) -> Optional[int]:
ports = get_service_ports()
return ports.get(service)
diff --git a/setup.cfg b/setup.cfg
index d8b8793..ad27a5e 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 1.39
+version = 2.0
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
diff --git a/tests/test_config.py b/tests/test_config.py
new file mode 100644
index 0000000..0c8ac2e
--- /dev/null
+++ b/tests/test_config.py
@@ -0,0 +1,20 @@
+from localstack_client import config
+
+
+def test_default_endpoint():
+ assert config.get_service_endpoint("sqs") == "http://localhost:4566"
+
+
+def test_with_localstack_host(monkeypatch):
+ monkeypatch.setenv("LOCALSTACK_HOST", "foobar:9999")
+ assert config.get_service_endpoint("sqs") == "http://foobar:9999"
+
+
+def test_without_port(monkeypatch):
+ monkeypatch.setenv("LOCALSTACK_HOST", "foobar")
+ assert config.get_service_endpoint("sqs") == "http://foobar:4566"
+
+
+def test_without_host(monkeypatch):
+ monkeypatch.setenv("LOCALSTACK_HOST", ":4566")
+ assert config.get_service_endpoint("sqs") == "http://localhost:4566"
From 08084836fd2aae835905b5f70a98606e0a997bb5 Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Thu, 18 May 2023 22:08:57 +0200
Subject: [PATCH 23/36] consider `AWS_ENDPOINT_URL` configuration when
resolving service endpoints (#46)
---
CHANGELOG.md | 1 +
README.md | 5 +++--
localstack_client/config.py | 32 +++++++++++++++++---------------
setup.cfg | 2 +-
4 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4b18ebe..3c13b4d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.1: Consider `AWS_ENDPOINT_URL` configuration when resolving service endpoints
* v2.0: Change `LOCALSTACK_HOSTNAME` from `` to `:`; remove `EDGE_PORT` environment variable
* v1.39: Add endpoint for Amazon MQ
* v1.38: Add `enable_local_endpoints()` util function; slight project refactoring, migrate from `nose` to `pytests`
diff --git a/README.md b/README.md
index 3fce0b8..7bca6dc 100644
--- a/README.md
+++ b/README.md
@@ -70,8 +70,9 @@ assert sqs.list_queues() is not None # list SQS in localstack
You can use the following environment variables for configuration:
-* `LOCALSTACK_HOST`: A `:` variable defining where to find LocalStack (default: `localhost:4566`).
-* `USE_SSL`: Whether to use SSL when connecting to LocalStack (default: `False`).
+* `AWS_ENDPOINT_URL`: The endpoint URL to connect to (takes precedence over `USE_SSL`/`LOCALSTACK_HOST` below)
+* `LOCALSTACK_HOST` (deprecated): A `:` variable defining where to find LocalStack (default: `localhost:4566`).
+* `USE_SSL` (deprecated): Whether to use SSL when connecting to LocalStack (default: `False`).
### Enabling Transparent Local Endpoints
diff --git a/localstack_client/config.py b/localstack_client/config.py
index adbce3f..9d6c710 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -8,6 +8,7 @@
# central entrypoint port for all LocalStack API endpoints
DEFAULT_EDGE_PORT = 4566
+# TODO: deprecated, remove!
# NOTE: The ports listed below will soon become deprecated/removed, as the default in the
# latest version is to access all services via a single "edge service" (port 4566 by default)
_service_ports: Dict[str, int] = {
@@ -123,21 +124,6 @@
_service_ports[key] = DEFAULT_EDGE_PORT
-def get_service_endpoint(
- service: str, localstack_host: Optional[str] = None
-) -> Optional[str]:
- """
- Return the local endpoint URL for the given boto3 service (e.g., "s3").
- If $AWS_ENDPOINT_URL is configured in the environment, it is returned directly.
- Otherwise, the service endpoint is constructed from the dict of service ports (usually http://localhost:4566).
- """
- env_endpoint_url = os.environ.get("AWS_ENDPOINT_URL", "").strip()
- if env_endpoint_url:
- return env_endpoint_url
- endpoints = get_service_endpoints(localstack_host=localstack_host)
- return endpoints.get(service)
-
-
def parse_localstack_host(given: str) -> Tuple[str, int]:
parts = given.split(":", 1)
if len(parts) == 1:
@@ -156,6 +142,15 @@ def parse_localstack_host(given: str) -> Tuple[str, int]:
def get_service_endpoints(localstack_host: Optional[str] = None) -> Dict[str, str]:
+ """
+ Return the local endpoint URLs for the list of supported boto3 services (e.g., "s3", "lambda", etc).
+ If $AWS_ENDPOINT_URL is configured in the environment, it is returned directly. Otherwise,
+ the service endpoint is constructed from the dict of service ports (usually http://localhost:4566).
+ """
+ env_endpoint_url = os.environ.get("AWS_ENDPOINT_URL", "").strip()
+ if env_endpoint_url:
+ return {key: env_endpoint_url for key in _service_ports.keys()}
+
if localstack_host is None:
localstack_host = os.environ.get(
"LOCALSTACK_HOST", f"localhost:{DEFAULT_EDGE_PORT}"
@@ -168,6 +163,13 @@ def get_service_endpoints(localstack_host: Optional[str] = None) -> Dict[str, st
return {key: f"{protocol}://{hostname}:{port}" for key in _service_ports.keys()}
+def get_service_endpoint(
+ service: str, localstack_host: Optional[str] = None
+) -> Optional[str]:
+ endpoints = get_service_endpoints(localstack_host=localstack_host)
+ return endpoints.get(service)
+
+
def get_service_port(service: str) -> Optional[int]:
ports = get_service_ports()
return ports.get(service)
diff --git a/setup.cfg b/setup.cfg
index ad27a5e..b348f56 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.0
+version = 2.1
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 579d50ce443074e9e5c2c96cef5b62098444aa33 Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Fri, 9 Jun 2023 19:29:29 +0200
Subject: [PATCH 24/36] add endpoint configs for emr-serverless and a few other
services (#47)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 4 ++++
setup.cfg | 2 +-
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3c13b4d..26f51b6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.2: Add endpoint configs for `emr-serverless` and a few other services
* v2.1: Consider `AWS_ENDPOINT_URL` configuration when resolving service endpoints
* v2.0: Change `LOCALSTACK_HOSTNAME` from `` to `:`; remove `EDGE_PORT` environment variable
* v1.39: Add endpoint for Amazon MQ
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 9d6c710..51f8c13 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -115,6 +115,10 @@
"meteringmarketplace": 4644,
"transcribe": 4566,
"mq": 4566,
+ "emr-serverless": 4566,
+ "appflow": 4566,
+ "route53domains": 4566,
+ "keyspaces": 4566,
}
# TODO remove service port mapping above entirely
diff --git a/setup.cfg b/setup.cfg
index b348f56..41f493c 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.1
+version = 2.2
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 1e1a434ca7747d772e3f4acd9535ae32fb2d5259 Mon Sep 17 00:00:00 2001
From: Viren Nadkarni
Date: Sun, 30 Jul 2023 00:48:51 +0530
Subject: [PATCH 25/36] add endpoint config for EventBridge Scheduler (#48)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 1 +
setup.cfg | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 26f51b6..d3e3dbe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.3: Add endpoint config for Amazon EventBridge Scheduler
* v2.2: Add endpoint configs for `emr-serverless` and a few other services
* v2.1: Consider `AWS_ENDPOINT_URL` configuration when resolving service endpoints
* v2.0: Change `LOCALSTACK_HOSTNAME` from `` to `:`; remove `EDGE_PORT` environment variable
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 51f8c13..59b5b23 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -119,6 +119,7 @@
"appflow": 4566,
"route53domains": 4566,
"keyspaces": 4566,
+ "scheduler": 4566,
}
# TODO remove service port mapping above entirely
diff --git a/setup.cfg b/setup.cfg
index 41f493c..22e762c 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.2
+version = 2.3
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 2aa7da844a6fc56e8f3d655fbcd3f4cc76e5c7c2 Mon Sep 17 00:00:00 2001
From: Viren Nadkarni
Date: Tue, 19 Sep 2023 14:39:00 +0530
Subject: [PATCH 26/36] Add endpoint for Resource Access Manager (#49)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 1 +
setup.cfg | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d3e3dbe..caf711c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.4: Add endpoint config for Resource Access Manager
* v2.3: Add endpoint config for Amazon EventBridge Scheduler
* v2.2: Add endpoint configs for `emr-serverless` and a few other services
* v2.1: Consider `AWS_ENDPOINT_URL` configuration when resolving service endpoints
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 59b5b23..9163d12 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -120,6 +120,7 @@
"route53domains": 4566,
"keyspaces": 4566,
"scheduler": 4566,
+ "ram": 4566,
}
# TODO remove service port mapping above entirely
diff --git a/setup.cfg b/setup.cfg
index 22e762c..b7cc704 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.3
+version = 2.4
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From f6195ce4ed9e7a607d608ed8bbb27514aa7fd39e Mon Sep 17 00:00:00 2001
From: Waldemar Hummer
Date: Thu, 19 Oct 2023 22:27:35 +0200
Subject: [PATCH 27/36] add endpoint config for appconfigdata (#50)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 1 +
setup.cfg | 4 +++-
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index caf711c..3e305ab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.5: Add endpoint config for AppConfig Data
* v2.4: Add endpoint config for Resource Access Manager
* v2.3: Add endpoint config for Amazon EventBridge Scheduler
* v2.2: Add endpoint configs for `emr-serverless` and a few other services
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 9163d12..1e9073f 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -99,6 +99,7 @@
"servicediscovery": 4630,
"serverlessrepo": 4631,
"appconfig": 4632,
+ "appconfigdata": 4632,
"ce": 4633,
"mediaconvert": 4634,
"resourcegroupstaggingapi": 4635,
diff --git a/setup.cfg b/setup.cfg
index b7cc704..205dac9 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.4
+version = 2.5
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
@@ -12,6 +12,8 @@ classifiers =
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
+ Programming Language :: Python :: 3.10
+ Programming Language :: Python :: 3.11
License :: OSI Approved :: Apache Software License
Topic :: Software Development :: Testing
From 60c174aad83e05892ecd6fa283ce709ea9f4096b Mon Sep 17 00:00:00 2001
From: Ben Simon Hartung <42031100+bentsku@users.noreply.github.com>
Date: Mon, 9 Sep 2024 16:04:45 +0300
Subject: [PATCH 28/36] add endpoint configuration for Pinpoint (#53)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 1 +
setup.cfg | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3e305ab..5e1523e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.6: Add endpoint config for Pinpoint
* v2.5: Add endpoint config for AppConfig Data
* v2.4: Add endpoint config for Resource Access Manager
* v2.3: Add endpoint config for Amazon EventBridge Scheduler
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 1e9073f..76ab1b5 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -122,6 +122,7 @@
"keyspaces": 4566,
"scheduler": 4566,
"ram": 4566,
+ "pinpoint": 4566,
}
# TODO remove service port mapping above entirely
diff --git a/setup.cfg b/setup.cfg
index 205dac9..1a12009 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.5
+version = 2.6
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 5b8d55fae2bb7730115eeb60062397e0a97a8393 Mon Sep 17 00:00:00 2001
From: Harsh Mishra
Date: Tue, 8 Oct 2024 16:46:08 +0530
Subject: [PATCH 29/36] add endpoint entry for EventBridge pipes (#54)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 1 +
setup.cfg | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e1523e..08de6ca 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.7: Add endpoint config for EventBridge Pipes
* v2.6: Add endpoint config for Pinpoint
* v2.5: Add endpoint config for AppConfig Data
* v2.4: Add endpoint config for Resource Access Manager
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 76ab1b5..8ee2c03 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -123,6 +123,7 @@
"scheduler": 4566,
"ram": 4566,
"pinpoint": 4566,
+ "pipes": 4566,
}
# TODO remove service port mapping above entirely
diff --git a/setup.cfg b/setup.cfg
index 1a12009..aa02212 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.6
+version = 2.7
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From f1c2318dbc83d0452286c9764502db894b9333d2 Mon Sep 17 00:00:00 2001
From: Mathieu Cloutier <79954947+cloutierMat@users.noreply.github.com>
Date: Wed, 20 Nov 2024 10:47:48 -0700
Subject: [PATCH 30/36] update python version (#55)
---
.github/workflows/ci.yml | 5 ++++-
CHANGELOG.md | 1 +
setup.cfg | 6 +++---
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d48bbf3..5b894e9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,6 +5,7 @@ on:
branches: [ master ]
pull_request:
branches: [ master ]
+ workflow_dispatch:
jobs:
test:
@@ -13,10 +14,12 @@ jobs:
fail-fast: false
matrix:
python-version:
+ - "3.13"
+ - "3.12"
+ - "3.11"
- "3.10"
- "3.9"
- "3.8"
- - "3.7"
steps:
- uses: actions/checkout@v2
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 08de6ca..6476dce 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.8: Removes support for python `3.6` and `3.7` and adds `3.12` and `3.13` for parity with boto3
* v2.7: Add endpoint config for EventBridge Pipes
* v2.6: Add endpoint config for Pinpoint
* v2.5: Add endpoint config for AppConfig Data
diff --git a/setup.cfg b/setup.cfg
index aa02212..4b18765 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.7
+version = 2.8
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
@@ -8,12 +8,12 @@ description = A lightweight Python client for LocalStack.
license = Apache License 2.0
classifiers =
Programming Language :: Python :: 3
- Programming Language :: Python :: 3.6
- Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
+ Programming Language :: Python :: 3.12
+ Programming Language :: Python :: 3.13
License :: OSI Approved :: Apache Software License
Topic :: Software Development :: Testing
From 39fa060d2ba570fbae47d9d4302245c7786117c1 Mon Sep 17 00:00:00 2001
From: Viren Nadkarni
Date: Wed, 2 Apr 2025 17:14:35 +0530
Subject: [PATCH 31/36] Update endpoint services (#56)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 196 +++++++++++++++++++-----------------
setup.cfg | 2 +-
3 files changed, 108 insertions(+), 91 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6476dce..99b46bd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.9: Add endpoints for Account Management, Private Certificate Authority, Bedrock, CloudControl, CodeBuild, CodeCommit, CodeConnections, CodeDeploy, CodePipeline, ElasticTranscoder, MemoryDB, Shield, Textract and Verified Permissions
* v2.8: Removes support for python `3.6` and `3.7` and adds `3.12` and `3.13` for parity with boto3
* v2.7: Add endpoint config for EventBridge Pipes
* v2.6: Add endpoint config for Pinpoint
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 8ee2c03..0faa62a 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -13,117 +13,133 @@
# latest version is to access all services via a single "edge service" (port 4566 by default)
_service_ports: Dict[str, int] = {
"edge": 4566,
+ # Botocore services
+ # When adding new services below, assign them port 4566
+ "account": 4566,
+ "acm": 4619,
+ "acm-pca": 4566,
+ "amplify": 4622,
"apigateway": 4567,
+ "apigatewaymanagementapi": 4625,
"apigatewayv2": 4567,
- "kinesis": 4568,
+ "appconfig": 4632,
+ "appconfigdata": 4632,
+ "appflow": 4566,
+ "application-autoscaling": 4623,
+ "appsync": 4605,
+ "athena": 4607,
+ "autoscaling": 4616,
+ "backup": 4638,
+ "batch": 4614,
+ "bedrock": 4566,
+ "bedrock-runtime": 4566,
+ "ce": 4633,
+ "cloudcontrol": 4566,
+ "cloudformation": 4581,
+ "cloudfront": 4606,
+ "cloudsearch": 4595,
+ "cloudtrail": 4612,
+ "cloudwatch": 4582,
+ "codebuild": 4566,
+ "codecommit": 4620,
+ "codeconnections": 4566,
+ "codedeploy": 4566,
+ "codepipeline": 4566,
+ "cognito-identity": 4591,
+ "cognito-idp": 4590,
+ "config": 4641,
+ "configservice": 4641,
+ "docdb": 4594,
"dynamodb": 4569,
"dynamodbstreams": 4570,
+ "ec2": 4597,
+ "ecr": 4610,
+ "ecs": 4601,
+ "efs": 4637,
+ "eks": 4602,
+ "elasticache": 4598,
+ "elasticbeanstalk": 4604,
"elasticsearch": 4571,
- "s3": 4572,
- "firehose": 4573,
- "lambda": 4574,
- "sns": 4575,
- "sqs": 4576,
- "redshift": 4577,
- "redshift-data": 4577,
+ "elastictranscoder": 4566,
+ "elb": 4588,
+ "elbv2": 4628,
+ "emr": 4600,
+ "emr-serverless": 4566,
"es": 4578,
- "opensearch": 4578,
- "ses": 4579,
- "sesv2": 4579,
- "route53": 4580,
- "route53resolver": 4580,
- "cloudformation": 4581,
- "cloudwatch": 4582,
- "ssm": 4583,
- "secretsmanager": 4584,
- "stepfunctions": 4585,
- "logs": 4586,
"events": 4587,
- "elb": 4588,
+ "firehose": 4573,
+ "fis": 4643,
+ "glacier": 4613,
+ "glue": 4608,
+ "iam": 4593,
"iot": 4589,
"iotanalytics": 4589,
+ "iot-data": 4589,
"iotevents": 4589,
"iotevents-data": 4589,
- "iotwireless": 4589,
- "iot-data": 4589,
"iot-jobs-data": 4589,
- "cognito-idp": 4590,
- "cognito-identity": 4591,
- "sts": 4592,
- "iam": 4593,
+ "iotwireless": 4589,
+ "kafka": 4624,
+ "keyspaces": 4566,
+ "kinesis": 4568,
+ "kinesisanalytics": 4621,
+ "kinesisanalyticsv2": 4621,
+ "kms": 4599,
+ "lakeformation": 4639,
+ "lambda": 4574,
+ "logs": 4586,
+ "mediaconvert": 4634,
+ "mediastore": 4617,
+ "mediastore-data": 4617,
+ "meteringmarketplace": 4644,
+ "memorydb": 4566,
+ "mq": 4566,
+ "mwaa": 4642,
+ "neptune": 4594,
+ "opensearch": 4578,
+ "organizations": 4615,
+ "pinpoint": 4566,
+ "pipes": 4566,
+ "qldb": 4611,
+ "qldb-session": 4611,
+ "ram": 4566,
"rds": 4594,
"rds-data": 4594,
- "cloudsearch": 4595,
- "swf": 4596,
- "ec2": 4597,
- "elasticache": 4598,
- "kms": 4599,
- "emr": 4600,
- "ecs": 4601,
- "eks": 4602,
- "xray": 4603,
- "elasticbeanstalk": 4604,
- "appsync": 4605,
- "cloudfront": 4606,
- "athena": 4607,
- "glue": 4608,
+ "redshift": 4577,
+ "redshift-data": 4577,
+ "resource-groups": 4636,
+ "resourcegroupstaggingapi": 4635,
+ "route53": 4580,
+ "route53domains": 4566,
+ "route53resolver": 4580,
+ "s3": 4572,
+ "s3control": 4627,
"sagemaker": 4609,
"sagemaker-runtime": 4609,
- "ecr": 4610,
- "qldb": 4611,
- "qldb-session": 4611,
- "cloudtrail": 4612,
- "glacier": 4613,
- "batch": 4614,
- "organizations": 4615,
- "autoscaling": 4616,
- "mediastore": 4617,
- "mediastore-data": 4617,
- "transfer": 4618,
- "acm": 4619,
- "codecommit": 4620,
- "kinesisanalytics": 4621,
- "kinesisanalyticsv2": 4621,
- "amplify": 4622,
- "application-autoscaling": 4623,
- "kafka": 4624,
- "apigatewaymanagementapi": 4625,
+ "scheduler": 4566,
+ "secretsmanager": 4584,
+ "serverlessrepo": 4631,
+ "servicediscovery": 4630,
+ "ses": 4579,
+ "sesv2": 4579,
+ "shield": 4566,
+ "sns": 4575,
+ "sqs": 4576,
+ "ssm": 4583,
+ "stepfunctions": 4585,
+ "sts": 4592,
+ "support": 4629,
+ "swf": 4596,
+ "textract": 4566,
"timestream": 4626,
"timestream-query": 4626,
"timestream-write": 4626,
- "s3control": 4627,
- "elbv2": 4628,
- "support": 4629,
- "neptune": 4594,
- "docdb": 4594,
- "servicediscovery": 4630,
- "serverlessrepo": 4631,
- "appconfig": 4632,
- "appconfigdata": 4632,
- "ce": 4633,
- "mediaconvert": 4634,
- "resourcegroupstaggingapi": 4635,
- "resource-groups": 4636,
- "efs": 4637,
- "backup": 4638,
- "lakeformation": 4639,
+ "transcribe": 4566,
+ "transfer": 4618,
+ "verifiedpermissions": 4566,
"waf": 4640,
"wafv2": 4640,
- "config": 4641,
- "configservice": 4641,
- "mwaa": 4642,
- "fis": 4643,
- "meteringmarketplace": 4644,
- "transcribe": 4566,
- "mq": 4566,
- "emr-serverless": 4566,
- "appflow": 4566,
- "route53domains": 4566,
- "keyspaces": 4566,
- "scheduler": 4566,
- "ram": 4566,
- "pinpoint": 4566,
- "pipes": 4566,
+ "xray": 4603,
}
# TODO remove service port mapping above entirely
diff --git a/setup.cfg b/setup.cfg
index 4b18765..1104dab 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.8
+version = 2.9
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 041fdfb02d62f5a5fbabe313f80b6d94ec65c811 Mon Sep 17 00:00:00 2001
From: Viren Nadkarni
Date: Wed, 2 Apr 2025 17:37:14 +0530
Subject: [PATCH 32/36] Remove unsupported endpoint overrides (#57)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 2 --
setup.cfg | 2 +-
3 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 99b46bd..eac2216 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.10: Remove endpoints for 'bedrock-runtime' and 'textract' because overriding them is not supported by the AWS Terraform provider
* v2.9: Add endpoints for Account Management, Private Certificate Authority, Bedrock, CloudControl, CodeBuild, CodeCommit, CodeConnections, CodeDeploy, CodePipeline, ElasticTranscoder, MemoryDB, Shield, Textract and Verified Permissions
* v2.8: Removes support for python `3.6` and `3.7` and adds `3.12` and `3.13` for parity with boto3
* v2.7: Add endpoint config for EventBridge Pipes
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 0faa62a..10ba740 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -32,7 +32,6 @@
"backup": 4638,
"batch": 4614,
"bedrock": 4566,
- "bedrock-runtime": 4566,
"ce": 4633,
"cloudcontrol": 4566,
"cloudformation": 4581,
@@ -130,7 +129,6 @@
"sts": 4592,
"support": 4629,
"swf": 4596,
- "textract": 4566,
"timestream": 4626,
"timestream-query": 4626,
"timestream-write": 4626,
diff --git a/setup.cfg b/setup.cfg
index 1104dab..412f97f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.9
+version = 2.10
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 502a8e87985c83ad544d39808c7714175ef178eb Mon Sep 17 00:00:00 2001
From: Przemek Denkiewicz <67517453+hovaesco@users.noreply.github.com>
Date: Fri, 9 Jan 2026 11:06:13 +0100
Subject: [PATCH 33/36] Add S3 tables to list of supported services (#58)
* Add S3 tables to list of supported services
* bump version and add changelog entry
---
CHANGELOG.md | 1 +
localstack_client/config.py | 1 +
setup.cfg | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index eac2216..36a898b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.11: Add endpoint config for S3 Tables
* v2.10: Remove endpoints for 'bedrock-runtime' and 'textract' because overriding them is not supported by the AWS Terraform provider
* v2.9: Add endpoints for Account Management, Private Certificate Authority, Bedrock, CloudControl, CodeBuild, CodeCommit, CodeConnections, CodeDeploy, CodePipeline, ElasticTranscoder, MemoryDB, Shield, Textract and Verified Permissions
* v2.8: Removes support for python `3.6` and `3.7` and adds `3.12` and `3.13` for parity with boto3
diff --git a/localstack_client/config.py b/localstack_client/config.py
index 10ba740..e4482ad 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -113,6 +113,7 @@
"route53resolver": 4580,
"s3": 4572,
"s3control": 4627,
+ "s3tables": 4566,
"sagemaker": 4609,
"sagemaker-runtime": 4609,
"scheduler": 4566,
diff --git a/setup.cfg b/setup.cfg
index 412f97f..59d206d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.10
+version = 2.11
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 29cba5e14960fbe73023f5998edc2173e471704b Mon Sep 17 00:00:00 2001
From: Alex Rashed <2796604+alexrashed@users.noreply.github.com>
Date: Wed, 25 Feb 2026 10:22:24 +0100
Subject: [PATCH 34/36] update LocalStack links in README.md (#59)
Updated LocalStack links to point to the official website.
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 7bca6dc..fb0b55f 100644
--- a/README.md
+++ b/README.md
@@ -7,14 +7,14 @@
-This is an easy-to-use Python client for [LocalStack](https://github.com/localstack/localstack).
+This is an easy-to-use Python client for [LocalStack](https://www.localstack.cloud/).
The client library provides a thin wrapper around [boto3](https://github.com/boto/boto3) which
automatically configures the target endpoints to use LocalStack for your local cloud
application development.
## Prerequisites
-To make use of this library, you need to have [LocalStack](https://github.com/localstack/localstack) installed on your local machine. In particular, the `localstack` command needs to be available.
+To make use of this library, you need to have [LocalStack](https://www.localstack.cloud/) installed on your local machine. In particular, the `localstack` command needs to be available.
## Installation
From 4bee152cb72167409c8a8473b081189c9d94faf4 Mon Sep 17 00:00:00 2001
From: Yoshiaki Yoshida
Date: Tue, 21 Jul 2026 18:47:27 +0900
Subject: [PATCH 35/36] feat: add endpoint config for Amazon Aurora DSQL (#60)
---
CHANGELOG.md | 1 +
localstack_client/config.py | 1 +
setup.cfg | 2 +-
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 36a898b..8e60cab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# LocalStack Python Client Change Log
+* v2.12: Add endpoint config for Amazon Aurora DSQL
* v2.11: Add endpoint config for S3 Tables
* v2.10: Remove endpoints for 'bedrock-runtime' and 'textract' because overriding them is not supported by the AWS Terraform provider
* v2.9: Add endpoints for Account Management, Private Certificate Authority, Bedrock, CloudControl, CodeBuild, CodeCommit, CodeConnections, CodeDeploy, CodePipeline, ElasticTranscoder, MemoryDB, Shield, Textract and Verified Permissions
diff --git a/localstack_client/config.py b/localstack_client/config.py
index e4482ad..4e5a365 100644
--- a/localstack_client/config.py
+++ b/localstack_client/config.py
@@ -49,6 +49,7 @@
"config": 4641,
"configservice": 4641,
"docdb": 4594,
+ "dsql": 4566,
"dynamodb": 4569,
"dynamodbstreams": 4570,
"ec2": 4597,
diff --git a/setup.cfg b/setup.cfg
index 59d206d..35363a6 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = localstack-client
-version = 2.11
+version = 2.12
url = https://github.com/localstack/localstack-python-client
author = LocalStack Team
author_email = info@localstack.cloud
From 75fd3274bce2927b8c4675d69b014a3e56e7f704 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cristian=20Pallar=C3=A9s?=
Date: Tue, 21 Jul 2026 12:32:08 +0200
Subject: [PATCH 36/36] fix: use python -m build in make publish, drop setup.py
(#61)
PyPI now rejects sdist filenames from the legacy `setup.py sdist`
path (hyphenated) since it enforces PEP 625 normalized names
(underscore). Switch to `python -m build`, which also produces a
wheel. setup.py was just a `setup()` shim; replaced with a minimal
pyproject.toml declaring the setuptools build backend.
---
.github/workflows/ci.yml | 2 ++
Makefile | 5 ++++-
pyproject.toml | 3 +++
setup.py | 4 ----
4 files changed, 9 insertions(+), 5 deletions(-)
create mode 100644 pyproject.toml
delete mode 100755 setup.py
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5b894e9..cdcd043 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -40,3 +40,5 @@ jobs:
- name: Test
run: make test
+ env:
+ LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
diff --git a/Makefile b/Makefile
index 150194b..13c0acb 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,10 @@ install: ## Install dependencies in local virtualenv folder
publish: ## Publish the library to the central PyPi repository
# build and upload archive
- $(VENV_RUN); ./setup.py sdist && twine upload $(BUILD_DIR)/*.tar.gz
+ rm -rf $(BUILD_DIR)
+ $(VENV_RUN); $(PIP_CMD) install --upgrade build twine && \
+ python -m build --sdist --wheel && \
+ twine upload $(BUILD_DIR)/*
test: ## Run automated tests
($(VENV_RUN); test `which localstack` || pip install .[test]) && \
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..fed528d
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["setuptools"]
+build-backend = "setuptools.build_meta"
diff --git a/setup.py b/setup.py
deleted file mode 100755
index ac42fe2..0000000
--- a/setup.py
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env python
-
-from setuptools import setup
-setup()