11from enum import IntEnum
2+ from typing import Final , Iterable , List , Optional , TypedDict , Union
23
34from ada_url ._ada_wrapper import ffi , lib
45
@@ -56,6 +57,21 @@ class HostType(IntEnum):
5657 IPV6 = 2
5758
5859
60+ class ParseAttributes (TypedDict , total = False ):
61+ href : str
62+ username : str
63+ password : str
64+ protocol : str
65+ port : str
66+ hostname : str
67+ host : str
68+ pathname : str
69+ search : str
70+ hash : str
71+ origin : str
72+ host_type : HostType
73+
74+
5975def _get_obj (constructor , destructor , * args ):
6076 obj = constructor (* args )
6177
@@ -95,6 +111,7 @@ class URL:
95111 * ``port``
96112 * ``pathname``
97113 * ``search``
114+ * ``hash``
98115
99116 You can additionally read the ``origin`` and ``host_type`` attributes.
100117 ``host_type`` is a :class:`HostType` enum.
@@ -114,7 +131,20 @@ class URL:
114131
115132 """
116133
117- def __init__ (self , url , base = None ):
134+ href : str
135+ username : str
136+ password : str
137+ protocol : str
138+ port : str
139+ hostname : str
140+ host : str
141+ pathname : str
142+ search : str
143+ hash : str
144+ origin : Final [str ]
145+ host_type : Final [HostType ]
146+
147+ def __init__ (self , url : str , base : Optional [str ] = None ):
118148 url_bytes = url .encode ('utf-8' )
119149
120150 if base is None :
@@ -150,7 +180,7 @@ def __deepcopy__(self, memo):
150180
151181 return ret
152182
153- def __delattr__ (self , attr ):
183+ def __delattr__ (self , attr : str ):
154184 if attr in CLEAR_ATTRIBUTES :
155185 clear_func = getattr (lib , f'ada_clear_{ attr } ' )
156186 clear_func (self .urlobj )
@@ -160,10 +190,10 @@ def __delattr__(self, attr):
160190 else :
161191 raise AttributeError (f'cannot remove { attr } ' )
162192
163- def __dir__ (self ):
193+ def __dir__ (self ) -> List [ str ] :
164194 return super ().__dir__ () + list (PARSE_ATTRIBUTES )
165195
166- def __getattr__ (self , attr ) :
196+ def __getattr__ (self , attr : str ) -> Union [ str , HostType ] :
167197 if attr in GET_ATTRIBUTES :
168198 get_func = getattr (lib , f'ada_get_{ attr } ' )
169199 data = get_func (self .urlobj )
@@ -179,7 +209,7 @@ def __getattr__(self, attr):
179209
180210 raise AttributeError (f'no attribute named { attr } ' )
181211
182- def __setattr__ (self , attr , value ) :
212+ def __setattr__ (self , attr : str , value : str ) -> None :
183213 if attr in SET_ATTRIBUTES :
184214 try :
185215 value_bytes = value .encode ()
@@ -202,7 +232,7 @@ def __repr__(self):
202232 return f'<URL "{ self .href } ">'
203233
204234 @staticmethod
205- def can_parse (url , base = None ):
235+ def can_parse (url : str , base : Optional [ str ] = None ) -> bool :
206236 try :
207237 url_bytes = url .encode ('utf-8' )
208238 except Exception :
@@ -221,7 +251,7 @@ def can_parse(url, base=None):
221251 )
222252
223253
224- def check_url (s ) :
254+ def check_url (s : str ) -> bool :
225255 """
226256 Returns ``True`` if *s* represents a valid URL, and ``False`` otherwise.
227257
@@ -243,7 +273,7 @@ def check_url(s):
243273 return lib .ada_is_valid (urlobj )
244274
245275
246- def join_url (base_url , s ) :
276+ def join_url (base_url : str , s : str ) -> str :
247277 """
248278 Return the URL that results from joining *base_url* to *s*.
249279 Raises ``ValueError`` if no valid URL can be constructed.
@@ -276,7 +306,7 @@ def join_url(base_url, s):
276306 return _get_str (lib .ada_get_href (urlobj ))
277307
278308
279- def normalize_url (s ) :
309+ def normalize_url (s : str ) -> str :
280310 """
281311 Returns a "normalized" URL with all ``'..'`` and ``'/'`` characters resolved.
282312
@@ -290,7 +320,7 @@ def normalize_url(s):
290320 return parse_url (s , attributes = ('href' ,))['href' ]
291321
292322
293- def parse_url (s , attributes = PARSE_ATTRIBUTES ):
323+ def parse_url (s : str , attributes : Iterable [ str ] = PARSE_ATTRIBUTES ) -> ParseAttributes :
294324 """
295325 Returns a dictionary with the parsed components of the URL represented by *s*.
296326
@@ -354,7 +384,7 @@ def parse_url(s, attributes=PARSE_ATTRIBUTES):
354384 return ret
355385
356386
357- def replace_url (s , ** kwargs ) :
387+ def replace_url (s : str , ** kwargs : str ) -> str :
358388 """
359389 Start with the URL represented by *s*, replace the attributes given in the *kwargs*
360390 mapping, and return a normalized URL with the result.
@@ -433,15 +463,15 @@ class idna:
433463 """
434464
435465 @staticmethod
436- def decode (s ) :
466+ def decode (s : Union [ str , bytes ]) -> str :
437467 if isinstance (s , str ):
438468 s = s .encode ('ascii' )
439469
440470 data = _get_obj (lib .ada_idna_to_unicode , lib .ada_free_owned_string , s , len (s ))
441471 return _get_str (data )
442472
443473 @staticmethod
444- def encode (s ) :
474+ def encode (s : Union [ str , bytes ]) -> str :
445475 if isinstance (s , str ):
446476 s = s .encode ('utf-8' )
447477
0 commit comments