{"id":289,"library":"yarl","title":"yarl — Yet Another URL Library","description":"yarl is an immutable, RFC 3986-compliant URL parsing and manipulation library for Python 3. It provides the URL class with automatic percent-encoding/decoding, pathlib-style path operations, query-string helpers, and human-readable representations. The current release is 1.23.0, published March 2026. Releases ship frequently (multiple times per minor version) as part of the aio-libs ecosystem, closely tracking aiohttp.","status":"active","version":"1.23.0","language":"python","source_language":"en","source_url":"https://github.com/aio-libs/yarl","tags":["url","http","async","aiohttp","networking","parsing","aio-libs"],"install":[{"cmd":"pip install yarl","lang":"bash","label":"Latest (with C extension)"},{"cmd":"YARL_NO_EXTENSIONS=1 pip install yarl","lang":"bash","label":"Pure-Python fallback (slower)"}],"dependencies":[{"reason":"Required — URL.query returns a MultiDictProxy; installed automatically by pip","package":"multidict","optional":false},{"reason":"Required — fast property caching layer extracted from yarl ~1.17; installed automatically","package":"propcache","optional":false}],"imports":[{"note":"Always import URL directly from yarl; the top-level module is rarely used on its own.","wrong":"import yarl; yarl.URL(...)","symbol":"URL","correct":"from yarl import URL"},{"note":"ip_address_size and host_validate_size are deprecated since ~1.17 in favour of encode_host_size and will be removed in a future release.","wrong":"cache_configure(ip_address_size=256, host_validate_size=256)","symbol":"cache_configure","correct":"from yarl import cache_configure\ncache_configure(encode_host_size=256)"}],"quickstart":{"code":"from yarl import URL\n\n# Parse an existing URL\nurl = URL('https://user:pw@api.example.com:8080/v1/items?page=1&q=foo#section')\nprint(url.scheme)        # 'https'\nprint(url.host)          # 'api.example.com'  (decoded)\nprint(url.raw_host)      # IDNA-encoded form\nprint(url.port)          # 8080 (explicit); None falls back to scheme default\nprint(url.path)          # '/v1/items'  (percent-decoded)\nprint(url.raw_path)      # '/v1/items'  (percent-encoded, wire form)\nprint(url.query)         # MultiDictProxy with parsed key/value pairs\nprint(url.query_string)  # 'page=1&q=foo'\nprint(url.fragment)      # 'section'\n\n# Build from components — port must be int, not str\nbase = URL.build(scheme='https', host='api.example.com', port=8080, path='/v1')\nprint(base)  # https://api.example.com:8080/v1\n\n# Path-join (like pathlib)\nendpoint = base / 'items' / '42'\nprint(endpoint)  # https://api.example.com:8080/v1/items/42\n\n# Apply a query string with %\nwith_query = endpoint % {'expand': 'true', 'format': 'json'}\nprint(with_query)\n\n# Mutation methods return new URL objects (immutable)\nupdated = endpoint.with_query({'page': '2'}).with_fragment('results')\nprint(str(updated))      # wire-safe string for HTTP clients\nprint(updated.human_repr())  # human-readable (non-ASCII decoded)\n\n# Non-ASCII is encoded automatically\nunicode_url = URL('https://example.com/пошук?q=кіт')\nprint(str(unicode_url))      # percent-encoded\nprint(unicode_url.human_repr())  # readable\n","lang":"python","description":"Parse, inspect, and mutate URLs; build from parts; path-join with /; apply query with %."},"warnings":[{"fix":"Always pass port as int: URL.build(scheme='https', host='example.com', port=443)","message":"URL.build() and URL.with_host() raise TypeError when port is passed as a string. Previously a string port silently produced a malformed URL.","severity":"breaking","affected_versions":">=1.10"},{"fix":"Ensure propcache is present in all deployment targets. pip install yarl handles this automatically.","message":"propcache is now a required hard dependency (split out ~v1.17). Environments that vendor or vendor-pin transitive deps without propcache will fail to import yarl.","severity":"breaking","affected_versions":">=1.17"},{"fix":"Replace cache_configure(ip_address_size=N, host_validate_size=N) with cache_configure(encode_host_size=N)","message":"cache_configure() parameters ip_address_size and host_validate_size are deprecated in favour of encode_host_size and will be removed in a future release.","severity":"deprecated","affected_versions":">=1.17"},{"fix":"Use str(url) or url.raw_path / url.raw_query_string when constructing HTTP request lines.","message":"URL properties (e.g. .path, .host, .query_string) return percent-DECODED values. Pass these to other URLs or HTTP wire formats and you risk double-encoding. Use the raw_ prefixed variants (.raw_path, .raw_host, .raw_query_string) for wire-safe strings.","severity":"gotcha","affected_versions":"all"},{"fix":"Convert bools to strings before passing: {'flag': 'true'} not {'flag': True}","message":"Passing boolean values to with_query() or URL.build(query=...) raises TypeError. yarl refuses to guess how to serialize True/False.","severity":"gotcha","affected_versions":"all"},{"fix":"Use encoded=True only as a last resort and avoid chaining mutation methods on encoded URLs. Prefer URL.build() or proper string inputs instead.","message":"encoded=True skips all auto-encoding but any subsequent mutation method (.with_query(), /, etc.) may re-quote parts, silently corrupting pre-encoded values. The docs explicitly warn against relying on this.","severity":"gotcha","affected_versions":"all"},{"fix":"Use URL.joinpath(*parts) with explicit trailing slash control, or URL.with_path() for full path replacement.","message":"The / operator (URL.__truediv__) and URL.joinpath() strip a trailing slash from the base path before appending the segment. URL('https://example.com/api/') / 'v1' gives /api/v1, not /api//v1. This matches pathlib semantics but surprises users expecting query-string-style appending.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T12:52:14.757Z","next_check":"2026-06-26T00:00:00.000Z","problems":[{"fix":"pip install yarl","cause":"The yarl library is not installed in the current Python environment.","error":"ModuleNotFoundError: No module named 'yarl'"},{"fix":"from yarl import URL","cause":"The URL class is exposed directly from the top-level yarl package, not from a nested yarl.url submodule.","error":"ModuleNotFoundError: No module named 'yarl.url'"},{"fix":"new_url = url.with_query(param1='value1', param2='value2')","cause":"yarl.URL objects are immutable. To modify query parameters, use methods like with_query() or update_query(), which return a new URL object.","error":"AttributeError: 'URL' object has no attribute 'add_query_param'"},{"fix":"Ensure the argument passed is a string representing a path segment or another yarl.URL object. Example: url.joinpath(str(segment_id)) or url / 'segment_name'","cause":"Methods like joinpath() or the / operator for URL objects expect string or other URL objects as arguments for path segments, not other types like integers.","error":"TypeError: argument should be str or URL, got <class 'int'>"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":2.4,"disk_size":"20.2M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":2.4,"disk_size":"21M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":2,"disk_size":"21.7M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":2,"disk_size":"22M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":1.7,"disk_size":"13.6M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":1.7,"disk_size":"14M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":2,"disk_size":"13.3M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":1.8,"disk_size":"14M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":2.1,"disk_size":"20.4M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":2.1,"disk_size":"22M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}