url-normalize 2.0.1__tar.gz → 2.2.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.
Files changed (44) hide show
  1. {url_normalize-2.0.1 → url_normalize-2.2.0}/PKG-INFO +49 -4
  2. {url_normalize-2.0.1 → url_normalize-2.2.0}/README.md +48 -3
  3. {url_normalize-2.0.1 → url_normalize-2.2.0}/pyproject.toml +4 -1
  4. url_normalize-2.2.0/tests/test_cli.py +294 -0
  5. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_normalize_fragment.py +2 -0
  6. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_normalize_path.py +3 -1
  7. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_normalize_query.py +2 -0
  8. url_normalize-2.2.0/tests/test_provide_url_domain.py +31 -0
  9. url_normalize-2.2.0/tests/test_url_normalize.py +163 -0
  10. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/__init__.py +1 -1
  11. url_normalize-2.2.0/url_normalize/cli.py +73 -0
  12. url_normalize-2.2.0/url_normalize/normalize_fragment.py +27 -0
  13. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/normalize_path.py +4 -4
  14. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/normalize_query.py +2 -2
  15. url_normalize-2.2.0/url_normalize/provide_url_domain.py +28 -0
  16. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/provide_url_scheme.py +11 -4
  17. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/url_normalize.py +7 -2
  18. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize.egg-info/PKG-INFO +49 -4
  19. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize.egg-info/SOURCES.txt +5 -0
  20. url_normalize-2.2.0/url_normalize.egg-info/entry_points.txt +2 -0
  21. url_normalize-2.0.1/tests/test_url_normalize.py +0 -125
  22. url_normalize-2.0.1/url_normalize/normalize_fragment.py +0 -18
  23. {url_normalize-2.0.1 → url_normalize-2.2.0}/LICENSE +0 -0
  24. {url_normalize-2.0.1 → url_normalize-2.2.0}/setup.cfg +0 -0
  25. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_deconstruct_url.py +0 -0
  26. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_generic_url_cleanup.py +0 -0
  27. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_normalize_host.py +0 -0
  28. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_normalize_port.py +0 -0
  29. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_normalize_query_filters.py +0 -0
  30. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_normalize_scheme.py +0 -0
  31. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_normalize_userinfo.py +0 -0
  32. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_provide_url_scheme.py +0 -0
  33. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_reconstruct_url.py +0 -0
  34. {url_normalize-2.0.1 → url_normalize-2.2.0}/tests/test_tools.py +0 -0
  35. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/generic_url_cleanup.py +0 -0
  36. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/normalize_host.py +0 -0
  37. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/normalize_port.py +0 -0
  38. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/normalize_scheme.py +0 -0
  39. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/normalize_userinfo.py +0 -0
  40. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/param_allowlist.py +0 -0
  41. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize/tools.py +0 -0
  42. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize.egg-info/dependency_links.txt +0 -0
  43. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize.egg-info/requires.txt +0 -0
  44. {url_normalize-2.0.1 → url_normalize-2.2.0}/url_normalize.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: url-normalize
3
- Version: 2.0.1
3
+ Version: 2.2.0
4
4
  Summary: URL normalization for Python
5
5
  Author-email: Nikolay Panov <github@npanov.com>
6
6
  License: MIT
@@ -26,6 +26,9 @@ Dynamic: license-file
26
26
 
27
27
  # url-normalize
28
28
 
