Skip to content

Commit 9fdb4f1

Browse files
authored
[Corehttp] Changelog update (#45113)
- Update changelog with new version - Add urljoin fix from core Signed-off-by: Paul Van Eck <paulvaneck@microsoft.com>
1 parent 4d09e4b commit 9fdb4f1

4 files changed

Lines changed: 70 additions & 6 deletions

File tree

sdk/core/corehttp/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Release History
22

3+
## 1.0.0b8 (Unreleased)
4+
5+
### Features Added
6+
7+
### Breaking Changes
8+
9+
### Bugs Fixed
10+
11+
- Fixed `PipelineClient.format_url` to avoid adding trailing slashes when the URL template contains only query parameters. #45113
12+
13+
### Other Changes
14+
315
## 1.0.0b7 (2026-02-05)
416

517
### Features Added

sdk/core/corehttp/corehttp/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@
99
# regenerated.
1010
# --------------------------------------------------------------------------
1111

12-
VERSION = "1.0.0b7"
12+
VERSION = "1.0.0b8"

sdk/core/corehttp/corehttp/runtime/_base.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,10 @@ def _urljoin(base_url: str, stub_url: str) -> str:
7474

7575
# Note that _replace is a public API named that way to avoid conflicts in namedtuple
7676
# https://docs.python.org/3/library/collections.html?highlight=namedtuple#collections.namedtuple
77-
parsed_base_url = parsed_base_url._replace(
78-
path=parsed_base_url.path.rstrip("/") + "/" + stub_url_path,
79-
)
77+
if stub_url_path:
78+
parsed_base_url = parsed_base_url._replace(
79+
path=parsed_base_url.path.rstrip("/") + "/" + stub_url_path.lstrip("/"),
80+
)
8081
if stub_url_query:
8182
query_params = [stub_url_query]
8283
if parsed_base_url.query:
@@ -108,7 +109,6 @@ def format_url(self, url_template: str, **kwargs: Any) -> str:
108109
if url:
109110
parsed = urlparse(url)
110111
if not parsed.scheme or not parsed.netloc:
111-
url = url.lstrip("/")
112112
try:
113113
base = self._endpoint.format(**kwargs).rstrip("/")
114114
except KeyError as key:

sdk/core/corehttp/tests/test_pipeline.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
RetryPolicy,
2323
HTTPPolicy,
2424
)
25-
from corehttp.runtime._base import PipelineClientBase, _format_url_section
25+
from corehttp.runtime._base import PipelineClientBase, _format_url_section, _urljoin
2626
from corehttp.transport import HttpTransport
2727
from corehttp.transport.requests import RequestsTransport
2828
from corehttp.transport.httpx import HttpXTransport
@@ -90,6 +90,25 @@ def test_transport_socket_timeout(transport):
9090
response = pipeline.run(request, connection_timeout=0.000001, read_timeout=0.000001)
9191

9292

93+
def test_url_join():
94+
assert _urljoin("devstoreaccount1", "?testdir") == "devstoreaccount1?testdir"
95+
assert _urljoin("devstoreaccount1", "?testdir=foo") == "devstoreaccount1?testdir=foo"
96+
assert _urljoin("devstoreaccount1/api", "?a=1") == "devstoreaccount1/api?a=1"
97+
assert (
98+
_urljoin("devstoreaccount1", "/?restype=service&comp=properties")
99+
== "devstoreaccount1/?restype=service&comp=properties"
100+
)
101+
assert _urljoin("devstoreaccount1", "") == "devstoreaccount1"
102+
assert _urljoin("devstoreaccount1", "testdir/") == "devstoreaccount1/testdir/"
103+
assert _urljoin("devstoreaccount1/", "") == "devstoreaccount1/"
104+
assert _urljoin("devstoreaccount1/", "/testdir/") == "devstoreaccount1/testdir/"
105+
assert _urljoin("devstoreaccount1/", "testdir/") == "devstoreaccount1/testdir/"
106+
assert _urljoin("devstoreaccount1?a=1", "testdir/") == "devstoreaccount1/testdir/?a=1"
107+
assert _urljoin("devstoreaccount1", "testdir/?b=2") == "devstoreaccount1/testdir/?b=2"
108+
assert _urljoin("devstoreaccount1?a=1", "testdir/?b=2") == "devstoreaccount1/testdir/?a=1&b=2"
109+
assert _urljoin("devstoreaccount1", "documentModels:build") == "devstoreaccount1/documentModels:build"
110+
111+
93112
def test_format_url_basic():
94113
client = PipelineClientBase("https://bing.com")
95114
formatted = client.format_url("/{foo}", foo="bar")
@@ -177,6 +196,39 @@ def test_format_incorrect_endpoint():
177196
)
178197

179198

199+
def test_format_url_query_strings():
200+
client = PipelineClientBase("https://foo.core.windows.net")
201+
formatted = client.format_url("/")
202+
assert formatted == "https://foo.core.windows.net/"
203+
204+
formatted = client.format_url("/?a=X&c=Y")
205+
assert formatted == "https://foo.core.windows.net/?a=X&c=Y"
206+
207+
formatted = client.format_url("?a=X&c=Y")
208+
assert formatted == "https://foo.core.windows.net?a=X&c=Y"
209+
210+
formatted = client.format_url("/Tables/?a=X&c=Y")
211+
assert formatted == "https://foo.core.windows.net/Tables/?a=X&c=Y"
212+
213+
formatted = client.format_url("/Tables?a=X&c=Y")
214+
assert formatted == "https://foo.core.windows.net/Tables?a=X&c=Y"
215+
216+
217+
def test_format_url_from_http_request():
218+
client = PipelineClientBase("https://foo.core.windows.net")
219+
220+
_url = "/"
221+
_params = {"foo": "bar"}
222+
request = HttpRequest("GET", _url, params=_params)
223+
formatted = client.format_url(request.url)
224+
assert formatted == "https://foo.core.windows.net/?foo=bar"
225+
226+
_url = "?restype=service&comp=properties"
227+
request = HttpRequest("GET", _url)
228+
formatted = client.format_url(request.url)
229+
assert formatted == "https://foo.core.windows.net?restype=service&comp=properties"
230+
231+
180232
def test_request_json():
181233

182234
data = "Lots of dataaaa"

0 commit comments

Comments
 (0)