urlpattern 0.2.0__tar.gz → 0.3.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.
@@ -389,9 +389,11 @@ dependencies = [
389
389
 
390
390
  [[package]]
391
391
  name = "urlpattern"
392
- version = "0.2.0"
392
+ version = "0.3.0"
393
393
  dependencies = [
394
394
  "pyo3",
395
+ "regex",
396
+ "url",
395
397
  "urlpattern 0.6.0",
396
398
  ]
397
399
 
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "urlpattern"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  authors = ["방성범 (Bang Seongbeom) <bangseongbeom@gmail.com>"]
5
5
  edition = "2024"
6
6
  description = "An implementation of the URL Pattern Standard for Python written in Rust."
@@ -15,5 +15,7 @@ readme = "README.md"
15
15
  crate-type = ["cdylib"]
16
16
 
17
17
  [dependencies]
18
- pyo3 = "0.28.2"
19
18
  deno-urlpattern = { version = "0.6.0", package = "urlpattern" }
19
+ pyo3 = "0.28.2"
20
+ regex = "1.12.3"
21
+ url = "2.5.8"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: urlpattern
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -158,3 +158,9 @@ Due to limitations in the dependency [denoland/rust-urlpattern](https://github.c
158
158
 
159
159
  Check `pytest.skip` in [`tests/test_lib.py`](https://github.com/urlpattern/python-urlpattern/blob/main/tests/test_lib.py).
160
160
 
161
+ ## Why camelCase?
162
+
163
+ In this library, some names such as `baseURL` and `hasRegExpGroups` do not use snake_case.
164
+
165
+ Like [`xml.dom`](https://docs.python.org/3/library/xml.dom.html), Python wrappers around web standards typically preserve the original camelCase rather than converting names to snake_case. This library follows that convention as well.
166
+
@@ -125,3 +125,9 @@ with make_server("", 8000, app) as httpd:
125
125
  Due to limitations in the dependency [denoland/rust-urlpattern](https://github.com/denoland/rust-urlpattern), it may not support all features specified in [the standard](https://urlpattern.spec.whatwg.org/).
126
126
 
127
127
  Check `pytest.skip` in [`tests/test_lib.py`](https://github.com/urlpattern/python-urlpattern/blob/main/tests/test_lib.py).
128
+
129
+ ## Why camelCase?
130
+
131
+ In this library, some names such as `baseURL` and `hasRegExpGroups` do not use snake_case.
132
+
133
+ Like [`xml.dom`](https://docs.python.org/3/library/xml.dom.html), Python wrappers around web standards typically preserve the original camelCase rather than converting names to snake_case. This library follows that convention as well.
@@ -0,0 +1,479 @@
1
+ #![allow(non_snake_case)]
2
+
3
+ use pyo3::{
4
+ BoundObject,
5
+ exceptions::{PyTypeError, PyValueError},
6
+ prelude::*,
7
+ types::{PyDict, PyList, PyString},
8
+ };
9
+ use std::collections::HashMap;
10
+
11
+ #[pyclass(name = "URLPattern")]
12
+ struct UrlPattern(deno_urlpattern::UrlPattern);
13
+
14
+ #[pymethods]
15
+ impl UrlPattern {
16
+ #[new]
17
+ #[pyo3(signature = (input=None, baseURL=None, options=None))]
18
+ fn new(
19
+ input: Option<UrlPatternInput>,
20
+ baseURL: Option<&Bound<'_, PyAny>>,
21
+ options: Option<&Bound<'_, PyDict>>,
22
+ ) -> PyResult<Self> {
23
+ let (base_url, options) = match baseURL {
24
+ Some(value) => {
25
+ if let Ok(options_dict) = value.cast::<PyDict>() {
26
+ (None, Some(options_dict))
27
+ } else if value.is_none() {
28
+ (None, options)
29
+ } else {
30
+ (
31
+ Some(
32
+ value
33
+ .extract::<String>()?
34
+ .parse::<url::Url>()
35
+ .map_err(deno_urlpattern::Error::Url)
36
+ .map_err(Error)?,
37
+ ),
38
+ options,
39
+ )
40
+ }
41
+ }
42
+ None => (None, options),
43
+ };
44
+
45
+ if let Some(UrlPatternInput::Init(_)) = input {
46
+ if let Some(_) = base_url {
47
+ return Err(PyTypeError::new_err("cannot use dict input with baseURL"));
48
+ }
49
+ }
50
+
51
+ let init: deno_urlpattern::UrlPatternInit = match input {
52
+ Some(input) => match input {
53
+ UrlPatternInput::String(input) => {
54
+ deno_urlpattern::UrlPatternInit::parse_constructor_string::<regex::Regex>(
55
+ input.as_str(),
56
+ base_url,
57
+ )
58
+ .map_err(Error)?
59
+ }
60
+ UrlPatternInput::Init(init) => deno_urlpattern::UrlPatternInit {
61
+ protocol: init
62
+ .get_item("protocol")?
63
+ .map(|v| v.extract::<String>())
64
+ .transpose()?,
65
+ username: init
66
+ .get_item("username")?
67
+ .map(|v| v.extract::<String>())
68
+ .transpose()?,
69
+ password: init
70
+ .get_item("password")?
71
+ .map(|v| v.extract::<String>())
72
+ .transpose()?,
73
+ hostname: init
74
+ .get_item("hostname")?
75
+ .map(|v| v.extract::<String>())
76
+ .transpose()?,
77
+ port: init
78
+ .get_item("port")?
79
+ .map(|v| v.extract::<String>())
80
+ .transpose()?,
81
+ pathname: init
82
+ .get_item("pathname")?
83
+ .map(|v| v.extract::<String>())
84
+ .transpose()?,
85
+ search: init
86
+ .get_item("search")?
87
+ .map(|v| v.extract::<String>())
88
+ .transpose()?,
89
+ hash: init
90
+ .get_item("hash")?
91
+ .map(|v| v.extract::<String>())
92
+ .transpose()?,
93
+ base_url: init
94
+ .get_item("baseURL")?
95
+ .map(|v| v.extract::<String>())
96
+ .transpose()?
97
+ .map(|v| v.parse::<url::Url>())
98
+ .transpose()
99
+ .map_err(deno_urlpattern::Error::Url)
100
+ .map_err(Error)?,
101
+ },
102
+ },
103
+ None => deno_urlpattern::UrlPatternInit::default(),
104
+ };
105
+ let options = if let Some(options) = options {
106
+ deno_urlpattern::UrlPatternOptions {
107
+ ignore_case: options
108
+ .get_item("ignoreCase")?
109
+ .map(|v| v.extract::<bool>())
110
+ .transpose()?
111
+ .unwrap_or(false),
112
+ ..deno_urlpattern::UrlPatternOptions::default()
113
+ }
114
+ } else {
115
+ deno_urlpattern::UrlPatternOptions::default()
116
+ };
117
+ Ok(UrlPattern(
118
+ deno_urlpattern::UrlPattern::parse(init, options).map_err(Error)?,
119
+ ))
120
+ }
121
+
122
+ fn __repr__(&self, py: Python) -> String {
123
+ let dict = PyDict::new(py);
124
+ dict.set_item("protocol", self.0.protocol()).unwrap();
125
+ dict.set_item("username", self.0.username()).unwrap();
126
+ dict.set_item("password", self.0.password()).unwrap();
127
+ dict.set_item("hostname", self.0.hostname()).unwrap();
128
+ dict.set_item("port", self.0.port()).unwrap();
129
+ dict.set_item("pathname", self.0.pathname()).unwrap();
130
+ dict.set_item("search", self.0.search()).unwrap();
131
+ dict.set_item("hash", self.0.hash()).unwrap();
132
+ dict.set_item("hasRegExpGroups", self.0.has_regexp_groups())
133
+ .unwrap();
134
+ format!("URLPattern({})", dict)
135
+ }
136
+
137
+ #[pyo3(signature = (input=None, baseURL=None))]
138
+ fn test(&self, input: Option<UrlPatternInput>, baseURL: Option<&str>) -> PyResult<bool> {
139
+ let input: deno_urlpattern::UrlPatternMatchInput = match input {
140
+ Some(input) => match input {
141
+ UrlPatternInput::String(input) => match baseURL {
142
+ Some(base_url) => {
143
+ let base_url = match url::Url::parse(base_url) {
144
+ Ok(url) => url,
145
+ Err(_) => return Ok(false),
146
+ };
147
+ deno_urlpattern::UrlPatternMatchInput::Url(
148
+ match url::Url::options()
149
+ .base_url(Some(&base_url))
150
+ .parse(input.as_ref())
151
+ {
152
+ Ok(url) => url,
153
+ Err(_) => return Ok(false),
154
+ },
155
+ )
156
+ }
157
+ None => deno_urlpattern::UrlPatternMatchInput::Url(
158
+ match input.parse::<url::Url>() {
159
+ Ok(url) => url,
160
+ Err(_) => return Ok(false),
161
+ },
162
+ ),
163
+ },
164
+ UrlPatternInput::Init(init) => {
165
+ if let Some(_) = baseURL {
166
+ return Err(PyTypeError::new_err("cannot use dict input with baseURL"));
167
+ }
168
+
169
+ deno_urlpattern::UrlPatternMatchInput::Init(deno_urlpattern::UrlPatternInit {
170
+ protocol: init
171
+ .get_item("protocol")?
172
+ .map(|v| v.extract::<String>())
173
+ .transpose()?,
174
+ username: init
175
+ .get_item("username")?
176
+ .map(|v| v.extract::<String>())
177
+ .transpose()?,
178
+ password: init
179
+ .get_item("password")?
180
+ .map(|v| v.extract::<String>())
181
+ .transpose()?,
182
+ hostname: init
183
+ .get_item("hostname")?
184
+ .map(|v| v.extract::<String>())
185
+ .transpose()?,
186
+ port: init
187
+ .get_item("port")?
188
+ .map(|v| v.extract::<String>())
189
+ .transpose()?,
190
+ pathname: init
191
+ .get_item("pathname")?
192
+ .map(|v| v.extract::<String>())
193
+ .transpose()?,
194
+ search: init
195
+ .get_item("search")?
196
+ .map(|v| v.extract::<String>())
197
+ .transpose()?,
198
+ hash: init
199
+ .get_item("hash")?
200
+ .map(|v| v.extract::<String>())
201
+ .transpose()?,
202
+ base_url: init
203
+ .get_item("baseURL")?
204
+ .map(|v| v.extract::<String>())
205
+ .transpose()?
206
+ .map(|v| v.parse::<url::Url>())
207
+ .transpose()
208
+ .map_err(deno_urlpattern::Error::Url)
209
+ .map_err(Error)?,
210
+ })
211
+ }
212
+ },
213
+ None => deno_urlpattern::UrlPatternMatchInput::Init(
214
+ deno_urlpattern::UrlPatternInit::default(),
215
+ ),
216
+ };
217
+ Ok(self.0.test(input).map_err(Error)?)
218
+ }
219
+
220
+ #[pyo3(signature = (input=None, baseURL=None))]
221
+ fn exec<'py>(
222
+ &self,
223
+ py: Python<'py>,
224
+ input: Option<&Bound<'py, PyAny>>,
225
+ baseURL: Option<&Bound<'py, PyString>>,
226
+ ) -> PyResult<Option<UrlPatternResult<'py>>> {
227
+ let urlpattern_input: Option<UrlPatternInput> = input.map(|i| i.extract()).transpose()?;
228
+ let input: deno_urlpattern::UrlPatternMatchInput = match &urlpattern_input {
229
+ Some(input) => match input {
230
+ UrlPatternInput::String(input) => match baseURL {
231
+ Some(base_url) => {
232
+ let base_url = match url::Url::parse(base_url.to_str()?) {
233
+ Ok(url) => url,
234
+ Err(_) => return Ok(None),
235
+ };
236
+ deno_urlpattern::UrlPatternMatchInput::Url(
237
+ match url::Url::options()
238
+ .base_url(Some(&base_url))
239
+ .parse(input.as_ref())
240
+ {
241
+ Ok(url) => url,
242
+ Err(_) => return Ok(None),
243
+ },
244
+ )
245
+ }
246
+ None => deno_urlpattern::UrlPatternMatchInput::Url(
247
+ match input.parse::<url::Url>() {
248
+ Ok(url) => url,
249
+ Err(_) => return Ok(None),
250
+ },
251
+ ),
252
+ },
253
+ UrlPatternInput::Init(init) => {
254
+ if let Some(_) = baseURL {
255
+ return Err(PyTypeError::new_err("cannot use dict input with baseURL"));
256
+ }
257
+
258
+ deno_urlpattern::UrlPatternMatchInput::Init(deno_urlpattern::UrlPatternInit {
259
+ protocol: init
260
+ .get_item("protocol")?
261
+ .map(|v| v.extract::<String>())
262
+ .transpose()?,
263
+ username: init
264
+ .get_item("username")?
265
+ .map(|v| v.extract::<String>())
266
+ .transpose()?,
267
+ password: init
268
+ .get_item("password")?
269
+ .map(|v| v.extract::<String>())
270
+ .transpose()?,
271
+ hostname: init
272
+ .get_item("hostname")?
273
+ .map(|v| v.extract::<String>())
274
+ .transpose()?,
275
+ port: init
276
+ .get_item("port")?
277
+ .map(|v| v.extract::<String>())
278
+ .transpose()?,
279
+ pathname: init
280
+ .get_item("pathname")?
281
+ .map(|v| v.extract::<String>())
282
+ .transpose()?,
283
+ search: init
284
+ .get_item("search")?
285
+ .map(|v| v.extract::<String>())
286
+ .transpose()?,
287
+ hash: init
288
+ .get_item("hash")?
289
+ .map(|v| v.extract::<String>())
290
+ .transpose()?,
291
+ base_url: init
292
+ .get_item("baseURL")?
293
+ .map(|v| v.extract::<String>())
294
+ .transpose()?
295
+ .map(|v| v.parse::<url::Url>())
296
+ .transpose()
297
+ .map_err(deno_urlpattern::Error::Url)
298
+ .map_err(Error)?,
299
+ })
300
+ }
301
+ },
302
+ None => deno_urlpattern::UrlPatternMatchInput::Init(
303
+ deno_urlpattern::UrlPatternInit::default(),
304
+ ),
305
+ };
306
+
307
+ let Some(result) = self.0.exec(input).map_err(Error)? else {
308
+ return Ok(None);
309
+ };
310
+
311
+ Ok(Some(UrlPatternResult {
312
+ inputs: {
313
+ let mut vec = Vec::new();
314
+ vec.push(
315
+ urlpattern_input.unwrap_or(UrlPatternInput::Init(PyDict::new(py).into_bound())),
316
+ );
317
+ if let Some(base_url) = baseURL {
318
+ vec.push(UrlPatternInput::String(base_url.to_string()));
319
+ }
320
+ vec
321
+ },
322
+ protocol: UrlPatternComponentResult {
323
+ input: result.protocol.input,
324
+ groups: result.protocol.groups,
325
+ },
326
+ username: UrlPatternComponentResult {
327
+ input: result.username.input,
328
+ groups: result.username.groups,
329
+ },
330
+ password: UrlPatternComponentResult {
331
+ input: result.password.input,
332
+ groups: result.password.groups,
333
+ },
334
+ hostname: UrlPatternComponentResult {
335
+ input: result.hostname.input,
336
+ groups: result.hostname.groups,
337
+ },
338
+ port: UrlPatternComponentResult {
339
+ input: result.port.input,
340
+ groups: result.port.groups,
341
+ },
342
+ pathname: UrlPatternComponentResult {
343
+ input: result.pathname.input,
344
+ groups: result.pathname.groups,
345
+ },
346
+ search: UrlPatternComponentResult {
347
+ input: result.search.input,
348
+ groups: result.search.groups,
349
+ },
350
+ hash: UrlPatternComponentResult {
351
+ input: result.hash.input,
352
+ groups: result.hash.groups,
353
+ },
354
+ }))
355
+ }
356
+
357
+ #[getter]
358
+ fn protocol(&self) -> PyResult<&str> {
359
+ Ok(self.0.protocol())
360
+ }
361
+
362
+ #[getter]
363
+ fn username(&self) -> PyResult<&str> {
364
+ Ok(self.0.username())
365
+ }
366
+
367
+ #[getter]
368
+ fn password(&self) -> PyResult<&str> {
369
+ Ok(self.0.password())
370
+ }
371
+
372
+ #[getter]
373
+ fn hostname(&self) -> PyResult<&str> {
374
+ Ok(self.0.hostname())
375
+ }
376
+
377
+ #[getter]
378
+ fn port(&self) -> PyResult<&str> {
379
+ Ok(self.0.port())
380
+ }
381
+
382
+ #[getter]
383
+ fn pathname(&self) -> PyResult<&str> {
384
+ Ok(self.0.pathname())
385
+ }
386
+
387
+ #[getter]
388
+ fn search(&self) -> PyResult<&str> {
389
+ Ok(self.0.search())
390
+ }
391
+
392
+ #[getter]
393
+ fn hash(&self) -> PyResult<&str> {
394
+ Ok(self.0.hash())
395
+ }
396
+
397
+ #[getter(hasRegExpGroups)]
398
+ fn has_regexp_groups(&self) -> PyResult<bool> {
399
+ Ok(self.0.has_regexp_groups())
400
+ }
401
+ }
402
+
403
+ #[derive(FromPyObject)]
404
+ enum UrlPatternInput<'py> {
405
+ String(String),
406
+ Init(Bound<'py, PyDict>),
407
+ }
408
+
409
+ struct UrlPatternResult<'py> {
410
+ inputs: Vec<UrlPatternInput<'py>>,
411
+ protocol: UrlPatternComponentResult,
412
+ username: UrlPatternComponentResult,
413
+ password: UrlPatternComponentResult,
414
+ hostname: UrlPatternComponentResult,
415
+ port: UrlPatternComponentResult,
416
+ pathname: UrlPatternComponentResult,
417
+ search: UrlPatternComponentResult,
418
+ hash: UrlPatternComponentResult,
419
+ }
420
+
421
+ impl<'py> IntoPyObject<'py> for UrlPatternResult<'py> {
422
+ type Target = PyDict;
423
+ type Output = Bound<'py, Self::Target>;
424
+ type Error = std::convert::Infallible;
425
+
426
+ fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
427
+ let dict = PyDict::new(py);
428
+
429
+ let inputs = PyList::empty(py);
430
+ for input in self.inputs {
431
+ match input {
432
+ UrlPatternInput::String(string) => {
433
+ inputs.append(string).unwrap();
434
+ }
435
+ UrlPatternInput::Init(init) => {
436
+ inputs.append(init).unwrap();
437
+ }
438
+ }
439
+ }
440
+
441
+ dict.set_item("inputs", inputs).unwrap();
442
+ dict.set_item("protocol", self.protocol).unwrap();
443
+ dict.set_item("username", self.username).unwrap();
444
+ dict.set_item("password", self.password).unwrap();
445
+ dict.set_item("hostname", self.hostname).unwrap();
446
+ dict.set_item("port", self.port).unwrap();
447
+ dict.set_item("pathname", self.pathname).unwrap();
448
+ dict.set_item("search", self.search).unwrap();
449
+ dict.set_item("hash", self.hash).unwrap();
450
+ Ok(dict.into_bound())
451
+ }
452
+ }
453
+
454
+ #[derive(IntoPyObject, IntoPyObjectRef)]
455
+ struct UrlPatternComponentResult {
456
+ input: String,
457
+ groups: HashMap<String, Option<String>>,
458
+ }
459
+
460
+ struct Error(deno_urlpattern::Error);
461
+
462
+ impl From<Error> for PyErr {
463
+ fn from(error: Error) -> Self {
464
+ PyValueError::new_err(error.0.to_string())
465
+ }
466
+ }
467
+
468
+ impl From<deno_urlpattern::Error> for Error {
469
+ fn from(other: deno_urlpattern::Error) -> Self {
470
+ Self(other)
471
+ }
472
+ }
473
+
474
+ /// A Python module implemented in Rust.
475
+ #[pymodule]
476
+ mod urlpattern {
477
+ #[pymodule_export]
478
+ use super::UrlPattern;
479
+ }
@@ -1,370 +0,0 @@
1
- #![allow(non_snake_case)]
2
-
3
- use std::borrow::Cow;
4
- use std::collections::HashMap;
5
-
6
- use pyo3::{
7
- BoundObject,
8
- exceptions::PyValueError,
9
- prelude::*,
10
- types::{PyDict, PyList},
11
- };
12
-
13
- #[pyclass(name = "URLPattern")]
14
- struct UrlPattern(deno_urlpattern::UrlPattern);
15
-
16
- #[pymethods]
17
- impl UrlPattern {
18
- #[new]
19
- #[pyo3(signature = (input=None, baseURL=None, options=None))]
20
- pub fn new(
21
- input: Option<UrlPatternInput>,
22
- baseURL: Option<&Bound<'_, PyAny>>,
23
- options: Option<&Bound<'_, PyDict>>,
24
- ) -> PyResult<Self> {
25
- let (base_url, options) = match baseURL {
26
- Some(value) => {
27
- if let Ok(options_dict) = value.cast::<PyDict>() {
28
- (None, Some(options_dict))
29
- } else if value.is_none() {
30
- (None, options)
31
- } else {
32
- (Some(value.extract::<String>()?), options)
33
- }
34
- }
35
- None => (None, options),
36
- };
37
-
38
- let string_or_init_input = match input {
39
- Some(input) => deno_urlpattern::quirks::StringOrInit::try_from(input)?,
40
- None => deno_urlpattern::quirks::StringOrInit::Init(
41
- deno_urlpattern::quirks::UrlPatternInit::default(),
42
- ),
43
- };
44
- let options = if let Some(options) = options {
45
- deno_urlpattern::UrlPatternOptions {
46
- ignore_case: options
47
- .get_item("ignoreCase")?
48
- .map(|v| v.extract::<bool>())
49
- .transpose()?
50
- .unwrap_or(false),
51
- ..deno_urlpattern::UrlPatternOptions::default()
52
- }
53
- } else {
54
- deno_urlpattern::UrlPatternOptions::default()
55
- };
56
- Ok(UrlPattern(
57
- <deno_urlpattern::UrlPattern>::parse(
58
- deno_urlpattern::quirks::process_construct_pattern_input(
59
- string_or_init_input,
60
- base_url.as_deref(),
61
- )
62
- .map_err(Error)?,
63
- options,
64
- )
65
- .map_err(Error)?,
66
- ))
67
- }
68
-
69
- pub fn __repr__(&self, py: Python) -> String {
70
- let dict = PyDict::new(py);
71
- dict.set_item("protocol", self.0.protocol()).unwrap();
72
- dict.set_item("username", self.0.username()).unwrap();
73
- dict.set_item("password", self.0.password()).unwrap();
74
- dict.set_item("hostname", self.0.hostname()).unwrap();
75
- dict.set_item("port", self.0.port()).unwrap();
76
- dict.set_item("pathname", self.0.pathname()).unwrap();
77
- dict.set_item("search", self.0.search()).unwrap();
78
- dict.set_item("hash", self.0.hash()).unwrap();
79
- dict.set_item("hasRegExpGroups", self.0.has_regexp_groups()).unwrap();
80
- format!("URLPattern({})", dict)
81
- }
82
-
83
- #[pyo3(signature = (input=None, baseURL=None))]
84
- pub fn test(&self, input: Option<UrlPatternInput>, baseURL: Option<&str>) -> PyResult<bool> {
85
- let string_or_init_input = match input {
86
- Some(input) => deno_urlpattern::quirks::StringOrInit::try_from(input)?,
87
- None => deno_urlpattern::quirks::StringOrInit::Init(
88
- deno_urlpattern::quirks::UrlPatternInit::default(),
89
- ),
90
- };
91
- let Some((match_input, _)) =
92
- deno_urlpattern::quirks::process_match_input(string_or_init_input, baseURL)
93
- .map_err(Error)?
94
- else {
95
- return Ok(false);
96
- };
97
- Ok(self.0.test(match_input).map_err(Error)?)
98
- }
99
-
100
- #[pyo3(signature = (input=None, baseURL=None))]
101
- pub fn exec(
102
- &self,
103
- input: Option<UrlPatternInput>,
104
- baseURL: Option<&str>,
105
- ) -> PyResult<Option<UrlPatternResult>> {
106
- let string_or_init_input = match input {
107
- Some(input) => deno_urlpattern::quirks::StringOrInit::try_from(input)?,
108
- None => deno_urlpattern::quirks::StringOrInit::Init(
109
- deno_urlpattern::quirks::UrlPatternInit::default(),
110
- ),
111
- };
112
- let Some((match_input, inputs)) =
113
- deno_urlpattern::quirks::process_match_input(string_or_init_input, baseURL)
114
- .map_err(Error)?
115
- else {
116
- return Ok(None);
117
- };
118
- let Some(result) = self.0.exec(match_input).map_err(Error)? else {
119
- return Ok(None);
120
- };
121
-
122
- Ok(Some(UrlPatternResult {
123
- inputs,
124
- protocol: UrlPatternComponentResult {
125
- input: result.protocol.input,
126
- groups: result.protocol.groups,
127
- },
128
- username: UrlPatternComponentResult {
129
- input: result.username.input,
130
- groups: result.username.groups,
131
- },
132
- password: UrlPatternComponentResult {
133
- input: result.password.input,
134
- groups: result.password.groups,
135
- },
136
- hostname: UrlPatternComponentResult {
137
- input: result.hostname.input,
138
- groups: result.hostname.groups,
139
- },
140
- port: UrlPatternComponentResult {
141
- input: result.port.input,
142
- groups: result.port.groups,
143
- },
144
- pathname: UrlPatternComponentResult {
145
- input: result.pathname.input,
146
- groups: result.pathname.groups,
147
- },
148
- search: UrlPatternComponentResult {
149
- input: result.search.input,
150
- groups: result.search.groups,
151
- },
152
- hash: UrlPatternComponentResult {
153
- input: result.hash.input,
154
- groups: result.hash.groups,
155
- },
156
- }))
157
- }
158
-
159
- #[getter]
160
- pub fn get_protocol(&self) -> PyResult<&str> {
161
- Ok(self.0.protocol())
162
- }
163
-
164
- #[getter]
165
- pub fn get_username(&self) -> PyResult<&str> {
166
- Ok(self.0.username())
167
- }
168
-
169
- #[getter]
170
- pub fn get_password(&self) -> PyResult<&str> {
171
- Ok(self.0.password())
172
- }
173
-
174
- #[getter]
175
- pub fn get_hostname(&self) -> PyResult<&str> {
176
- Ok(self.0.hostname())
177
- }
178
-
179
- #[getter]
180
- pub fn get_port(&self) -> PyResult<&str> {
181
- Ok(self.0.port())
182
- }
183
-
184
- #[getter]
185
- pub fn get_pathname(&self) -> PyResult<&str> {
186
- Ok(self.0.pathname())
187
- }
188
-
189
- #[getter]
190
- pub fn get_search(&self) -> PyResult<&str> {
191
- Ok(self.0.search())
192
- }
193
-
194
- #[getter]
195
- pub fn get_hash(&self) -> PyResult<&str> {
196
- Ok(self.0.hash())
197
- }
198
-
199
- #[getter]
200
- pub fn get_hasRegExpGroups(&self) -> PyResult<bool> {
201
- Ok(self.0.has_regexp_groups())
202
- }
203
- }
204
-
205
- #[derive(FromPyObject)]
206
- pub enum UrlPatternInput<'py> {
207
- String(String),
208
- Init(Bound<'py, PyDict>),
209
- }
210
-
211
- impl<'py> TryFrom<UrlPatternInput<'py>> for deno_urlpattern::quirks::StringOrInit<'static> {
212
- type Error = pyo3::PyErr;
213
-
214
- fn try_from(input: UrlPatternInput<'py>) -> Result<Self, Self::Error> {
215
- Ok(match input {
216
- UrlPatternInput::String(pattern) => {
217
- deno_urlpattern::quirks::StringOrInit::String(Cow::Owned(pattern))
218
- }
219
- UrlPatternInput::Init(init) => deno_urlpattern::quirks::StringOrInit::Init(
220
- deno_urlpattern::quirks::UrlPatternInit {
221
- protocol: init
222
- .get_item("protocol")?
223
- .map(|v| v.extract::<String>())
224
- .transpose()?,
225
- username: init
226
- .get_item("username")?
227
- .map(|v| v.extract::<String>())
228
- .transpose()?,
229
- password: init
230
- .get_item("password")?
231
- .map(|v| v.extract::<String>())
232
- .transpose()?,
233
- hostname: init
234
- .get_item("hostname")?
235
- .map(|v| v.extract::<String>())
236
- .transpose()?,
237
- port: init
238
- .get_item("port")?
239
- .map(|v| v.extract::<String>())
240
- .transpose()?,
241
- pathname: init
242
- .get_item("pathname")?
243
- .map(|v| v.extract::<String>())
244
- .transpose()?,
245
- search: init
246
- .get_item("search")?
247
- .map(|v| v.extract::<String>())
248
- .transpose()?,
249
- hash: init
250
- .get_item("hash")?
251
- .map(|v| v.extract::<String>())
252
- .transpose()?,
253
- base_url: init
254
- .get_item("baseURL")?
255
- .map(|v| v.extract::<String>())
256
- .transpose()?,
257
- },
258
- ),
259
- })
260
- }
261
- }
262
-
263
- pub struct UrlPatternResult {
264
- pub inputs: (
265
- deno_urlpattern::quirks::StringOrInit<'static>,
266
- Option<String>,
267
- ),
268
- pub protocol: UrlPatternComponentResult,
269
- pub username: UrlPatternComponentResult,
270
- pub password: UrlPatternComponentResult,
271
- pub hostname: UrlPatternComponentResult,
272
- pub port: UrlPatternComponentResult,
273
- pub pathname: UrlPatternComponentResult,
274
- pub search: UrlPatternComponentResult,
275
- pub hash: UrlPatternComponentResult,
276
- }
277
-
278
- impl<'py> IntoPyObject<'py> for UrlPatternResult {
279
- type Target = PyDict;
280
- type Output = Bound<'py, Self::Target>;
281
- type Error = std::convert::Infallible;
282
-
283
- fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
284
- let dict = PyDict::new(py);
285
-
286
- let (string_or_init, base_url) = self.inputs;
287
- let list = PyList::empty(py);
288
-
289
- match string_or_init {
290
- deno_urlpattern::quirks::StringOrInit::String(string) => {
291
- list.append(string.into_owned()).unwrap();
292
- }
293
- deno_urlpattern::quirks::StringOrInit::Init(init) => {
294
- let init_dict = PyDict::new(py);
295
- if let Some(protocol) = init.protocol {
296
- init_dict.set_item("protocol", protocol).unwrap();
297
- }
298
- if let Some(username) = init.username {
299
- init_dict.set_item("username", username).unwrap();
300
- }
301
- if let Some(password) = init.password {
302
- init_dict.set_item("password", password).unwrap();
303
- }
304
- if let Some(hostname) = init.hostname {
305
- init_dict.set_item("hostname", hostname).unwrap();
306
- }
307
- if let Some(port) = init.port {
308
- init_dict.set_item("port", port).unwrap();
309
- }
310
- if let Some(pathname) = init.pathname {
311
- init_dict.set_item("pathname", pathname).unwrap();
312
- }
313
- if let Some(search) = init.search {
314
- init_dict.set_item("search", search).unwrap();
315
- }
316
- if let Some(hash) = init.hash {
317
- init_dict.set_item("hash", hash).unwrap();
318
- }
319
- if let Some(base_url) = init.base_url {
320
- init_dict.set_item("baseURL", base_url).unwrap();
321
- }
322
- list.append(init_dict).unwrap();
323
- }
324
- }
325
-
326
- if let Some(base_url) = base_url {
327
- list.append(base_url).unwrap();
328
- }
329
-
330
- dict.set_item("inputs", list).unwrap();
331
-
332
- dict.set_item("protocol", self.protocol).unwrap();
333
- dict.set_item("username", self.username).unwrap();
334
- dict.set_item("password", self.password).unwrap();
335
- dict.set_item("hostname", self.hostname).unwrap();
336
- dict.set_item("port", self.port).unwrap();
337
- dict.set_item("pathname", self.pathname).unwrap();
338
- dict.set_item("search", self.search).unwrap();
339
- dict.set_item("hash", self.hash).unwrap();
340
-
341
- Ok(dict.into_bound())
342
- }
343
- }
344
-
345
- #[derive(IntoPyObject, IntoPyObjectRef)]
346
- pub struct UrlPatternComponentResult {
347
- input: String,
348
- groups: HashMap<String, Option<String>>,
349
- }
350
-
351
- pub struct Error(deno_urlpattern::Error);
352
-
353
- impl From<Error> for PyErr {
354
- fn from(error: Error) -> Self {
355
- PyValueError::new_err(error.0.to_string())
356
- }
357
- }
358
-
359
- impl From<deno_urlpattern::Error> for Error {
360
- fn from(other: deno_urlpattern::Error) -> Self {
361
- Self(other)
362
- }
363
- }
364
-
365
- /// A Python module implemented in Rust.
366
- #[pymodule]
367
- mod urlpattern {
368
- #[pymodule_export]
369
- use super::UrlPattern;
370
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes