portforward 0.6.2__tar.gz → 0.7.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.

Potentially problematic release.


This version of portforward might be problematic. Click here for more details.

Files changed (37) hide show
  1. {portforward-0.6.2 → portforward-0.7.0}/Cargo.lock +1 -1
  2. {portforward-0.6.2 → portforward-0.7.0}/Cargo.toml +1 -1
  3. {portforward-0.6.2 → portforward-0.7.0}/HISTORY.rst +4 -0
  4. {portforward-0.6.2 → portforward-0.7.0}/PKG-INFO +3 -3
  5. {portforward-0.6.2 → portforward-0.7.0}/pyproject.toml +2 -2
  6. {portforward-0.6.2 → portforward-0.7.0}/python/portforward/__init__.py +10 -4
  7. {portforward-0.6.2 → portforward-0.7.0}/src/portforward.rs +5 -3
  8. {portforward-0.6.2 → portforward-0.7.0}/tests/test_portforward.py +27 -0
  9. {portforward-0.6.2 → portforward-0.7.0}/.editorconfig +0 -0
  10. {portforward-0.6.2 → portforward-0.7.0}/.github/ISSUE_TEMPLATE.md +0 -0
  11. {portforward-0.6.2 → portforward-0.7.0}/.github/workflows/python-app.yml +0 -0
  12. {portforward-0.6.2 → portforward-0.7.0}/.github/workflows/release.yml +0 -0
  13. {portforward-0.6.2 → portforward-0.7.0}/.gitignore +0 -0
  14. {portforward-0.6.2 → portforward-0.7.0}/.readthedocs.yml +0 -0
  15. {portforward-0.6.2 → portforward-0.7.0}/AUTHORS.rst +0 -0
  16. {portforward-0.6.2 → portforward-0.7.0}/CONTRIBUTING.rst +0 -0
  17. {portforward-0.6.2 → portforward-0.7.0}/LICENSE +0 -0
  18. {portforward-0.6.2 → portforward-0.7.0}/Makefile +0 -0
  19. {portforward-0.6.2 → portforward-0.7.0}/README.rst +0 -0
  20. {portforward-0.6.2 → portforward-0.7.0}/docs/Makefile +0 -0
  21. {portforward-0.6.2 → portforward-0.7.0}/docs/authors.rst +0 -0
  22. {portforward-0.6.2 → portforward-0.7.0}/docs/conf.py +0 -0
  23. {portforward-0.6.2 → portforward-0.7.0}/docs/contributing.rst +0 -0
  24. {portforward-0.6.2 → portforward-0.7.0}/docs/docs/conf.rst +0 -0
  25. {portforward-0.6.2 → portforward-0.7.0}/docs/docs/modules.rst +0 -0
  26. {portforward-0.6.2 → portforward-0.7.0}/docs/history.rst +0 -0
  27. {portforward-0.6.2 → portforward-0.7.0}/docs/index.rst +0 -0
  28. {portforward-0.6.2 → portforward-0.7.0}/docs/installation.rst +0 -0
  29. {portforward-0.6.2 → portforward-0.7.0}/docs/make.bat +0 -0
  30. {portforward-0.6.2 → portforward-0.7.0}/docs/modules.rst +0 -0
  31. {portforward-0.6.2 → portforward-0.7.0}/docs/portforward.rst +0 -0
  32. {portforward-0.6.2 → portforward-0.7.0}/python/portforward/_portforward.pyi +0 -0
  33. {portforward-0.6.2 → portforward-0.7.0}/python/portforward/py.typed +0 -0
  34. {portforward-0.6.2 → portforward-0.7.0}/requirements-dev.txt +0 -0
  35. {portforward-0.6.2 → portforward-0.7.0}/src/lib.rs +0 -0
  36. {portforward-0.6.2 → portforward-0.7.0}/tests/conftest.py +0 -0
  37. {portforward-0.6.2 → portforward-0.7.0}/tests/resources.yaml +0 -0
@@ -1142,7 +1142,7 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
1142
1142
 
1143
1143
  [[package]]
1144
1144
  name = "portforward"
