{"id":13467660,"url":"https://github.com/gruns/furl","last_synced_at":"2025-05-14T21:02:22.984Z","repository":{"id":1867191,"uuid":"2792391","full_name":"gruns/furl","owner":"gruns","description":"🌐 URL parsing and manipulation made easy.","archived":false,"fork":false,"pushed_at":"2025-03-25T22:57:18.000Z","size":850,"stargazers_count":2680,"open_issues_count":40,"forks_count":158,"subscribers_count":36,"default_branch":"master","last_synced_at":"2025-05-04T22:37:36.983Z","etag":null,"topics":["library","manipulating-urls","python","python3","url","url-manipulation","url-parsing","urls"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"sonata-project/SonataCoreBundle","license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gruns.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.txt","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2011-11-17T01:08:16.000Z","updated_at":"2025-05-04T09:49:18.000Z","dependencies_parsed_at":"2023-02-17T21:46:00.706Z","dependency_job_id":"f0fcf76f-831c-4c04-9035-31a4fb94571a","html_url":"https://github.com/gruns/furl","commit_stats":{"total_commits":528,"total_committers":15,"mean_commits":35.2,"dds":"0.42992424242424243","last_synced_commit":"774846234ff803606fdd289a7549f9b50b2b3677"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gruns%2Ffurl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gruns%2Ffurl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gruns%2Ffurl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gruns%2Ffurl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gruns","download_url":"https://codeload.github.com/gruns/furl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252754050,"owners_count":21799046,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["library","manipulating-urls","python","python3","url","url-manipulation","url-parsing","urls"],"created_at":"2024-07-31T15:00:59.020Z","updated_at":"2025-05-07T07:41:46.416Z","avatar_url":"https://github.com/gruns.png","language":"Python","readme":"\u003ch1 align=\"center\"\u003e\n  \u003cimg src=\"logo.svg\" width=\"360px\" height=\"123px\" alt=\"furl\"\u003e\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pypi.python.org/pypi/furl\"\u003e\u003cimg src=\"https://badge.fury.io/py/furl.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/gruns/furl/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/gruns/furl/actions/workflows/ci.yml/badge.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"http://unlicense.org/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/l/furl.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pypi.python.org/pypi/furl\"\u003e\u003cimg src=\"https://img.shields.io/pypi/pyversions/furl.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## furl is a small Python library that makes parsing and\u003cbr\u003emanipulating URLs easy.\n\nPython's standard\n[urllib](https://docs.python.org/3/library/urllib.html) and\n[urlparse](https://docs.python.org/3/library/urllib.parse.html) modules\nprovide a number of URL related functions, but using these functions to\nperform common URL operations proves tedious. Furl makes parsing and\nmanipulating URLs easy.\n\nFurl is well tested, [Unlicensed](http://unlicense.org/) in the public\ndomain, and supports Python 3 and PyPy3.\n\n👥 Furl is looking for a lead contributor and maintainer. Would you love\nto lead furl, and making working with URLs a joy for everyone in Python?\nPlease [reach out](mailto:grunseid+icecream@gmail.com) and let me know! 🙌\n\nCode time: Paths and query arguments are easy. Really easy.\n\n```python\n\u003e\u003e\u003e from furl import furl\n\u003e\u003e\u003e f = furl('http://www.google.com/?one=1\u0026two=2')\n\u003e\u003e\u003e f /= 'path'\n\u003e\u003e\u003e del f.args['one']\n\u003e\u003e\u003e f.args['three'] = '3'\n\u003e\u003e\u003e f.url\n'http://www.google.com/path?two=2\u0026three=3'\n```\n\nOr use furl's inline modification methods.\n\n```python\n\u003e\u003e\u003e furl('http://www.google.com/?one=1').add({'two':'2'}).url\n'http://www.google.com/?one=1\u0026two=2'\n\n\u003e\u003e\u003e furl('http://www.google.com/?one=1\u0026two=2').set({'three':'3'}).url\n'http://www.google.com/?three=3'\n\n\u003e\u003e\u003e furl('http://www.google.com/?one=1\u0026two=2').remove(['one']).url\n'http://www.google.com/?two=2'\n```\n\nEncoding is handled for you. Unicode, too.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/')\n\u003e\u003e\u003e f.path = 'some encoding here'\n\u003e\u003e\u003e f.args['and some encoding'] = 'here, too'\n\u003e\u003e\u003e f.url\n'http://www.google.com/some%20encoding%20here?and+some+encoding=here,+too'\n\u003e\u003e\u003e f.set(host=u'ドメイン.テスト', path=u'джк', query=u'☃=☺')\n\u003e\u003e\u003e f.url\n'http://xn--eckwd4c7c.xn--zckzah/%D0%B4%D0%B6%D0%BA?%E2%98%83=%E2%98%BA'\n```\n\nFragments also have a path and a query.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/')\n\u003e\u003e\u003e f.fragment.path.segments = ['two', 'directories']\n\u003e\u003e\u003e f.fragment.args = {'one': 'argument'}\n\u003e\u003e\u003e f.url\n'http://www.google.com/#two/directories?one=argument'\n```\n\n## Installation\n\nInstalling furl with pip is easy.\n\n```\n$ pip install furl\n```\n\n\n## API\n\n  * [Basics](#basics)\n  * [Scheme, Username, Password, Host, Port, Network Location, and Origin](#scheme-username-password-host-port-network-location-and-origin)\n  * [Path](#path)\n    * [Manipulation](#manipulation)\n  * [Query](#query)\n    * [Manipulation](#manipulation-1)\n    * [Parameters](#parameters)\n  * [Fragment](#fragment)\n  * [Encoding](#encoding)\n  * [Inline manipulation](#inline-manipulation)\n  * [Miscellaneous](#miscellaneous)\n\n\n### Basics\n\nfurl objects let you access and modify the various components of a URL.\n\n```\nscheme://username:password@host:port/path?query#fragment\n```\n\n * __scheme__ is the scheme string (all lowercase) or None. None means no\n   scheme. An empty string means a protocol relative URL, like\n   `//www.google.com`.\n * __username__ is the username string for authentication.\n * __password__ is the password string for authentication with __username__.\n * __host__ is the domain name, IPv4, or IPv6 address as a string. Domain names\n  are all lowercase.\n * __port__ is an integer or None. A value of None means no port specified and\n  the default port for the given __scheme__ should be inferred, if possible\n  (e.g. port 80 for the scheme `http`).\n * __path__ is a Path object comprised of path segments.\n * __query__ is a Query object comprised of key:value query arguments.\n * __fragment__ is a Fragment object comprised of a Path object and Query object\n   separated by an optional `?` separator.\n\n\n\n### Scheme, Username, Password, Host, Port, Network Location, and Origin\n\n__scheme__, __username__, __password__, and __host__ are strings or\nNone. __port__ is an integer or None.\n\n```python\n\u003e\u003e\u003e f = furl('http://user:pass@www.google.com:99/')\n\u003e\u003e\u003e f.scheme, f.username, f.password, f.host, f.port\n('http', 'user', 'pass', 'www.google.com', 99)\n```\n\nfurl infers the default port for common schemes.\n\n```python\n\u003e\u003e\u003e f = furl('https://secure.google.com/')\n\u003e\u003e\u003e f.port\n443\n\n\u003e\u003e\u003e f = furl('unknown://www.google.com/')\n\u003e\u003e\u003e print(f.port)\nNone\n```\n\n__netloc__ is the string combination of __username__, __password__, __host__,\nand __port__, not including __port__ if it's None or the default port for the\nprovided __scheme__.\n\n```python\n\u003e\u003e\u003e furl('http://www.google.com/').netloc\n'www.google.com'\n\n\u003e\u003e\u003e furl('http://www.google.com:99/').netloc\n'www.google.com:99'\n\n\u003e\u003e\u003e furl('http://user:pass@www.google.com:99/').netloc\n'user:pass@www.google.com:99'\n```\n\n__origin__ is the string combination of __scheme__, __host__, and __port__, not\nincluding __port__ if it's None or the default port for the provided __scheme__.\n\n```python\n\u003e\u003e\u003e furl('http://www.google.com/').origin\n'http://www.google.com'\n\n\u003e\u003e\u003e furl('http://www.google.com:99/').origin\n'http://www.google.com:99'\n```\n\n\n\n### Path\n\nURL paths in furl are Path objects that have __segments__, a list of zero or\nmore path segments that can be manipulated directly. Path segments in\n__segments__ are percent-decoded and all interaction with __segments__ should\ntake place with percent-decoded strings.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/a/large%20ish/path')\n\u003e\u003e\u003e f.path\nPath('/a/large ish/path')\n\u003e\u003e\u003e f.path.segments\n['a', 'large ish', 'path']\n\u003e\u003e\u003e str(f.path)\n'/a/large%20ish/path'\n```\n\n#### Manipulation\n\n```python\n\u003e\u003e\u003e f.path.segments = ['a', 'new', 'path', '']\n\u003e\u003e\u003e str(f.path)\n'/a/new/path/'\n\n\u003e\u003e\u003e f.path = 'o/hi/there/with%20some%20encoding/'\n\u003e\u003e\u003e f.path.segments\n['o', 'hi', 'there', 'with some encoding', '']\n\u003e\u003e\u003e str(f.path)\n'/o/hi/there/with%20some%20encoding/'\n\n\u003e\u003e\u003e f.url\n'http://www.google.com/o/hi/there/with%20some%20encoding/'\n\n\u003e\u003e\u003e f.path.segments = ['segments', 'are', 'maintained', 'decoded', '^`\u003c\u003e[]\"#/?']\n\u003e\u003e\u003e str(f.path)\n'/segments/are/maintained/decoded/%5E%60%3C%3E%5B%5D%22%23%2F%3F'\n```\n\nA path that starts with `/` is considered absolute, and a Path can be absolute\nor not as specified (or set) by the boolean attribute __isabsolute__. URL Paths\nhave a special restriction: they must be absolute if a __netloc__ (username,\npassword, host, and/or port) is present. This restriction exists because a URL\npath must start with `/` to separate itself from the __netloc__, if\npresent. Fragment Paths have no such limitation and __isabsolute__ and can be\nTrue or False without restriction.\n\nHere's a URL Path example that illustrates how __isabsolute__ becomes True and\nread-only in the presence of a __netloc__.\n\n```python\n\u003e\u003e\u003e f = furl('/url/path')\n\u003e\u003e\u003e f.path.isabsolute\nTrue\n\u003e\u003e\u003e f.path.isabsolute = False\n\u003e\u003e\u003e f.url\n'url/path'\n\u003e\u003e\u003e f.host = 'blaps.ru'\n\u003e\u003e\u003e f.url\n'blaps.ru/url/path'\n\u003e\u003e\u003e f.path.isabsolute\nTrue\n\u003e\u003e\u003e f.path.isabsolute = False\nTraceback (most recent call last):\n  ...\nAttributeError: Path.isabsolute is True and read-only for URLs with a netloc (a username, password, host, and/or port). URL paths must be absolute if a netloc exists.\n\u003e\u003e\u003e f.url\n'blaps.ru/url/path'\n```\n\nConversely, the __isabsolute__ attribute of Fragment Paths isn't bound by the\nsame read-only restriction. URL fragments are always prefixed by a `#` character\nand don't need to be separated from the __netloc__.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/#/absolute/fragment/path/')\n\u003e\u003e\u003e f.fragment.path.isabsolute\nTrue\n\u003e\u003e\u003e f.fragment.path.isabsolute = False\n\u003e\u003e\u003e f.url\n'http://www.google.com/#absolute/fragment/path/'\n\u003e\u003e\u003e f.fragment.path.isabsolute = True\n\u003e\u003e\u003e f.url\n'http://www.google.com/#/absolute/fragment/path/'\n```\n\nA path that ends with `/` is considered a directory, and otherwise considered a\nfile. The Path attribute __isdir__ returns True if the path is a directory,\nFalse otherwise. Conversely, the attribute __isfile__ returns True if the path\nis a file, False otherwise.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/a/directory/')\n\u003e\u003e\u003e f.path.isdir\nTrue\n\u003e\u003e\u003e f.path.isfile\nFalse\n\n\u003e\u003e\u003e f = furl('http://www.google.com/a/file')\n\u003e\u003e\u003e f.path.isdir\nFalse\n\u003e\u003e\u003e f.path.isfile\nTrue\n```\n\nA path can be normalized with __normalize()__, and __normalize()__ returns the\nPath object for method chaining.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com////a/./b/lolsup/../c/')\n\u003e\u003e\u003e f.path.normalize()\n\u003e\u003e\u003e f.url\n'http://www.google.com/a/b/c/'\n```\n\nPath segments can also be appended with the slash operator, like with\n[pathlib.Path](https://docs.python.org/3/library/pathlib.html#operators).\n\n```python\n\u003e\u003e\u003e from __future__ import division  # For Python 2.x.\n\u003e\u003e\u003e\n\u003e\u003e\u003e f = furl('path')\n\u003e\u003e\u003e f.path /= 'with'\n\u003e\u003e\u003e f.path = f.path / 'more' / 'path segments/'\n\u003e\u003e\u003e f.url\n'/path/with/more/path%20segments/'\n```\n\nFor a dictionary representation of a path, use __asdict()__.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/some/enc%20oding')\n\u003e\u003e\u003e f.path.asdict()\n{ 'encoded': '/some/enc%20oding',\n  'isabsolute': True,\n  'isdir': False,\n  'isfile': True,\n  'segments': ['some', 'enc oding'] }\n```\n\n\n\n### Query\n\nURL queries in furl are Query objects that have __params__, a one dimensional\n[ordered multivalue dictionary](https://github.com/gruns/orderedmultidict) of\nquery keys and values. Query keys and values in __params__ are percent-decoded\nand all interaction with __params__ should take place with percent-decoded\nstrings.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/?one=1\u0026two=2')\n\u003e\u003e\u003e f.query\nQuery('one=1\u0026two=2')\n\u003e\u003e\u003e f.query.params\nomdict1D([('one', '1'), ('two', '2')])\n\u003e\u003e\u003e str(f.query)\n'one=1\u0026two=2'\n```\n\nfurl objects and Fragment objects (covered below) contain a Query object, and\n__args__ is provided as a shortcut on these objects to access __query.params__.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/?one=1\u0026two=2')\n\u003e\u003e\u003e f.query.params\nomdict1D([('one', '1'), ('two', '2')])\n\u003e\u003e\u003e f.args\nomdict1D([('one', '1'), ('two', '2')])\n\u003e\u003e\u003e f.args is f.query.params\nTrue\n```\n\n#### Manipulation\n\n__params__ is a one dimensional\n[ordered multivalue dictionary](https://github.com/gruns/orderedmultidict) that\nmaintains method parity with Python's standard dictionary.\n\n```python\n\u003e\u003e\u003e f.query = 'silicon=14\u0026iron=26\u0026inexorable%20progress=vae%20victus'\n\u003e\u003e\u003e f.query.params\nomdict1D([('silicon', '14'), ('iron', '26'), ('inexorable progress', 'vae victus')])\n\u003e\u003e\u003e del f.args['inexorable progress']\n\u003e\u003e\u003e f.args['magnesium'] = '12'\n\u003e\u003e\u003e f.args\nomdict1D([('silicon', '14'), ('iron', '26'), ('magnesium', '12')])\n```\n\n__params__ can also store multiple values for the same key because it's a\nmultivalue dictionary.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/?space=jams\u0026space=slams')\n\u003e\u003e\u003e f.args['space']\n'jams'\n\u003e\u003e\u003e f.args.getlist('space')\n['jams', 'slams']\n\u003e\u003e\u003e f.args.addlist('repeated', ['1', '2', '3'])\n\u003e\u003e\u003e str(f.query)\n'space=jams\u0026space=slams\u0026repeated=1\u0026repeated=2\u0026repeated=3'\n\u003e\u003e\u003e f.args.popvalue('space')\n'slams'\n\u003e\u003e\u003e f.args.popvalue('repeated', '2')\n'2'\n\u003e\u003e\u003e str(f.query)\n'space=jams\u0026repeated=1\u0026repeated=3'\n```\n\n__params__ is one dimensional. If a list of values is provided as a query value,\nthat list is interpreted as multiple values.\n\n```python\n\u003e\u003e\u003e f = furl()\n\u003e\u003e\u003e f.args['repeated'] = ['1', '2', '3']\n\u003e\u003e\u003e f.add(args={'space':['jams', 'slams']})\n\u003e\u003e\u003e str(f.query)\n'repeated=1\u0026repeated=2\u0026repeated=3\u0026space=jams\u0026space=slams'\n```\n\nThis makes sense: URL queries are inherently one dimensional -- query values\ncan't have native subvalues.\n\nSee the [orderedmultimdict](https://github.com/gruns/orderedmultidict)\ndocumentation for more information on interacting with the ordered multivalue\ndictionary __params__.\n\n#### Parameters\n\nTo produce an empty query argument, like `http://sprop.su/?param=`, set the\nargument's value to the empty string.\n\n```python\n\u003e\u003e\u003e f = furl('http://sprop.su')\n\u003e\u003e\u003e f.args['param'] = ''\n\u003e\u003e\u003e f.url\n'http://sprop.su/?param='\n```\n\nTo produce an empty query argument without a trailing `=`, use `None` as the\nparameter value.\n\n```python\n\u003e\u003e\u003e f = furl('http://sprop.su')\n\u003e\u003e\u003e f.args['param'] = None\n\u003e\u003e\u003e f.url\n'http://sprop.su/?param'\n```\n\n__encode(delimiter='\u0026', quote_plus=True, dont_quote='')__ can be used to encode\nquery strings with delimiters like `;`, encode spaces as `+` instead of `%20`\n(i.e. application/x-www-form-urlencoded encoded), or avoid percent-encoding\nvalid query characters entirely (valid query characters are\n`/?:@-._~!$\u0026'()*+,;=`).\n\n```python\n\u003e\u003e\u003e f.query = 'space=jams\u0026woofs=squeeze+dog'\n\u003e\u003e\u003e f.query.encode()\n'space=jams\u0026woofs=squeeze+dog'\n\u003e\u003e\u003e f.query.encode(';')\n'space=jams;woofs=squeeze+dog'\n\u003e\u003e\u003e f.query.encode(quote_plus=False)\n'space=jams\u0026woofs=squeeze%20dog'\n```\n\n`dont_quote` accepts `True`, `False`, or a string of valid query characters to\nnot percent-enode. If `True`, all valid query characters `/?:@-._~!$\u0026'()*+,;=`\naren't percent-encoded.\n\n```python\n\u003e\u003e\u003e f.query = 'one,two/three'\n\u003e\u003e\u003e f.query.encode()\n'one%2Ctwo%2Fthree'\n\u003e\u003e\u003e f.query.encode(dont_quote=True)\n'one,two/three'\n\u003e\u003e\u003e f.query.encode(dont_quote=',')\n'one,two%2Fthree'\n```\n\nFor a dictionary representation of a query, use __asdict()__.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/?space=ja+ms\u0026space=slams')\n\u003e\u003e\u003e f.query.asdict()\n{ 'encoded': 'space=ja+ms\u0026space=slams',\n  'params': [('space', 'ja ms'),\n             ('space', 'slams')] }\n```\n\n\n\n### Fragment\n\nURL fragments in furl are Fragment objects that have a Path __path__ and Query\n__query__ separated by an optional `?` __separator__.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/#/fragment/path?with=params')\n\u003e\u003e\u003e f.fragment\nFragment('/fragment/path?with=params')\n\u003e\u003e\u003e f.fragment.path\nPath('/fragment/path')\n\u003e\u003e\u003e f.fragment.query\nQuery('with=params')\n\u003e\u003e\u003e f.fragment.separator\nTrue\n```\n\nManipulation of Fragments is done via the Fragment's Path and Query instances,\n__path__ and __query__.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/#/fragment/path?with=params')\n\u003e\u003e\u003e str(f.fragment)\n'/fragment/path?with=params'\n\u003e\u003e\u003e f.fragment.path.segments.append('file.ext')\n\u003e\u003e\u003e str(f.fragment)\n'/fragment/path/file.ext?with=params'\n\n\u003e\u003e\u003e f = furl('http://www.google.com/#/fragment/path?with=params')\n\u003e\u003e\u003e str(f.fragment)\n'/fragment/path?with=params'\n\u003e\u003e\u003e f.fragment.args['new'] = 'yep'\n\u003e\u003e\u003e str(f.fragment)\n'/fragment/path?new=yep\u0026with=params'\n```\n\nCreating hash-bang fragments with furl illustrates the use of Fragment's boolean\nattribute __separator__. When __separator__ is False, the `?` that separates\n__path__ and __query__ isn't included.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/')\n\u003e\u003e\u003e f.fragment.path = '!'\n\u003e\u003e\u003e f.fragment.args = {'a':'dict', 'of':'args'}\n\u003e\u003e\u003e f.fragment.separator\nTrue\n\u003e\u003e\u003e str(f.fragment)\n'!?a=dict\u0026of=args'\n\n\u003e\u003e\u003e f.fragment.separator = False\n\u003e\u003e\u003e str(f.fragment)\n'!a=dict\u0026of=args'\n\u003e\u003e\u003e f.url\n'http://www.google.com/#!a=dict\u0026of=args'\n```\n\nFor a dictionary representation of a fragment, use __asdict()__.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/#path?args=args')\n\u003e\u003e\u003e f.fragment.asdict()\n{ 'encoded': 'path?args=args',\n  'separator': True,\n  'path': { 'encoded': 'path',\n            'isabsolute': False,\n            'isdir': False,\n            'isfile': True,\n            'segments': ['path']},\n  'query': { 'encoded': 'args=args',\n             'params': [('args', 'args')]} }\n```\n\n\n\n### Encoding\n\nFurl handles encoding for you, and furl's philosophy on encoding is simple: raw\nURL strings should always be percent-encoded.\n\n```python\n\u003e\u003e\u003e f = furl()\n\u003e\u003e\u003e f.netloc = '%40user:%3Apass@google.com'\n\u003e\u003e\u003e f.username, f.password\n'@user', ':pass'\n\n\u003e\u003e\u003e f = furl()\n\u003e\u003e\u003e f.path = 'supply%20percent%20encoded/path%20strings'\n\u003e\u003e\u003e f.path.segments\n['supply percent encoded', 'path strings']\n\n\u003e\u003e\u003e f.set(query='supply+percent+encoded=query+strings,+too')\n\u003e\u003e\u003e f.query.params\nomdict1D([('supply percent encoded', 'query strings, too')])\n\n\u003e\u003e\u003e f.set(fragment='percent%20encoded%20path?and+percent+encoded=query+too')\n\u003e\u003e\u003e f.fragment.path.segments\n['percent encoded path']\n\u003e\u003e\u003e f.fragment.args\nomdict1D([('and percent encoded', 'query too')])\n```\n\nRaw, non-URL strings should never be percent-encoded.\n\n```python\n\u003e\u003e\u003e f = furl('http://google.com')\n\u003e\u003e\u003e f.set(username='@prap', password=':porps')\n\u003e\u003e\u003e f.url\n'http://%40prap:%3Aporps@google.com'\n\n\u003e\u003e\u003e f = furl()\n\u003e\u003e\u003e f.set(path=['path segments are', 'decoded', '\u003c\u003e[]\"#'])\n\u003e\u003e\u003e str(f.path)\n'/path%20segments%20are/decoded/%3C%3E%5B%5D%22%23'\n\n\u003e\u003e\u003e f.set(args={'query parameters':'and values', 'are':'decoded, too'})\n\u003e\u003e\u003e str(f.query)\n'query+parameters=and+values\u0026are=decoded,+too'\n\n\u003e\u003e\u003e f.fragment.path.segments = ['decoded', 'path segments']\n\u003e\u003e\u003e f.fragment.args = {'and decoded':'query parameters and values'}\n\u003e\u003e\u003e str(f.fragment)\n'decoded/path%20segments?and+decoded=query+parameters+and+values'\n```\n\nPython's\n[urllib.quote()](http://docs.python.org/library/urllib.html#urllib.quote) and\n[urllib.unquote()](http://docs.python.org/library/urllib.html#urllib.unquote)\ncan be used to percent-encode and percent-decode path strings. Similarly,\n[urllib.quote_plus()](http://docs.python.org/library/urllib.html#urllib.quote_plus)\nand\n[urllib.unquote_plus()](http://docs.python.org/library/urllib.html#urllib.unquote_plus)\ncan be used to percent-encode and percent-decode query strings.\n\n\n\n### Inline manipulation\n\nFor quick, single-line URL manipulation, the __add()__, __set()__, and\n__remove()__ methods of furl objects manipulate various URL components and\nreturn the furl object for method chaining.\n\n```python\n\u003e\u003e\u003e url = 'http://www.google.com/#fragment' \n\u003e\u003e\u003e furl(url).add(args={'example':'arg'}).set(port=99).remove(fragment=True).url\n'http://www.google.com:99/?example=arg'\n```\n\n__add()__ adds items to a furl object with the optional arguments\n\n * __args__: Shortcut for __query_params__.\n * __path__: A list of path segments to add to the existing path segments, or a\n   path string to join with the existing path string.\n * __query_params__: A dictionary of query keys and values to add to the query.\n * __fragment_path__: A list of path segments to add to the existing fragment\n   path segments, or a path string to join with the existing fragment path\n   string.\n * __fragment_args__: A dictionary of query keys and values to add to the\n   fragment's query.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com/').add(\n...   path='/search', fragment_path='frag/path', fragment_args={'frag':'arg'})\n\u003e\u003e\u003e f.url\n'http://www.google.com/search#frag/path?frag=args'\n```\n\n__set()__ sets items of a furl object with the optional arguments\n\n * __args__: Shortcut for __query_params__.\n * __path__: List of path segments or a path string to adopt.\n * __scheme__: Scheme string to adopt.\n * __netloc__: Network location string to adopt.\n * __origin__: Origin string to adopt.\n * __query__: Query string to adopt.\n * __query_params__: A dictionary of query keys and values to adopt.\n * __fragment__: Fragment string to adopt.\n * __fragment_path__: A list of path segments to adopt for the fragment's path\n   or a path string to adopt as the fragment's path.\n * __fragment_args__: A dictionary of query keys and values for the fragment's\n   query to adopt.\n * __fragment_separator__: Boolean whether or not there should be a `?`\n   separator between the fragment path and the fragment query.\n * __host__: Host string to adopt.\n * __port__: Port number to adopt.\n * __username__: Username string to adopt.\n * __password__: password string to adopt.\n\n\n```python\n\u003e\u003e\u003e f = furl().set(\n...   scheme='https', host='secure.google.com', port=99, path='index.html',\n...   args={'some':'args'}, fragment='great job')\n\u003e\u003e\u003e f.url\n'https://secure.google.com:99/index.html?some=args#great%20job'\n```\n\n__remove()__ removes items from a furl object with the optional arguments\n\n * __args__: Shortcut for __query_params__.\n * __path__: A list of path segments to remove from the end of the existing path\n       segments list, or a path string to remove from the end of the existing\n       path string, or True to remove the entire path portion of the URL.\n * __query__: A list of query keys to remove from the query, if they exist, or\n       True to remove the entire query portion of the URL.\n * __query_params__: A list of query keys to remove from the query, if they\n       exist.\n * __fragment__: If True, remove the entire fragment portion of the URL.\n * __fragment_path__: A list of path segments to remove from the end of the\n       fragment's path segments, or a path string to remove from the end of the\n       fragment's path string, or True to remove the entire fragment path.\n * __fragment_args__: A list of query keys to remove from the fragment's query,\n       if they exist.\n * __username__: If True, remove the username, if it exists.\n * __password__: If True, remove the password, if it exists.\n\n\n```python\n\u003e\u003e\u003e url = 'https://secure.google.com:99/a/path/?some=args#great job'\n\u003e\u003e\u003e furl(url).remove(args=['some'], path='path/', fragment=True, port=True).url\n'https://secure.google.com/a/'\n```\n\n\n\n### Miscellaneous\n\nLike [pathlib.Path](https://docs.python.org/3/library/pathlib.html#operators),\npath segments can be appended to a furl object's Path with the slash operator.\n\n```python\n\u003e\u003e\u003e from __future__ import division  # For Python 2.x.\n\u003e\u003e\u003e f = furl('http://www.google.com/path?example=arg#frag')\n\u003e\u003e\u003e f /= 'add'\n\u003e\u003e\u003e f = f / 'seg ments/'\n\u003e\u003e\u003e f.url\n'http://www.google.com/path/add/seg%20ments/?example=arg#frag'\n```\n\n__tostr(query_delimiter='\u0026', query_quote_plus=True, query_dont_quote='')__\ncreates and returns a URL string. `query_delimiter`, `query_quote_plus`, and\n`query_dont_quote` are passed unmodified to `Query.encode()` as `delimiter`,\n`quote_plus`, and `dont_quote` respectively.\n\n```python\n\u003e\u003e\u003e f = furl('http://spep.ru/?a+b=c+d\u0026two%20tap=cat%20nap%24')\n\u003e\u003e\u003e f.tostr()\n'http://spep.ru/?a+b=c+d\u0026two+tap=cat+nap$'\n\u003e\u003e\u003e f.tostr(query_delimiter=';', query_quote_plus=False)\n'http://spep.ru/?a%20b=c%20d;two%20tap=cat%20nap$'\n\u003e\u003e\u003e f.tostr(query_dont_quote='$')\n'http://spep.ru/?a+b=c+d\u0026two+tap=cat+nap$'\n```\n\n`furl.url` is a shortcut for `furl.tostr()`.\n\n```python\n\u003e\u003e\u003e f.url\n'http://spep.ru/?a+b=c+d\u0026two+tap=cat+nap$'\n\u003e\u003e\u003e f.url == f.tostr() == str(f)\nTrue\n```\n\n__copy()__ creates and returns a new furl object with an identical URL.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com')\n\u003e\u003e\u003e f.copy().set(path='/new/path').url\n'http://www.google.com/new/path'\n\u003e\u003e\u003e f.url\n'http://www.google.com'\n```\n\n__join()__ joins the furl object's URL with the provided relative or absolute\nURL and returns the furl object for method chaining. __join()__'s action is the\nsame as navigating to the provided URL from the current URL in a web browser.\n\n```python\n\u003e\u003e\u003e f = furl('http://www.google.com')\n\u003e\u003e\u003e f.join('new/path').url\n'http://www.google.com/new/path'\n\u003e\u003e\u003e f.join('replaced').url\n'http://www.google.com/new/replaced'\n\u003e\u003e\u003e f.join('../parent').url\n'http://www.google.com/parent'\n\u003e\u003e\u003e f.join('path?query=yes#fragment').url\n'http://www.google.com/path?query=yes#fragment'\n\u003e\u003e\u003e f.join('unknown://www.yahoo.com/new/url/').url\n'unknown://www.yahoo.com/new/url/'\n```\n\nFor a dictionary representation of a URL, use __asdict()__.\n\n```python\n\u003e\u003e\u003e f = furl('https://xn--eckwd4c7c.xn--zckzah/path?args=args#frag')\n\u003e\u003e\u003e f.asdict()\n{ 'url': 'https://xn--eckwd4c7c.xn--zckzah/path?args=args#frag',\n  'scheme': 'https',\n  'username': None\n  'password': None,\n  'host': 'ドメイン.テスト',\n  'host_encoded': 'xn--eckwd4c7c.xn--zckzah',\n  'port': 443,\n  'netloc': 'xn--eckwd4c7c.xn--zckzah',\n  'origin': 'https://xn--eckwd4c7c.xn--zckzah',\n  'path': { 'encoded': '/path',\n            'isabsolute': True,\n            'isdir': False,\n            'isfile': True,\n            'segments': ['path']},\n  'query': { 'encoded': 'args=args',\n             'params': [('args', 'args')]},\n  'fragment': { 'encoded': 'frag',\n                'path': { 'encoded': 'frag',\n                          'isabsolute': False,\n                          'isdir': False,\n                          'isfile': True,\n                          'segments': ['frag']},\n                'query': { 'encoded': '',\n                           'params': []},\n                'separator': True} }\n```\n","funding_links":[],"categories":["URL Manipulation","Python","资源列表","URL操作","URL 处理","URL Utilities","URL Manipulation [🔝](#readme)","Awesome Python"],"sub_categories":["URL 处理","URL Manipulation"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgruns%2Ffurl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgruns%2Ffurl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgruns%2Ffurl/lists"}