testcontainers-rustfs 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 molnarbence.dev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,107 @@
1
+ Metadata-Version: 2.4
2
+ Name: testcontainers-rustfs
3
+ Version: 1.0.0
4
+ Summary: Unofficial Testcontainers Python module for RustFS
5
+ Author: Bence Molnár
6
+ Author-email: Bence Molnár <developer@molnarbence.dev>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Classifier: Topic :: Software Development :: Testing
15
+ Classifier: Typing :: Typed
16
+ Requires-Dist: testcontainers>=4.15.0
17
+ Requires-Dist: boto3>=1.34 ; extra == 'boto3'
18
+ Requires-Python: >=3.14
19
+ Project-URL: Homepage, https://github.com/mb-dot-dev/testcontainers-rustfs
20
+ Project-URL: Repository, https://github.com/mb-dot-dev/testcontainers-rustfs
21
+ Project-URL: Issues, https://github.com/mb-dot-dev/testcontainers-rustfs/issues
22
+ Provides-Extra: boto3
23
+ Description-Content-Type: text/markdown
24
+
25
+ # testcontainers-rustfs
26
+
27
+ Unofficial [Testcontainers](https://testcontainers.com/) Python module for
28
+ [RustFS](https://github.com/rustfs/rustfs), an S3-compatible object store.
29
+
30
+ Not affiliated with or endorsed by the RustFS or Testcontainers projects.
31
+
32
+ ## Install
33
+
34
+ Requires Python 3.14 or newer.
35
+
36
+ ```bash
37
+ pip install 'testcontainers-rustfs[boto3]'
38
+ ```
39
+
40
+ The `boto3` extra is optional. Without it the container still starts and
41
+ `get_config()` / `get_url()` work; only `get_client()` requires boto3.
42
+
43
+ ## Usage
44
+
45
+ ```python
46
+ from testcontainers_rustfs import RustfsContainer
47
+
48
+ with RustfsContainer() as rustfs:
49
+ client = rustfs.get_client()
50
+ client.create_bucket(Bucket="testbucket")
51
+ client.put_object(Bucket="testbucket", Key="hello.txt", Body=b"Hello RustFS")
52
+
53
+ stored = client.get_object(Bucket="testbucket", Key="hello.txt")["Body"].read()
54
+ ```
55
+
56
+ Bucket names must be 3–63 characters — RustFS rejects shorter names with
57
+ `InvalidBucketName`.
58
+
59
+ ### Bringing your own client
60
+
61
+ ```python
62
+ with RustfsContainer() as rustfs:
63
+ config = rustfs.get_config()
64
+ # {'endpoint': 'localhost:32768', 'endpoint_url': 'http://localhost:32768',
65
+ # 'access_key': 'rustfsadmin', 'secret_key': 'rustfsadmin', 'region_name': 'us-east-1'}
66
+ ```
67
+
68
+ `endpoint` is the `host:port` form some SDKs expect; `endpoint_url` is the full
69
+ URL boto3 wants.
70
+
71
+ ### Web console
72
+
73
+ Disabled by default. Enable it to inspect a failing test's data by eye:
74
+
75
+ ```python
76
+ with RustfsContainer(console=True) as rustfs:
77
+ print(rustfs.get_console_url())
78
+ ```
79
+
80
+ `get_console_url()` raises `RuntimeError` if the console was not enabled.
81
+
82
+ ## Configuration
83
+
84
+ | Parameter | Default | Description |
85
+ |---|---|---|
86
+ | `image` | `rustfs/rustfs:1.0.0-beta.12` | Docker image. Pinned deliberately — RustFS is pre-1.0 and `:latest` moves often |
87
+ | `port` | `9000` | Container port serving the S3 API |
88
+ | `access_key` | `rustfsadmin` | Access key for client connections |
89
+ | `secret_key` | `rustfsadmin` | Secret key for client connections |
90
+ | `console` | `False` | Enable and expose the web console (keyword-only) |
91
+ | `console_port` | `9001` | Container port serving the console (keyword-only) |
92
+ | `region_name` | `us-east-1` | Region reported to S3 clients (keyword-only) |
93
+
94
+ Any further keyword arguments are passed through to `DockerContainer`.
95
+
96
+ Credentials and region are always passed explicitly to the boto3 client, so your
97
+ `~/.aws/config` never influences test behaviour.
98
+
99
+ ## Development
100
+
101
+ ```bash
102
+ make install-dev
103
+ make test # lint + unit
104
+ make coverage
105
+ ```
106
+
107
+ Tests require a running Docker daemon.
@@ -0,0 +1,83 @@
1
+ # testcontainers-rustfs
2
+
3
+ Unofficial [Testcontainers](https://testcontainers.com/) Python module for
4
+ [RustFS](https://github.com/rustfs/rustfs), an S3-compatible object store.
5
+
6
+ Not affiliated with or endorsed by the RustFS or Testcontainers projects.
7
+
8
+ ## Install
9
+
10
+ Requires Python 3.14 or newer.
11
+
12
+ ```bash
13
+ pip install 'testcontainers-rustfs[boto3]'
14
+ ```
15
+
16
+ The `boto3` extra is optional. Without it the container still starts and
17
+ `get_config()` / `get_url()` work; only `get_client()` requires boto3.
18
+
19
+ ## Usage
20
+
21
+ ```python
22
+ from testcontainers_rustfs import RustfsContainer
23
+
24
+ with RustfsContainer() as rustfs:
25
+ client = rustfs.get_client()
26
+ client.create_bucket(Bucket="testbucket")
27
+ client.put_object(Bucket="testbucket", Key="hello.txt", Body=b"Hello RustFS")
28
+
29
+ stored = client.get_object(Bucket="testbucket", Key="hello.txt")["Body"].read()
30
+ ```
31
+
32
+ Bucket names must be 3–63 characters — RustFS rejects shorter names with
33
+ `InvalidBucketName`.
34
+
35
+ ### Bringing your own client
36
+
37
+ ```python
38
+ with RustfsContainer() as rustfs:
39
+ config = rustfs.get_config()
40
+ # {'endpoint': 'localhost:32768', 'endpoint_url': 'http://localhost:32768',
41
+ # 'access_key': 'rustfsadmin', 'secret_key': 'rustfsadmin', 'region_name': 'us-east-1'}
42
+ ```
43
+
44
+ `endpoint` is the `host:port` form some SDKs expect; `endpoint_url` is the full
45
+ URL boto3 wants.
46
+
47
+ ### Web console
48
+
49
+ Disabled by default. Enable it to inspect a failing test's data by eye:
50
+
51
+ ```python
52
+ with RustfsContainer(console=True) as rustfs:
53
+ print(rustfs.get_console_url())
54
+ ```
55
+
56
+ `get_console_url()` raises `RuntimeError` if the console was not enabled.
57
+
58
+ ## Configuration
59
+
60
+ | Parameter | Default | Description |
61
+ |---|---|---|
62
+ | `image` | `rustfs/rustfs:1.0.0-beta.12` | Docker image. Pinned deliberately — RustFS is pre-1.0 and `:latest` moves often |
63
+ | `port` | `9000` | Container port serving the S3 API |
64
+ | `access_key` | `rustfsadmin` | Access key for client connections |
65
+ | `secret_key` | `rustfsadmin` | Secret key for client connections |
66
+ | `console` | `False` | Enable and expose the web console (keyword-only) |
67
+ | `console_port` | `9001` | Container port serving the console (keyword-only) |
68
+ | `region_name` | `us-east-1` | Region reported to S3 clients (keyword-only) |
69
+
70
+ Any further keyword arguments are passed through to `DockerContainer`.
71
+
72
+ Credentials and region are always passed explicitly to the boto3 client, so your
73
+ `~/.aws/config` never influences test behaviour.
74
+
75
+ ## Development
76
+
77
+ ```bash
78
+ make install-dev
79
+ make test # lint + unit
80
+ make coverage
81
+ ```
82
+
83
+ Tests require a running Docker daemon.
@@ -0,0 +1,141 @@
1
+ [project]
2
+ name = "testcontainers-rustfs"
3
+ version = "1.0.0"
4
+ description = "Unofficial Testcontainers Python module for RustFS"
5
+ readme = "README.md"
6
+ requires-python = ">=3.14"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ classifiers = [
10
+ "Development Status :: 4 - Beta",
11
+ "Intended Audience :: Developers",
12
+ "Operating System :: OS Independent",
13
+ "Programming Language :: Python :: 3",
14
+ "Programming Language :: Python :: 3.14",
15
+ "Topic :: Software Development :: Testing",
16
+ "Typing :: Typed",
17
+ ]
18
+ dependencies = ["testcontainers>=4.15.0"]
19
+
20
+ [[project.authors]]
21
+ name = "Bence Molnár"
22
+ email = "developer@molnarbence.dev"
23
+
24
+ [project.optional-dependencies]
25
+ boto3 = ["boto3>=1.34"]
26
+
27
+ [project.urls]
28
+ Homepage = "https://github.com/mb-dot-dev/testcontainers-rustfs"
29
+ Repository = "https://github.com/mb-dot-dev/testcontainers-rustfs"
30
+ Issues = "https://github.com/mb-dot-dev/testcontainers-rustfs/issues"
31
+
32
+ [build-system]
33
+ requires = ["uv_build>=0.11.32,<0.12.0"]
34
+ build-backend = "uv_build"
35
+
36
+ [dependency-groups]
37
+ dev = [
38
+ "pytest>=8",
39
+ "pytest-cov>=7.1.0",
40
+ "ruff>=0.15.21",
41
+ "ty>=0.0.58",
42
+ "boto3>=1.34",
43
+ "boto3-stubs[s3]>=1.34",
44
+ ]
45
+
46
+ [tool.pytest.ini_options]
47
+ addopts = "-v"
48
+ testpaths = ["tests"]
49
+ python_files = [
50
+ "test_*.py",
51
+ "*_test.py",
52
+ ]
53
+
54
+ [tool.coverage.run]
55
+ branch = true
56
+ source = ["src"]
57
+ relative_files = true
58
+
59
+ [tool.coverage.report]
60
+ exclude_also = ["if TYPE_CHECKING:"]
61
+ fail_under = 75
62
+ precision = 2
63
+
64
+ [tool.coverage.xml]
65
+ output = "build/coverage.xml"
66
+
67
+ [tool.ruff]
68
+ line-length = 120
69
+ exclude = [
70
+ ".git",
71
+ "__pycache__",
72
+ ".venv",
73
+ "build",
74
+ "dist",
75
+ "*.egg-info",
76
+ ]
77
+
78
+ [tool.ruff.lint]
79
+ select = [
80
+ "A",
81
+ "ARG",
82
+ "ANN",
83
+ "ASYNC",
84
+ "B",
85
+ "BLE",
86
+ "FBT",
87
+ "C4",
88
+ "C90",
89
+ "DTZ",
90
+ "E",
91
+ "EM",
92
+ "F",
93
+ "G",
94
+ "FLY",
95
+ "I",
96
+ "ICN",
97
+ "N",
98
+ "PERF",
99
+ "PIE",
100
+ "PL",
101
+ "PT",
102
+ "PTH",
103
+ "RET",
104
+ "RUF",
105
+ "RSE",
106
+ "S",
107
+ "SIM",
108
+ "SLF001",
109
+ "SLOT",
110
+ "TCH",
111
+ "TID",
112
+ "TRY",
113
+ "T20",
114
+ "T100",
115
+ "UP",
116
+ "W",
117
+ ]
118
+
119
+ [tool.ruff.lint.per-file-ignores]
120
+ "tests/**/*.py" = [
121
+ "ARG001",
122
+ "PLR2004",
123
+ "PLC0415",
124
+ "S101",
125
+ "S105",
126
+ "S106",
127
+ "S107",
128
+ "T201",
129
+ ]
130
+
131
+ [tool.ruff.lint.isort]
132
+ force-sort-within-sections = true
133
+ split-on-trailing-comma = true
134
+
135
+ [tool.ruff.lint.pydocstyle]
136
+ convention = "pep257"
137
+
138
+ [tool.ruff.lint.flake8-quotes]
139
+ docstring-quotes = "double"
140
+ inline-quotes = "double"
141
+ multiline-quotes = "double"
@@ -0,0 +1,142 @@
1
+ [project]
2
+ name = "testcontainers-rustfs"
3
+ version = "1.0.0"
4
+ description = "Unofficial Testcontainers Python module for RustFS"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Bence Molnár", email = "developer@molnarbence.dev" }
8
+ ]
9
+ requires-python = ">=3.14"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "Intended Audience :: Developers",
15
+ "Operating System :: OS Independent",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.14",
18
+ "Topic :: Software Development :: Testing",
19
+ "Typing :: Typed",
20
+ ]
21
+ dependencies = [
22
+ "testcontainers>=4.15.0",
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ boto3 = ["boto3>=1.34"]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/mb-dot-dev/testcontainers-rustfs"
30
+ Repository = "https://github.com/mb-dot-dev/testcontainers-rustfs"
31
+ Issues = "https://github.com/mb-dot-dev/testcontainers-rustfs/issues"
32
+
33
+ [build-system]
34
+ requires = ["uv_build>=0.11.32,<0.12.0"]
35
+ build-backend = "uv_build"
36
+
37
+ [dependency-groups]
38
+ dev = [
39
+ "pytest>=8",
40
+ "pytest-cov>=7.1.0",
41
+ "ruff>=0.15.21",
42
+ "ty>=0.0.58",
43
+ "boto3>=1.34",
44
+ "boto3-stubs[s3]>=1.34",
45
+ ]
46
+
47
+ ##### TESTING #####
48
+
49
+ [tool.pytest.ini_options]
50
+ addopts = "-v"
51
+ testpaths = ["tests"]
52
+ python_files = ["test_*.py", "*_test.py"]
53
+
54
+ [tool.coverage.run]
55
+ branch = true
56
+ source = ["src"]
57
+ relative_files = true
58
+
59
+ [tool.coverage.report]
60
+ exclude_also = [
61
+ "if TYPE_CHECKING:", # imports / code here is executed during mypy tests.
62
+ ]
63
+ fail_under = 75
64
+ precision = 2
65
+
66
+ [tool.coverage.xml]
67
+ output = "build/coverage.xml"
68
+
69
+ #### LINTING ###
70
+
71
+ [tool.ruff]
72
+ # Set the maximum line length
73
+ line-length = 120
74
+ exclude = [".git", "__pycache__", ".venv", "build", "dist", "*.egg-info"]
75
+
76
+ [tool.ruff.lint]
77
+ # Enable these rule categories
78
+ select = [
79
+ "A", # flake8-builtins
80
+ "ARG", # flake8-unusued-arguments
81
+ "ANN", # flake8-annotations
82
+ "ASYNC", # flake8-async
83
+ "B", # flake8-bugbear
84
+ "BLE", # flake8-blind-except
85
+ "FBT", # flake8-boolean-trap
86
+ "C4", # flake8-comprehensions
87
+ "C90", # McCabe Complexity
88
+ "DTZ", # flake8-datetimez
89
+ "E", # pycodestyle
90
+ "EM", # flake8-errmsg
91
+ "F", # Pyflakes
92
+ "G", # flake8-logging-format
93
+ "FLY", # Flynt
94
+ "I", # isort
95
+ "ICN", # flake8-import-conventions
96
+ "N", # PEP8 Naming
97
+ "PERF", # Perflint
98
+ "PIE", # flake8-pie
99
+ "PL", # Pylint
100
+ "PT", # flake8-pytest-style
101
+ "PTH", # flake8-use-pathlib
102
+ "RET", # flake8-return
103
+ "RUF", # Ruff-specific
104
+ "RSE", # flake8-raise
105
+ "S", # flake8-bandit
106
+ "SIM", # flake8-simplify
107
+ "SLF001", # flake8-self private-member-access
108
+ "SLOT", # flake8-slots
109
+ "TCH", # flake8-typechecking
110
+ "TID", # flake8-tidy-imports
111
+ "TRY", # tryceratops
112
+ "T20", # flake8-print
113
+ "T100", # flake8-debugger
114
+ "UP", # pyupgrade
115
+ "W", # pycodestyle
116
+ ]
117
+
118
+ [tool.ruff.lint.per-file-ignores]
119
+ # Tests can have more flexible rules
120
+ "tests/**/*.py" = [
121
+ "ARG001", # Pytest fixtures appear as unused function arguments
122
+ "PLR2004", # Magic value used in comparison
123
+ "PLC0415", # Local imports inside test functions are a common pattern
124
+ "S101", # Use of assert
125
+ "S105",
126
+ "S106",
127
+ "S107",
128
+ "T201", # Print statements in tests
129
+ ]
130
+
131
+ [tool.ruff.lint.isort]
132
+ force-sort-within-sections = true
133
+ split-on-trailing-comma = true
134
+
135
+ [tool.ruff.lint.pydocstyle]
136
+ convention = "pep257"
137
+
138
+ [tool.ruff.lint.flake8-quotes]
139
+ # Use double quotes
140
+ docstring-quotes = "double"
141
+ inline-quotes = "double"
142
+ multiline-quotes = "double"
@@ -0,0 +1,124 @@
1
+ """Unofficial Testcontainers module for RustFS, an S3-compatible object store."""
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from testcontainers.core.container import DockerContainer
6
+ from testcontainers.core.wait_strategies import CompositeWaitStrategy, HttpWaitStrategy
7
+
8
+ if TYPE_CHECKING:
9
+ from mypy_boto3_s3.client import S3Client
10
+
11
+ __all__ = ["RustfsContainer"]
12
+
13
+ _DEFAULT_IMAGE = "rustfs/rustfs:1.0.0-beta.12"
14
+ _S3_HEALTH_PATH = "/health"
15
+ _CONSOLE_HEALTH_PATH = "/rustfs/console/health"
16
+
17
+
18
+ class RustfsContainer(DockerContainer):
19
+ """RustFS container exposing an S3-compatible API.
20
+
21
+ Example::
22
+
23
+ with RustfsContainer() as rustfs:
24
+ client = rustfs.get_client()
25
+ client.create_bucket(Bucket="testbucket")
26
+ client.put_object(Bucket="testbucket", Key="hello.txt", Body=b"Hello RustFS")
27
+ """
28
+
29
+ def __init__( # noqa: PLR0913
30
+ self,
31
+ image: str = _DEFAULT_IMAGE,
32
+ port: int = 9000,
33
+ access_key: str = "rustfsadmin",
34
+ secret_key: str = "rustfsadmin", # noqa: S107
35
+ *,
36
+ console: bool = False,
37
+ console_port: int = 9001,
38
+ region_name: str = "us-east-1",
39
+ **kwargs: Any, # noqa: ANN401
40
+ ) -> None:
41
+ """Create a RustFS container.
42
+
43
+ Args:
44
+ image: Docker image to run.
45
+ port: Container port serving the S3 API.
46
+ access_key: Access key for client connections.
47
+ secret_key: Secret key for client connections.
48
+ console: Whether to enable and expose the web console.
49
+ console_port: Container port serving the web console.
50
+ region_name: Region reported to S3 clients.
51
+ kwargs: Passed through to ``DockerContainer``.
52
+ """
53
+ wait_strategy = HttpWaitStrategy(port, _S3_HEALTH_PATH)
54
+ if console:
55
+ wait_strategy = CompositeWaitStrategy(
56
+ wait_strategy,
57
+ HttpWaitStrategy(console_port, _CONSOLE_HEALTH_PATH),
58
+ )
59
+ super().__init__(image, _wait_strategy=wait_strategy, **kwargs)
60
+
61
+ self.port = port
62
+ self.access_key = access_key
63
+ self.secret_key = secret_key
64
+ self.console = console
65
+ self.console_port = console_port
66
+ self.region_name = region_name
67
+
68
+ self.with_exposed_ports(self.port)
69
+ self.with_env("RUSTFS_ACCESS_KEY", self.access_key)
70
+ self.with_env("RUSTFS_SECRET_KEY", self.secret_key)
71
+ self.with_env("RUSTFS_ADDRESS", f":{self.port}")
72
+
73
+ if self.console:
74
+ self.with_exposed_ports(self.console_port)
75
+ self.with_env("RUSTFS_CONSOLE_ENABLE", "true")
76
+ self.with_env("RUSTFS_CONSOLE_ADDRESS", f":{self.console_port}")
77
+
78
+ def get_url(self) -> str:
79
+ """Return the S3 endpoint URL reachable from the host."""
80
+ return f"http://{self.get_container_host_ip()}:{self.get_exposed_port(self.port)}"
81
+
82
+ def get_console_url(self) -> str:
83
+ """Return the web console URL reachable from the host.
84
+
85
+ Raises:
86
+ RuntimeError: If the console was not enabled.
87
+ """
88
+ if not self.console:
89
+ msg = "The RustFS console is disabled; construct the container with RustfsContainer(console=True)."
90
+ raise RuntimeError(msg)
91
+ return f"http://{self.get_container_host_ip()}:{self.get_exposed_port(self.console_port)}"
92
+
93
+ def get_config(self) -> dict[str, str]:
94
+ """Return the connection settings for the container."""
95
+ host_ip = self.get_container_host_ip()
96
+ exposed_port = self.get_exposed_port(self.port)
97
+ return {
98
+ "endpoint": f"{host_ip}:{exposed_port}",
99
+ "endpoint_url": f"http://{host_ip}:{exposed_port}",
100
+ "access_key": self.access_key,
101
+ "secret_key": self.secret_key,
102
+ "region_name": self.region_name,
103
+ }
104
+
105
+ def get_client(self, **kwargs: Any) -> "S3Client": # noqa: ANN401, UP037
106
+ """Return a boto3 S3 client bound to this container.
107
+
108
+ Raises:
109
+ RuntimeError: If the optional boto3 dependency is not installed.
110
+ """
111
+ try:
112
+ import boto3 # noqa: PLC0415
113
+ except ImportError as exc:
114
+ msg = "boto3 is required by get_client(); install it with: pip install 'testcontainers-rustfs[boto3]'"
115
+ raise RuntimeError(msg) from exc
116
+
117
+ return boto3.client(
118
+ "s3",
119
+ endpoint_url=self.get_url(),
120
+ aws_access_key_id=self.access_key,
121
+ aws_secret_access_key=self.secret_key,
122
+ region_name=self.region_name,
123
+ **kwargs,
124
+ )