diff --git a/panel/io/location.py b/panel/io/location.py index 0fcf978f3e..c895897abc 100644 --- a/panel/io/location.py +++ b/panel/io/location.py @@ -25,6 +25,46 @@ from bokeh.server.contexts import BokehSessionContext from pyviz_comms import Comm +def _get_location_params(protocol: str|None, host: str| None, uri: str| None)->dict: + params = {} + href = '' + if protocol: + params['protocol'] = href = f'{protocol}:' + if host: + if host.startswith("::ffff:"): + host = host.replace("::ffff:", "") + + href += f'//{host}' + if ':' in host: + params['hostname'], params['port'] = host.split(':') + else: + params['hostname'] = host + if uri: + search = hash = None + + if uri.startswith("https,"): + uri = uri.replace("https,", "") + + if uri.startswith("http"): + uri = urlparse.urlparse(uri).path + + href += uri + if '?' in uri and '#' in uri: + params['pathname'], query = uri.split('?') + search, hash = query.split('#') + elif '?' in uri: + params['pathname'], search = uri.split('?') + elif '#' in uri: + params['pathname'], hash = uri.split('#') + else: + params['pathname'] = uri + if search: + params['search'] = f'?{search}' + if hash: + params['hash'] = f'#{hash}' + params['href'] = href + return params + class Location(Syncable): """ The Location component can be made available in a server context @@ -70,33 +110,7 @@ def from_request(cls, request): except ImportError: return cls() - params = {} - href = '' - if request.protocol: - params['protocol'] = href = f'{request.protocol}:' - if request.host: - href += f'//{request.host}' - if ':' in request.host: - params['hostname'], params['port'] = request.host.split(':') - else: - params['hostname'] = request.host - if request.uri: - search = hash = None - href += request.uri - if '?' in request.uri and '#' in request.uri: - params['pathname'], query = request.uri.split('?') - search, hash = query.split('#') - elif '?' in request.uri: - params['pathname'], search = request.uri.split('?') - elif '#' in request.uri: - params['pathname'], hash = request.uri.split('#') - else: - params['pathname'] = request.uri - if search: - params['search'] = f'?{search}' - if hash: - params['hash'] = f'#{hash}' - params['href'] = href + params = _get_location_params(request.protocol, request.host, request.uri) loc = cls() with edit_readonly(loc): loc.param.update(params) diff --git a/panel/tests/io/test_location.py b/panel/tests/io/test_location.py index c7106a726e..ddaed0f4e6 100644 --- a/panel/tests/io/test_location.py +++ b/panel/tests/io/test_location.py @@ -2,7 +2,7 @@ import param import pytest -from panel.io.location import Location +from panel.io.location import Location, _get_location_params from panel.io.state import state from panel.tests.util import serve_and_request, wait_until from panel.util import edit_readonly @@ -188,3 +188,20 @@ def test_location_sync_to_dataframe_with_initial_value(location, dataframe): location.search = "?dataframe=%5B%7B%22x%22%3A+1%7D%5D" location.sync(p) pd.testing.assert_frame_equal(p.dataframe, dataframe) + +@pytest.mark.parametrize(("protocol", "host", "uri", "expected"), [ + # Started with the command fastapi dev script.py on local laptop + ( + "http", "127.0.0.1", "/panel", + {'protocol': 'http:', 'hostname': '127.0.0.1', 'pathname': '/panel', 'href': 'http://127.0.0.1/panel'} + ), + # Started with the command fastapi dev script.py --root-path /some/path in VS Code terminal on JupyterHub + ( + "http", "::ffff:172.20.0.233", "https,http://sub.domain.dk/some/path/panel", + # I believe the below should be the result. But do not know for sure + {"protocol": "http:", "hostname": "172.20.0.233", "pathname": "/some/path/panel", 'href': 'http://172.20.0.233/some/path/panel'} + ) +]) +def test_get_location_params(protocol, host, uri, expected): + params = _get_location_params(protocol, host, uri) + assert params==expected