29
+ [![CI](https://github.com/niksite/url-normalize/actions/workflows/ci.yml/badge.svg)](https://github.com/niksite/url-normalize/actions/workflows/ci.yml)
30
+ [![PyPI](https://github.com/niksite/url-normalize/actions/workflows/publish.yml/badge.svg)](https://github.com/niksite/url-normalize/actions/workflows/publish.yml)
31
+
29
32
  URI Normalization function:
30
33
 
31
34
  * Take care of IDN domains.
@@ -47,6 +50,7 @@ Inspired by Sam Ruby's [urlnorm.py](<http://intertwingly.net/blog/2004/08/04/Url
47
50
 
48
51
  * IDN (Internationalized Domain Name) support
49
52
  * Configurable default scheme (https by default)
53
+ * Configurable default domain for absolute paths
50
54
  * Query parameter filtering with allowlists
51
55
  * Support for various URL formats including:
52
56
  * Empty string URLs
@@ -64,8 +68,6 @@ pip install url-normalize
64
68
 
65
69
  ## Usage
66
70
 
67
- Basic usage:
68
-
69
71
  ```python
70
72
  from url_normalize import url_normalize
71
73
 
@@ -81,19 +83,62 @@ print(url_normalize("www.foo.com/foo", default_scheme="http"))
81
83
  print(url_normalize("www.google.com/search?q=test&utm_source=test", filter_params=True))
82
84
  # Output: https://www.google.com/search?q=test
83
85
 
84
- # With custom parameter allowlist
86
+ # With custom parameter allowlist as a dict
85
87
  print(url_normalize(
86
88
  "example.com?page=1&id=123&ref=test",
87
89
  filter_params=True,
88
90
  param_allowlist={"example.com": ["page", "id"]}
89
91
  ))
90
92
  # Output: https://example.com?page=1&id=123
93
+
94
+ # With custom parameter allowlist as a list
91
95
  print(url_normalize(
92
96
  "example.com?page=1&id=123&ref=test",
93
97
  filter_params=True,
94
98
  param_allowlist=["page", "id"]
95
99
  ))
96
100
  # Output: https://example.com?page=1&id=123
101
+
102
+ # With default domain for absolute paths
103
+ print(url_normalize("/images/logo.png", default_domain="example.com"))
104
+ # Output: https://example.com/images/logo.png
105
+
106
+ # With default domain and custom scheme
107
+ print(url_normalize("/images/logo.png", default_scheme="http", default_domain="example.com"))
108
+ # Output: http://example.com/images/logo.png
109
+ ```
110
+
111
+ ### Command-line usage
112
+
113
+ You can also use `url-normalize` from the command line:
114
+
115
+ ```bash
116
+ $ url-normalize "www.foo.com:80/foo"
117
+ # Output: https://www.foo.com/foo
118
+
119
+ # With custom default scheme
120
+ $ url-normalize -s http "www.foo.com/foo"
121
+ # Output: http://www.foo.com/foo
122
+
123
+ # With query parameter filtering
124
+ $ url-normalize -f "www.google.com/search?q=test&utm_source=test"
125
+ # Output: https://www.google.com/search?q=test
126
+
127
+ # With custom allowlist
128
+ $ url-normalize -f -p page,id "example.com?page=1&id=123&ref=test"
129
+ # Output: https://example.com/?page=1&id=123
130
+
131
+ # With default domain for absolute paths
132
+ $ url-normalize -d example.com "/images/logo.png"
133
+ # Output: https://example.com/images/logo.png
134
+
135
+ # With default domain and custom scheme
136
+ $ url-normalize -d example.com -s http "/images/logo.png"
137
+ # Output: http://example.com/images/logo.png
138
+
139
+ # Via uv tool/uvx
140
+ $ uvx url-normalize www.foo.com:80/foo
141
+ # Output: https://www.foo.com:80/foo
97
142
  ```
98
143
 
99
144
  ## Documentation
@@ -1,5 +1,8 @@
1
1
  # url-normalize
2
2
 
3
+ [![CI](https://github.com/niksite/url-normalize/actions/workflows/ci.yml/badge.svg)](https://github.com/niksite/url-normalize/actions/workflows/ci.yml)
4
+ [![PyPI](https://github.com/niksite/url-normalize/actions/workflows/publish.yml/badge.svg)](https://github.com/niksite/url-normalize/actions/workflows/publish.yml)
5
+
3
6
  URI Normalization function:
4
7
 
5
8
  * Take care of IDN domains.
@@ -21,6 +24,7 @@ Inspired by Sam Ruby's [urlnorm.py](<http://intertwingly.net/blog/2004/08/04/Url
21
24
 
22
25
  * IDN (Internationalized Domain Name) support
23
26
  * Configurable default scheme (https by default)
27
+ * Configurable default domain for absolute paths
24
28
  * Query parameter filtering with allowlists
25
29
  * Support for various URL formats including:
26
30
  * Empty string URLs
@@ -38,8 +42,6 @@ pip install url-normalize
38
42
 
39
43
  ## Usage
40
44
 
41
- Basic usage:
42
-
43
45
  ```python
44
46
  from url_normalize import url_normalize
45
47
 
@@ -55,19 +57,62 @@ print(url_normalize("www.foo.com/foo", default_scheme="http"))
55
57
  print(url_normalize("www.google.com/search?q=test&utm_source=test", filter_params=True))
56
58
  # Output: https://www.google.com/search?q=test
57
59
 
58
- # With custom parameter allowlist
60
+ # With custom parameter allowlist as a dict
59
61
  print(url_normalize(
60
62
  "example.com?page=1&id=123&ref=test",
61
63
  filter_params=True,
62
64
  param_allowlist={"example.com": ["page", "id"]}
63
65
  ))
64
66
  # Output: https://example.com?page=1&id=123
67
+
68
+ # With custom parameter allowlist as a list
65
69
  print(url_normalize(
66
70
  "example.com?page=1&id=123&ref=test",
67
71
  filter_params=True,
68
72
  param_allowlist=["page", "id"]
69
73
  ))
70
74
  # Output: https://example.com?page=1&id=123
75
+
76
+ # With default domain for absolute paths
77
+ print(url_normalize("/images/logo.png", default_domain="example.com"))
78
+ # Output: https://example.com/images/logo.png
79
+
80
+ # With default domain and custom scheme
81
+ print(url_normalize("/images/logo.png", default_scheme="http", default_domain="example.com"))
82
+ # Output: http://example.com/images/logo.png
83
+ ```
84
+
85
+ ### Command-line usage
86
+
87
+ You can also use `url-normalize` from the command line:
88
+
89
+ ```bash
90
+ $ url-normalize "www.foo.com:80/foo"
91
+ # Output: https://www.foo.com/foo
92
+
93
+ # With custom default scheme
94
+ $ url-normalize -s http "www.foo.com/foo"
95
+ # Output: http://www.foo.com/foo
96
+
97
+ # With query parameter filtering
98
+ $ url-normalize -f "www.google.com/search?q=test&utm_source=test"
99
+ # Output: https://www.google.com/search?q=test
100
+
101
+ # With custom allowlist
102
+ $ url-normalize -f -p page,id "example.com?page=1&id=123&ref=test"
103
+ # Output: https://example.com/?page=1&id=123
104
+
105
+ # With default domain for absolute paths
106
+ $ url-normalize -d example.com "/images/logo.png"
107
+ # Output: https://example.com/images/logo.png
108
+
109
+ # With default domain and custom scheme
110
+ $ url-normalize -d example.com -s http "/images/logo.png"
111
+ # Output: http://example.com/images/logo.png
112
+
113
+ # Via uv tool/uvx
114
+ $ uvx url-normalize www.foo.com:80/foo
115
+ # Output: https://www.foo.com:80/foo
71
116
  ```
72
117
 
73
118
  ## Documentation
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "url-normalize"
3
- version = "2.0.1"
3
+ version = "2.2.0"
4
4
  description = "URL normalization for Python"
5
5
  authors = [{ name = "Nikolay Panov", email = "github@npanov.com" }]
6
6
  license = { text = "MIT" }
@@ -15,6 +15,9 @@ Repository = "https://github.com/niksite/url-normalize"
15
15
  Issues = "https://github.com/niksite/url-normalize/issues"
16
16
  Changelog = "https://github.com/niksite/url-normalize/blob/master/CHANGELOG.md"
17
17
 
18
+ [project.scripts]
19
+ url-normalize = "url_normalize.cli:main"
20
+
18
21
  [project.optional-dependencies]
19
22
  dev = [
20
23
  "mypy",
@@ -0,0 +1,294 @@
1
+ """Tests for the command line interface."""
2
+
3
+ import subprocess
4
+ import sys
5
+ from unittest.mock import patch
6
+
7
+ import pytest
8
+
9
+ from url_normalize import __version__
10
+ from url_normalize.cli import main
11
+
12
+
13
+ def run_cli(*args: str) -> subprocess.CompletedProcess:
14
+ """Run the CLI command with given arguments.
15
+
16
+ Params:
17
+ *args: Command line arguments to pass to the CLI.
18
+
19
+ Returns:
20
+ A completed process with stdout, stderr, and return code.
21
+
22
+ """
23
+ command = [sys.executable, "-m", "url_normalize.cli", *list(args)]
24
+ return subprocess.run( # noqa: S603
25
+ command, capture_output=True, text=True, check=False
26
+ )
27
+
28
+
29
+ def test_cli_error_handling(capsys, monkeypatch):
30
+ """Test CLI error handling when URL normalization fails."""
31
+ with patch("url_normalize.cli.url_normalize") as mock_normalize:
32
+ mock_normalize.side_effect = Exception("Simulated error")
33
+ monkeypatch.setattr("sys.argv", ["url-normalize", "http://example.com"])
34
+
35
+ with pytest.raises(SystemExit) as excinfo:
36
+ main()
37
+
38
+ assert excinfo.value.code == 1
39
+ captured = capsys.readouterr()
40
+ assert "Error normalizing URL: Simulated error" in captured.err
41
+ assert not captured.out
42
+
43
+
44
+ def test_cli_basic_normalization() -> None:
45
+ """Test basic URL normalization via CLI."""
46
+ url = "http://EXAMPLE.com/./path/../other/"
47
+ expected = "http://example.com/other/"
48
+
49
+ result = run_cli(url)
50
+
51
+ assert result.returncode == 0
52
+ assert result.stdout.strip() == expected
53
+ assert not result.stderr
54
+
55
+
56
+ def test_cli_basic_normalization_short_args() -> None:
57
+ """Test basic URL normalization via CLI using short arguments."""
58
+ url = "http://EXAMPLE.com/./path/../other/"
59
+ expected = "http://example.com/other/"
60
+ # Using short args where applicable (none for the URL itself)
61
+
62
+ result = run_cli(url) # No short args needed for basic case
63
+
64
+ assert result.returncode == 0
65
+ assert result.stdout.strip() == expected
66
+ assert not result.stderr
67
+
68
+
69
+ def test_cli_default_scheme() -> None:
70
+ """Test default scheme addition via CLI."""
71
+ url = "//example.com"
72
+ expected = "https://example.com/"
73
+
74
+ result = run_cli(url)
75
+
76
+ assert result.returncode == 0
77
+ assert result.stdout.strip() == expected
78
+ assert not result.stderr
79
+
80
+
81
+ def test_cli_default_scheme_short_arg() -> None:
82
+ """Test default scheme addition via CLI using short argument."""
83
+ url = "//example.com"
84
+ expected = "https://example.com/"
85
+
86
+ result = run_cli(url) # Default scheme is implicit, no arg needed
87
+
88
+ assert result.returncode == 0
89
+ assert result.stdout.strip() == expected
90
+ assert not result.stderr
91
+
92
+
93
+ def test_cli_custom_default_scheme() -> None:
94
+ """Test custom default scheme via CLI."""
95
+ url = "//example.com"
96
+ expected = "ftp://example.com/"
97
+
98
+ result = run_cli("--default-scheme", "ftp", url)
99
+
100
+ assert result.returncode == 0
101
+ assert result.stdout.strip() == expected
102
+ assert not result.stderr
103
+
104
+
105
+ def test_cli_custom_default_scheme_short_arg() -> None:
106
+ """Test custom default scheme via CLI using short argument."""
107
+ url = "//example.com"
108
+ expected = "ftp://example.com/"
109
+
110
+ result = run_cli("-s", "ftp", url)
111
+
112
+ assert result.returncode == 0
113
+ assert result.stdout.strip() == expected
114
+ assert not result.stderr
115
+
116
+
117
+ def test_cli_filter_params() -> None:
118
+ """Test parameter filtering via CLI."""
119
+ url = "http://google.com?utm_source=test&q=1"
120
+ expected = "http://google.com/?q=1"
121
+
122
+ result = run_cli("--filter-params", url)
123
+
124
+ assert result.returncode == 0
125
+ assert result.stdout.strip() == expected
126
+ assert not result.stderr
127
+
128
+
129
+ def test_cli_filter_params_short_arg() -> None:
130
+ """Test parameter filtering via CLI using short argument."""
131
+ url = "http://google.com?utm_source=test&q=1"
132
+ expected = "http://google.com/?q=1"
133
+
134
+ result = run_cli("-f", url)
135
+
136
+ assert result.returncode == 0
137
+ assert result.stdout.strip() == expected
138
+ assert not result.stderr
139
+
140
+
141
+ def test_cli_param_allowlist() -> None:
142
+ """Test parameter allowlist via CLI."""
143
+ url = "http://example.com?remove=me&keep=this&remove_too=true"
144
+ expected = "http://example.com/?keep=this"
145
+ # Use filter_params to enable filtering, then allowlist to keep specific ones
146
+
147
+ result = run_cli("-f", "-p", "keep", url)
148
+
149
+ assert result.returncode == 0
150
+ assert result.stdout.strip() == expected
151
+ assert not result.stderr
152
+
153
+
154
+ def test_cli_param_allowlist_multiple() -> None:
155
+ """Test parameter allowlist with multiple params via CLI."""
156
+ url = "http://example.com?remove=me&keep=this&keep_too=yes&remove_too=true"
157
+ expected = "http://example.com/?keep=this&keep_too=yes"
158
+
159
+ result = run_cli("-f", "-p", "keep,keep_too", url)
160
+
161
+ assert result.returncode == 0
162
+ assert result.stdout.strip() == expected
163
+ assert not result.stderr
164
+
165
+
166
+ def test_cli_param_allowlist_without_filtering() -> None:
167
+ """Test allowlist has no effect if filtering is not enabled."""
168
+ url = "http://example.com?remove=me&keep=this&remove_too=true"
169
+ expected = "http://example.com/?remove=me&keep=this&remove_too=true"
170
+ # Not using -f, so allowlist should be ignored
171
+
172
+ result = run_cli("-p", "keep", url)
173
+
174
+ assert result.returncode == 0
175
+ assert result.stdout.strip() == expected
176
+ assert not result.stderr
177
+
178
+
179
+ def test_cli_no_url() -> None:
180
+ """Test CLI error when no URL is provided."""
181
+ result = run_cli()
182
+
183
+ assert result.returncode != 0
184
+ assert "the following arguments are required: url" in result.stderr
185
+
186
+
187
+ def test_cli_version_long() -> None:
188
+ """Test version output with --version flag."""
189
+ result = run_cli("--version")
190
+
191
+ assert result.returncode == 0
192
+ assert __version__ in result.stdout
193
+ assert not result.stderr
194
+
195
+
196
+ def test_cli_version_short() -> None:
197
+ """Test version output with -v flag."""
198
+ result = run_cli("-v")
199
+
200
+ assert result.returncode == 0
201
+ assert __version__ in result.stdout
202
+ assert not result.stderr
203
+
204
+
205
+ @pytest.mark.skipif(
206
+ sys.platform == "win32", reason="Charset handling differs on Windows CLI"
207
+ )
208
+ def test_cli_charset() -> None:
209
+ """Test charset handling via CLI (might be platform-dependent)."""
210
+ # Example using Cyrillic characters which need correct encoding
211
+ url = "http://пример.рф/path"
212
+ expected_idn = "http://xn--e1afmkfd.xn--p1ai/path"
213
+
214
+ # Test with default UTF-8
215
+ result_utf8 = run_cli(url)
216
+
217
+ assert result_utf8.returncode == 0
218
+ assert result_utf8.stdout.strip() == expected_idn
219
+ assert not result_utf8.stderr
220
+
221
+ # Test specifying UTF-8 explicitly
222
+ result_charset = run_cli("--charset", "utf-8", url)
223
+
224
+ assert result_charset.returncode == 0
225
+ assert result_charset.stdout.strip() == expected_idn
226
+ assert not result_charset.stderr
227
+
228
+ # Test specifying UTF-8 explicitly using short arg
229
+ result_charset_short = run_cli("-c", "utf-8", url)
230
+
231
+ assert result_charset_short.returncode == 0
232
+ assert result_charset_short.stdout.strip() == expected_idn
233
+ assert not result_charset_short.stderr
234
+
235
+
236
+ def test_cli_default_domain() -> None:
237
+ """Test adding default domain to absolute path via CLI."""
238
+ url = "/path/to/image.png"
239
+ expected = "https://example.com/path/to/image.png"
240
+
241
+ result = run_cli("--default-domain", "example.com", url)
242
+
243
+ assert result.returncode == 0
244
+ assert result.stdout.strip() == expected
245
+ assert not result.stderr
246
+
247
+
248
+ def test_cli_default_domain_short_arg() -> None:
249
+ """Test adding default domain using short argument."""
250
+ url = "/path/to/image.png"
251
+ expected = "https://example.com/path/to/image.png"
252
+
253
+ result = run_cli("-d", "example.com", url)
254
+
255
+ assert result.returncode == 0
256
+ assert result.stdout.strip() == expected
257
+ assert not result.stderr
258
+
259
+
260
+ def test_cli_default_domain_with_scheme() -> None:
261
+ """Test adding default domain with custom scheme."""
262
+ url = "/path/to/image.png"
263
+ expected = "http://example.com/path/to/image.png"
264
+
265
+ result = run_cli("-d", "example.com", "-s", "http", url)
266
+
267
+ assert result.returncode == 0
268
+ assert result.stdout.strip() == expected
269
+ assert not result.stderr
270
+
271
+
272
+ def test_cli_default_domain_no_effect_on_absolute_urls() -> None:
273
+ """Test default domain has no effect on absolute URLs."""
274
+ url = "http://original-domain.com/path"
275
+ expected = "http://original-domain.com/path"
276
+
277
+ result = run_cli("-d", "example.com", url)
278
+
279
+ assert result.returncode == 0
280
+ assert result.stdout.strip() == expected
281
+ assert not result.stderr
282
+
283
+
284
+ def test_cli_default_domain_no_effect_on_relative_paths() -> None:
285
+ """Test default domain has no effect on relative paths."""
286
+ url = "path/to/file.html"
287
+ # This becomes a regular URL with the default scheme
288
+ expected = "https://path/to/file.html"
289
+
290
+ result = run_cli("-d", "example.com", url)
291
+
292
+ assert result.returncode == 0
293
+ assert result.stdout.strip() == expected
294
+ assert not result.stderr
@@ -8,6 +8,8 @@ EXPECTED_DATA = {
8
8
  "пример": "%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80",
9
9
  "!fragment": "%21fragment",
10
10
  "~fragment": "~fragment",
11
+ # Issue #36: Equal sign should not be encoded
12
+ "gid=1234": "gid=1234",
11
13
  }
12
14
 
13
15
 
@@ -29,10 +29,12 @@ EXPECTED_DATA = {
29
29
  "/foo/bar/../baz": "/foo/baz",
30
30
  "/foo/bar/.": "/foo/bar/",
31
31
  "/foo/bar/./": "/foo/bar/",
32
+ # Issue #25: we should preserve ? in the path
33
+ "/More+Tea+Vicar%3F/discussion": "/More+Tea+Vicar%3F/discussion",
32
34
  }
33
35
 
34
36
 
35
- def test_normalize_host_result_is_expected():
37
+ def test_normalize_path_result_is_expected():
36
38
  """Assert we got expected results from the normalize_path function."""
37
39
  for url, expected in EXPECTED_DATA.items():
38
40
  result = normalize_path(url, "http")
@@ -14,6 +14,8 @@ from url_normalize.url_normalize import normalize_query
14
14
  ("Ç=Ç", "%C3%87=%C3%87"),
15
15
  ("%C3%87=%C3%87", "%C3%87=%C3%87"),
16
16
  ("q=C%CC%A7", "q=%C3%87"),
17
+ ("q=%23test", "q=%23test"), # Preserve encoded # in value, #31
18
+ ("where=code%3D123", "where=code%3D123"), # Preserve encoded = in value, #25
17
19
  ],
18
20
  )
19
21
  def test_normalize_query_result_is_expected(query, expected):
@@ -0,0 +1,31 @@
1
+ """Tests for provide_url_domain function."""
2
+
3
+ import pytest
4
+
5
+ from url_normalize.provide_url_domain import provide_url_domain
6
+
7
+
8
+ @pytest.mark.parametrize(
9
+ ("url", "expected"),
10
+ [
11
+ ("", ""),
12
+ ("-", "-"),
13
+ ("http://example.com/", "http://example.com/"),
14
+ ("/file/path", "//example.com/file/path"),
15
+ ("site/page", "site/page"), # No change for relative paths
16
+ ],
17
+ )
18
+ def test_provide_url_domain_result_is_expected(url: str, expected: str) -> None:
19
+ """Assert we get expected results from provide_url_domain function."""
20
+ result = provide_url_domain(url, default_domain="example.com")
21
+ assert result == expected
22
+
23
+
24
+ def test_provide_url_domain_accept_different_domains():
25
+ """Assert we could provide different default_domain values."""
26
+ url = "/file/path"
27
+ expected = "//custom-domain.org/file/path"
28
+
29
+ actual = provide_url_domain(url, default_domain="custom-domain.org")
30
+
31
+ assert actual == expected