envoy-server 1.36.2.post1__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) CurioSwitch (oss@curioswitch.org)
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,64 @@
1
+ Metadata-Version: 2.4
2
+ Name: envoy-server
3
+ Version: 1.36.2.post1
4
+ Summary: A Python wheel distribution of the Envoy server
5
+ Keywords: envoy
6
+ Author: CurioSwitch
7
+ License-File: LICENSE
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: MacOS :: MacOS X
13
+ Classifier: Operating System :: Microsoft :: Windows
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Internet :: Proxy Servers
23
+ Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
24
+ Classifier: Topic :: System :: Networking
25
+ Requires-Python: >=3.10
26
+ Project-URL: Changelog, https://github.com/curioswitch/py-envoy-server/releases
27
+ Project-URL: Homepage, https://github.com/curioswitch/py-envoy-server
28
+ Project-URL: Issues, https://github.com/curioswitch/py-envoy-server/issues
29
+ Project-URL: Repository, https://github.com/curioswitch/py-envoy-server.git
30
+ Description-Content-Type: text/markdown
31
+
32
+ # envoy-server
33
+
34
+ A Python package containing a runnable [Envoy](https://github.com/envoyproxy/envoy) command.
35
+
36
+ On platforms supported natively by Envoy, typically glibc Linux or macOS on arm64, the package
37
+ embeds the Envoy binary itself and runs it directly. On other platforms such as Windows, it runs
38
+ the official [Envoy docker image](https://hub.docker.com/r/envoyproxy/envoy) - Docker must be installed
39
+ to run. The Docker fallback is primarily meant for non-production usage, for example when your
40
+ project runs Envoy on Linux in production but should still be runnable on a Windows developer
41
+ machine.
42
+
43
+ ## Usage
44
+
45
+ ```bash
46
+ uv add envoy-server # or pip install
47
+ ```
48
+
49
+ The package defines a script named `envoy` which will be available on the `PATH` as normal and can
50
+ then be run as you need.
51
+
52
+ ```bash
53
+ uv run envoy --version # or just envoy if in the system Python or an activated virtualenv
54
+ ```
55
+
56
+ The path to the actual binary can be found with `get_envoy_path` for use with e.g., `subprocess` in Python code.
57
+
58
+ ```python
59
+ import subprocess
60
+
61
+ from envoy import get_envoy_path
62
+
63
+ subprocess.run([get_envoy_path(), "--version"], check=True)
64
+ ```
@@ -0,0 +1,33 @@
1
+ # envoy-server
2
+
3
+ A Python package containing a runnable [Envoy](https://github.com/envoyproxy/envoy) command.
4
+
5
+ On platforms supported natively by Envoy, typically glibc Linux or macOS on arm64, the package
6
+ embeds the Envoy binary itself and runs it directly. On other platforms such as Windows, it runs
7
+ the official [Envoy docker image](https://hub.docker.com/r/envoyproxy/envoy) - Docker must be installed
8
+ to run. The Docker fallback is primarily meant for non-production usage, for example when your
9
+ project runs Envoy on Linux in production but should still be runnable on a Windows developer
10
+ machine.
11
+
12
+ ## Usage
13
+
14
+ ```bash
15
+ uv add envoy-server # or pip install
16
+ ```
17
+
18
+ The package defines a script named `envoy` which will be available on the `PATH` as normal and can
19
+ then be run as you need.
20
+
21
+ ```bash
22
+ uv run envoy --version # or just envoy if in the system Python or an activated virtualenv
23
+ ```
24
+
25
+ The path to the actual binary can be found with `get_envoy_path` for use with e.g., `subprocess` in Python code.
26
+
27
+ ```python
28
+ import subprocess
29
+
30
+ from envoy import get_envoy_path
31
+
32
+ subprocess.run([get_envoy_path(), "--version"], check=True)
33
+ ```
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+ __all__ = ["get_envoy_path"]
4
+
5
+ from ._envoy import get_envoy_path
File without changes
@@ -0,0 +1,105 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import os
5
+ import shutil
6
+ from importlib import metadata
7
+ from pathlib import Path
8
+
9
+
10
+ class EnvoyArgs:
11
+ """Subset of Envoy arguments pointing to filesystem paths we need to mount in Docker."""
12
+
13
+ config_path: str
14
+ admin_address_path: str
15
+ base_id_path: str
16
+ log_path: str
17
+ socket_path: str
18
+
19
+
20
+ def run_with_docker() -> None:
21
+ """Runs Envoy using Docker, for platforms not natively supported such as Windows.
22
+
23
+ This is meant to allow executing Envoy, not to isolate it, so we keep networking
24
+ simplest by using host networking without port mapping and mounting any referenced
25
+ paths rw.
26
+ """
27
+
28
+ docker_path = shutil.which("docker")
29
+ if not docker_path:
30
+ msg = (
31
+ "This platform requires Docker to run Envoy, but Docker could not be found. "
32
+ "Ensure it is installed and available."
33
+ )
34
+ raise RuntimeError(msg)
35
+
36
+ parser = argparse.ArgumentParser()
37
+ parser.add_argument("-c", "--config-path", type=str, default="")
38
+ parser.add_argument("--admin-address-path", type=str, default="")
39
+ parser.add_argument("--base-id-path", type=str, default="")
40
+ parser.add_argument("--log-path", type=str, default="")
41
+ parser.add_argument("--socket-path", type=str, default="")
42
+
43
+ volume_mounts: list[str] = []
44
+
45
+ paths, envoy_args = parser.parse_known_args(namespace=EnvoyArgs())
46
+ _handle_path(
47
+ "admin-address-path", paths.admin_address_path, volume_mounts, envoy_args
48
+ )
49
+ _handle_path("base-id-path", paths.base_id_path, volume_mounts, envoy_args)
50
+ _handle_path("config-path", paths.config_path, volume_mounts, envoy_args)
51
+ _handle_path("log-path", paths.log_path, volume_mounts, envoy_args)
52
+ _handle_path("socket-path", paths.socket_path, volume_mounts, envoy_args)
53
+
54
+ version = metadata.version("envoy-server")
55
+ if (post_idx := version.find(".post")) >= 0:
56
+ version = version[:post_idx]
57
+
58
+ docker_cmd = [
59
+ "docker",
60
+ "run",
61
+ "--rm",
62
+ "--network",
63
+ "host",
64
+ *volume_mounts,
65
+ f"envoyproxy/envoy:distroless-v{version}",
66
+ *envoy_args,
67
+ ]
68
+ os.execv(docker_path, docker_cmd) # noqa: S606
69
+
70
+
71
+ def _handle_path(
72
+ arg_name: str, path_str: str | None, volume_mounts: list[str], args: list[str]
73
+ ) -> None:
74
+ if not path_str:
75
+ return
76
+
77
+ path = Path(path_str).resolve()
78
+
79
+ # All of these should be files but it doesn't hurt to handle dir.
80
+ parent_dir = path if path.is_dir() else path.parent
81
+
82
+ if os.sep == "/":
83
+ # Unix-like, we can use the same path inside Docker.
84
+ args.extend([f"--{arg_name}", str(path)])
85
+ volume_mounts.append(f"-v{parent_dir}:{parent_dir}:rw")
86
+ else:
87
+ # Windows, we need to convert to /c/ style path.
88
+ # parent_dir.drive is 'C:', 'D:', etc. - always a string ending in exactly one colon
89
+ drive_letter = parent_dir.drive[:-1].lower()
90
+ # Skip the drive and convert
91
+ rel_parts = parent_dir.parts[1:]
92
+ wsl_dir = (
93
+ f"/mnt/{drive_letter}/{'/'.join(rel_parts)}"
94
+ if rel_parts
95
+ else f"/mnt/{drive_letter}"
96
+ )
97
+
98
+ docker_path = wsl_dir if path.is_dir() else f"{wsl_dir}/{path.name}"
99
+
100
+ args.extend([f"--{arg_name}", docker_path])
101
+ # It should be fine using the wsl directory corresponding to the Windows folder
102
+ # for the host side to support vanilla docker. Docker Desktop would also allow
103
+ # using native paths, and while it may be commonly used, we can't really use it
104
+ # in CI - this should work with either.
105
+ volume_mounts.append(f"-v{wsl_dir}:{wsl_dir}:rw")
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+
6
+ def get_envoy_path() -> Path:
7
+ return Path(__file__).parent / "_bin" / "envoy"
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import sys
5
+
6
+ from ._docker import run_with_docker
7
+ from ._envoy import get_envoy_path
8
+
9
+
10
+ def main() -> None:
11
+ envoy = get_envoy_path()
12
+ if not envoy.exists() or os.environ.get("ENVOY_SERVER_USE_DOCKER") == "true":
13
+ run_with_docker()
14
+ return
15
+ os.execv(envoy, sys.argv) # noqa: S606
16
+
17
+
18
+ if __name__ == "__main__":
19
+ main()
@@ -0,0 +1,186 @@
1
+ [project]
2
+ name = "envoy-server"
3
+ version = "1.36.2.post1"
4
+ description = "A Python wheel distribution of the Envoy server"
5
+ authors = [{ name = "CurioSwitch" }]
6
+ readme = "README.md"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.10"
9
+ keywords = ["envoy"]
10
+ classifiers = [
11
+ "Development Status :: 5 - Production/Stable",
12
+ "Environment :: Console",
13
+ "Intended Audience :: Developers",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Operating System :: MacOS :: MacOS X",
16
+ "Operating System :: Microsoft :: Windows",
17
+ "Operating System :: POSIX :: Linux",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3 :: Only",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
+ "Topic :: Internet :: Proxy Servers",
26
+ "Topic :: Internet :: WWW/HTTP :: HTTP Servers",
27
+ "Topic :: System :: Networking",
28
+ ]
29
+
30
+ [dependency-groups]
31
+ dev = [
32
+ "httpx",
33
+ "poethepoet",
34
+ "pyright[nodejs]",
35
+ "pytest",
36
+ "ruff",
37
+ "toml",
38
+ "wheel",
39
+ ]
40
+
41
+ [project.urls]
42
+ Homepage = "https://github.com/curioswitch/py-envoy-server"
43
+ Repository = "https://github.com/curioswitch/py-envoy-server.git"
44
+ Issues = "https://github.com/curioswitch/py-envoy-server/issues"
45
+ Changelog = "https://github.com/curioswitch/py-envoy-server/releases"
46
+
47
+
48
+ [project.scripts]
49
+ envoy = "envoy._main:main"
50
+
51
+ [build-system]
52
+ requires = ["uv_build>=0.8.13,<0.9.0"]
53
+ build-backend = "uv_build"
54
+
55
+ [tool.uv.build-backend]
56
+ module-name = "envoy"
57
+ module-root = ""
58
+
59
+ [tool.ruff.format]
60
+ skip-magic-trailing-comma = true
61
+ docstring-code-format = true
62
+
63
+ [tool.ruff.lint]
64
+ extend-select = [
65
+ # Same order as listed on https://docs.astral.sh/ruff/rules/
66
+ "YTT",
67
+ "ANN",
68
+ "ASYNC",
69
+ "S",
70
+ "FBT",
71
+ "B",
72
+ "A",
73
+ "COM818", # Other comma rules are handled by formatting
74
+ "C4",
75
+ "DTZ",
76
+ "T10",
77
+ "EM",
78
+ "EXE",
79
+ "FA",
80
+ "ISC",
81
+ "ICN",
82
+ "LOG",
83
+ "G",
84
+ "INP",
85
+ "PIE",
86
+ "T20",
87
+ "PYI",
88
+ "PT",
89
+ "Q004", # Other quote rules are handled by formatting
90
+ "RSE",
91
+ "RET",
92
+ # This rule is a bit strict since accessing private members within this package can be
93
+ # useful to reduce public API exposure. But it is important to not access private members
94
+ # of dependencies like httpx so we enable it and ignore the locations where we need to.
95
+ "SLF",
96
+ "SIM",
97
+ "SLOT",
98
+ "TID",
99
+ # TODO: Update TODOs then enable
100
+ # "TD",
101
+ "TC",
102
+ "ARG",
103
+ "PTH",
104
+ "FLY",
105
+ "I",
106
+ "N",
107
+ "PERF",
108
+ "E",
109
+ "W",
110
+ # TODO: Flesh out docs and enable
111
+ # "DOC"
112
+ # "D",
113
+ "F",
114
+ "PGH",
115
+ "PLC",
116
+ "PLE",
117
+ "PLW",
118
+ "UP",
119
+ "FURB",
120
+ "RUF",
121
+ "TRY",
122
+ ]
123
+
124
+ # Document reasons for ignoring specific linting errors
125
+ extend-ignore = [
126
+ # Not applicable
127
+ "AIR",
128
+ # Dangerous false positives https://github.com/astral-sh/ruff/issues/4845
129
+ "ERA",
130
+ # Not Applicable
131
+ "FAST",
132
+ # Important to call user callbacks safely
133
+ "BLE",
134
+ # stdlib includes a module named code. This is less of an issue since users need to import a module so allow it
135
+ "A005",
136
+ # TODO: Consider using copyright headers
137
+ "CPY",
138
+ # Not Applicable
139
+ "DJ",
140
+ # It's fine to have TODOs
141
+ "FIX",
142
+ # Not Applicable
143
+ "INT",
144
+ # Even prevents pytest.raises around an iteration which is too strict
145
+ "PT012",
146
+ # Triggers for protocol implementations that don't need the arg too
147
+ "ARG002",
148
+ # Complexity checks usually reduce readability
149
+ "C90",
150
+ # Not Applicable
151
+ "NPY",
152
+ # Not Applicable
153
+ "PD",
154
+ # We use the Exception suffix instead
155
+ "N818",
156
+ # Handled by formatting
157
+ "E111",
158
+ "E114",
159
+ "E117",
160
+ "E501",
161
+ "W191",
162
+ # Low signal-to-noise ratio
163
+ "PLR",
164
+ ]
165
+
166
+ typing-extensions = false
167
+
168
+ [tool.ruff.lint.per-file-ignores]
169
+ "scripts/**.py" = ["S603", "S607", "T201"]
170
+ "**/test_*.py" = [
171
+ "ANN",
172
+ "S101",
173
+ "S603",
174
+ "S607",
175
+ "FBT",
176
+ "EM",
177
+ "INP",
178
+ "SLF",
179
+ "PERF",
180
+ "D",
181
+ ]
182
+
183
+
184
+ [tool.ruff.lint.isort]
185
+ required-imports = ["from __future__ import annotations"]
186
+ split-on-trailing-comma = false