1145
- version = "0.6.2"
1145
+ version = "0.7.0"
1146
1146
  dependencies = [
1147
1147
  "anyhow",
1148
1148
  "env_logger",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "portforward"
3
- version = "0.6.2"
3
+ version = "0.7.0"
4
4
  edition = "2021"
5
5
 
6
6
  # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -2,6 +2,10 @@
2
2
  History
3
3
  =======
4
4
 
5
+ 0.7.0 (2024-10-18)
6
+ ------------------
7
+ * Allow binding to a local random free port
8
+
5
9
  0.6.2 (2024-06-19)
6
10
  ------------------
7
11
  * Allow defining binding ip
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: portforward
3
- Version: 0.6.2
3
+ Version: 0.7.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -18,9 +18,9 @@ Author-email: Sebastian Ziemann <corka149@mailbox.org>
18
18
  License: MIT License
19
19
  Requires-Python: >=3.7
20
20
  Description-Content-Type: text/x-rst; charset=UTF-8
21
- Project-URL: Repository, https://github.com/pytogo/portforward.git
22
- Project-URL: Changelog, https://github.com/pytogo/portforward/blob/main/HISTORY.rst
23
21
  Project-URL: Documentation, https://portforward.readthedocs.io
22
+ Project-URL: Changelog, https://github.com/pytogo/portforward/blob/main/HISTORY.rst
23
+ Project-URL: Repository, https://github.com/pytogo/portforward.git
24
24
 
25
25
  ===========
26
26
  portforward
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "portforward"
7
- version = "0.6.2"
7
+ version = "0.7.0"
8
8
  authors = [{ name = "Sebastian Ziemann", email = "corka149@mailbox.org" }]
9
9
  description = "Easy Kubernetes Port-Forward For Python"
10
10
  readme = "README.rst"
@@ -34,7 +34,7 @@ module-name = "portforward._portforward"
34
34
  python-source = "python"
35
35
 
36
36
  [tool.bumpversion]
37
- current_version = "0.6.2"
37
+ current_version = "0.7.0"
38
38
  tag = true
39
39
  commit = true
40
40
 
@@ -2,7 +2,7 @@
2
2
  Easy Kubernetes Port-Forward For Python
3
3
  """
4
4
 
5
- __version__ = "0.6.2"
5
+ __version__ = "0.7.0"
6
6
 
7
7
  import asyncio
8
8
  import contextlib
@@ -57,7 +57,7 @@ def forward(
57
57
 
58
58
  :param namespace: Target namespace
59
59
  :param pod_or_service: Name of target Pod or service
60
- :param from_port: Local port
60
+ :param from_port: Local port, or 0 to use any free port
61
61
  :param to_port: Port inside the pod
62
62
  :param config_path: Path for loading kube config
63
63
  :param waiting: Delay in seconds
@@ -129,6 +129,11 @@ class PortForwarder:
129
129
  def is_stopped(self):
130
130
  return self._async_forwarder.is_stopped
131
131
 
132
+ @property
133
+ def from_port(self):
134
+ """The local port that was actually used for the portforward."""
135
+ return self._async_forwarder.from_port
136
+
132
137
 
133
138
  class AsyncPortForwarder:
134
139
  """Use the same args as the `portforward.forward` method."""
@@ -158,11 +163,12 @@ class AsyncPortForwarder:
158
163
  bind_ip = _validate_ip_address(bind_ip)
159
164
 
160
165
  self.actual_pod_name: str = ""
166
+ self.from_port: int = 0
161
167
  self._is_stopped: bool = False
162
168
  self.bind_address: str = f"{bind_ip}:{from_port}"
163
169
 
164
170
  async def forward(self):
165
- self.actual_pod_name = await _portforward.forward(
171
+ (self.actual_pod_name, self.from_port) = await _portforward.forward(
166
172
  self.namespace,
167
173
  self.pod_or_service,
168
174
  self.bind_address,
@@ -200,7 +206,7 @@ def _validate_str(arg_name, arg) -> str:
200
206
 
201
207
 
202
208
  def _validate_port(arg_name, arg) -> int:
203
- in_range = arg and 0 < arg < 65536
209
+ in_range = arg is not None and 0 <= arg < 65536
204
210
  if arg is None or not isinstance(arg, int) or not in_range:
205
211
  raise ValueError(f"{arg_name}={arg} is not a valid port")
206
212
 
@@ -34,9 +34,10 @@ pub struct ForwardConfig {
34
34
  kube_context: String,
35
35
  }
36
36
 
37
- /// Creates a connection to a pod. It returns the actual pod name for the portforward.
37
+ /// Creates a connection to a pod. It returns a `(pod_name, from_port)` tuple
38
+ /// with the actual pod name and local port used for the portforward.
38
39
  /// It differs from `pod_or_service` when `pod_or_service` represents a service.
39
- pub async fn forward(config: ForwardConfig) -> anyhow::Result<String> {
40
+ pub async fn forward(config: ForwardConfig) -> anyhow::Result<(String, u16)> {
40
41
  debug!("{:?}", config);
41
42
 
42
43
  let client_config = load_config(&config.config_path, &config.kube_context).await?;
@@ -58,6 +59,7 @@ pub async fn forward(config: ForwardConfig) -> anyhow::Result<String> {
58
59
 
59
60
  let addr = SocketAddr::from_str(&config.bind_address).with_context(move || config.bind_address)?;
60
61
  let tcp_listener = TcpListener::bind(addr).await?;
62
+ let from_port = tcp_listener.local_addr()?.port();
61
63
  let forward_task = setup_forward_task(
62
64
  tcp_listener,
63
65
  rx,
@@ -68,7 +70,7 @@ pub async fn forward(config: ForwardConfig) -> anyhow::Result<String> {
68
70
 
69
71
  tokio::spawn(forward_task);
70
72
 
71
- return Ok(q_name.pod_name);
73
+ return Ok((q_name.pod_name, from_port));
72
74
  }
73
75
 
74
76
  async fn load_config(
@@ -124,6 +124,33 @@ def test_service_portforward_with_success(kind_cluster: KindCluster):
124
124
  response: requests.Response = requests.get(url_2)
125
125
  pytest.fail("Portforward should be closed after leaving the context manager")
126
126
 
127
+ def test_portforward_from_port_zero_assigns_port(kind_cluster: KindCluster):
128
+ # Arrange
129
+ _create_test_resources(kind_cluster)
130
+
131
+ pod_name = "test-pod"
132
+ config = str(kind_cluster.kubeconfig_path.absolute())
133
+
134
+ local_port = 0 # from port
135
+ pod_port = 3000 # to port
136
+
137
+ pf = portforward.forward(
138
+ TEST_NAMESPACE,
139
+ pod_name,
140
+ local_port,
141
+ pod_port,
142
+ config_path=config,
143
+ kube_context=TEST_CONTEXT,
144
+ )
145
+
146
+ # Act & Assert
147
+ with pf as forwarder:
148
+ assert not forwarder.is_stopped()
149
+ assert forwarder.from_port != 0
150
+ url = f"http://localhost:{forwarder.from_port}/ping"
151
+ response: requests.Response = requests.get(url)
152
+ assert response.status_code == 200
153
+
127
154
 
128
155
  @pytest.mark.parametrize(
129
156
  "namespace,pod,from_port,to_port",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes