Quote a URL if it isn't already quoted.
(url)
| 241 | |
| 242 | |
| 243 | def smart_urlquote(url): |
| 244 | """Quote a URL if it isn't already quoted.""" |
| 245 | |
| 246 | def unquote_quote(segment): |
| 247 | segment = unquote(segment) |
| 248 | # Tilde is part of RFC 3986 Section 2.3 Unreserved Characters, |
| 249 | # see also https://bugs.python.org/issue16285 |
| 250 | return quote(segment, safe=RFC3986_SUBDELIMS + RFC3986_GENDELIMS + "~") |
| 251 | |
| 252 | try: |
| 253 | scheme, netloc, path, query, fragment = urlsplit(url) |
| 254 | except ValueError: |
| 255 | # invalid IPv6 URL (normally square brackets in hostname part). |
| 256 | return unquote_quote(url) |
| 257 | |
| 258 | # Handle IDN as percent-encoded UTF-8 octets, per WHATWG URL Specification |
| 259 | # section 3.5 and RFC 3986 section 3.2.2. Defer any IDNA to the user agent. |
| 260 | # See #36013. |
| 261 | netloc = unquote_quote(netloc) |
| 262 | |
| 263 | if query: |
| 264 | # Separately unquoting key/value, so as to not mix querystring |
| 265 | # separators included in query values. See #22267. |
| 266 | query_parts = [ |
| 267 | (unquote(q[0]), unquote(q[1])) |
| 268 | for q in parse_qsl(query, keep_blank_values=True) |
| 269 | ] |
| 270 | # urlencode will take care of quoting |
| 271 | query = urlencode(query_parts) |
| 272 | |
| 273 | path = unquote_quote(path) |
| 274 | fragment = unquote_quote(fragment) |
| 275 | |
| 276 | return urlunsplit((scheme, netloc, path, query, fragment)) |
| 277 | |
| 278 | |
| 279 | class CountsDict(dict): |