{"id":16544794,"url":"https://github.com/synchronizing/toolbox","last_synced_at":"2025-03-21T10:31:33.133Z","repository":{"id":36970463,"uuid":"326564232","full_name":"synchronizing/toolbox","owner":"synchronizing","description":"🧰 ‎‎‎‏‏  Small (~0.2MB) set of tools to expand the PSL.","archived":false,"fork":false,"pushed_at":"2023-10-18T05:26:33.000Z","size":255,"stargazers_count":12,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-01T05:12:22.051Z","etag":null,"topics":["python3","toolbox"],"latest_commit_sha":null,"homepage":"https://synchronizing.github.io/toolbox/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/synchronizing.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-01-04T03:58:08.000Z","updated_at":"2023-10-13T04:56:26.000Z","dependencies_parsed_at":"2022-07-29T00:48:01.962Z","dependency_job_id":"7a1c3ee7-2486-4b8a-b3b2-24bf42bd08d8","html_url":"https://github.com/synchronizing/toolbox","commit_stats":{"total_commits":51,"total_committers":1,"mean_commits":51.0,"dds":0.0,"last_synced_commit":"b3be4ed8b4b54fc71268a7e6efd30238ef9bcc62"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synchronizing%2Ftoolbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synchronizing%2Ftoolbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synchronizing%2Ftoolbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/synchronizing%2Ftoolbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/synchronizing","download_url":"https://codeload.github.com/synchronizing/toolbox/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244777876,"owners_count":20508803,"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":["python3","toolbox"],"created_at":"2024-10-11T19:04:40.856Z","updated_at":"2025-03-21T10:31:32.773Z","avatar_url":"https://github.com/synchronizing.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🧰 Toolbox\n\n\u003cp align=\"center\"\u003e\n\n  \u003ca href=\"https://www.pepy.tech/projects/toolbox\"\u003e\n    \u003cimg src=\"https://static.pepy.tech/badge/toolbox\"\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://github.com/synchronizing/toolbox/actions?query=workflow%3ABuild\"\u003e\n    \u003cimg src=\"https://github.com/synchronizing/toolbox/workflows/Build/badge.svg?branch=master\u0026event=push\"\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://synchronizing.github.io/toolbox/\"\u003e\n    \u003cimg src=\"https://github.com/synchronizing/toolbox/workflows/Docs/badge.svg?branch=master\u0026event=push\"\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://coveralls.io/github/synchronizing/toolbox?branch=master\"\u003e\n    \u003cimg src=\"https://coveralls.io/repos/github/synchronizing/toolbox/badge.svg?branch=master\"\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nToolbox is a small (~0.2MB) set of tools that expands the [Python Standard Library](https://docs.python.org/3/library/).\n\n## Installing\n\n```\npip install toolbox\n```\n\n## Documentation\n\nDocumentation can be found [**here**](http://synchronizing.github.io/toolbox/).\n\n## Tools\n\n### `asyncio`\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/asyncio.html#toolbox.asyncio.cache.future_lru_cache\"\u003e\u003ccode\u003efuture_lru_cache\u003c/code\u003e\u003c/a\u003e — \u003ccode\u003elru_cache\u003c/code\u003e for async functions.\u003c/summary\u003e\u003cbr\u003e\n  \n```python\nfrom toolbox import future_lru_cache\nimport asyncio\n\n@future_lru_cache\nasync def func():\n    await asyncio.sleep(10)\n    return 42\n\nasync def main():\n    await func() # Runs once.\n    await func() # Returns cached value.\n\nasyncio.run(main())\n````\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/asyncio.html#toolbox.asyncio.threads.to_thread\"\u003e\u003ccode\u003eto_thread\u003c/code\u003e\u003c/a\u003e — Run a synchronous function in a separate thread.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import to_thread\nimport asyncio\nimport time\n\ndef func():\n    time.sleep(2)\n    return \"Hello world\"\n\nasync def main():\n    await to_thread(func)\n\nasyncio.run(main())\n````\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/asyncio.html#toolbox.asyncio.threads.awaitable\"\u003e\u003ccode\u003eawaitable\u003c/code\u003e\u003c/a\u003e — Convert synchronous function to an async function via thread.\u003c/summary\u003e\u003cbr\u003e\n  \nLeverages the `to_thread` function above.\n\n```python\nfrom toolbox import awaitable\nimport asyncio\nimport time\n\n@awaitable\ndef func():\n    time.sleep(2)\n    return \"Hello world\"\n\nasync def main():\n    await func()\n\nasyncio.run(func())\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/asyncio.html#toolbox.asyncio.streams.tls_handshake\"\u003e\u003ccode\u003etls_handshake\u003c/code\u003e\u003c/a\u003e — Perform TLS handshake with a stream reader \u0026 writer.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import tls_handshake\nimport asyncio\n\nasync def client():\n    reader, writer = await asyncio.open_connection(\"httpbin.org\", 443, ssl=False)\n    await tls_handshake(reader=reader, writer=writer)\n\n    # Communication is now encrypted.\n\nasyncio.run(client())\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/asyncio.html#toolbox.asyncio.pattern.CoroutineClass\"\u003e\u003ccode\u003eCoroutineClass\u003c/code\u003e\u003c/a\u003e — Class pattern for implementing object-based coroutines. \u003c/summary\u003e\u003cbr\u003e\n  \nPattern for creating a coroutine-like class that has multiple ways to start it.\n\n```python\nfrom toolbox import CoroutineClass\nimport asyncio\n\nclass Coroutine(CoroutineClass):\n    def __init__(self, run: bool = False):\n        super().__init__(run=run)\n\n    # Default entry function.\n    async def entry(self):\n        await asyncio.sleep(1)\n        return \"Hello world\"\n\n# Start coroutine outside Python async context.\ndef iomain():\n\n    # via __init__\n    coro = Coroutine(run=True)\n    print(coro.result)  # Hello world\n\n    # via .run()\n    coro = Coroutine()\n    result = coro.run()\n    print(result)  # Hello world\n\n# Start coroutine inside Python async context.\nasync def aiomain():\n\n    # via __init__\n    coro = Coroutine(run=True)\n    await asyncio.sleep(1)\n    coro.stop()\n    print(coro.result)  # None - because process was stopped before completion.\n\n    # via .run()\n    coro = Coroutine()\n    coro.run()\n    await asyncio.sleep(1)\n    result = coro.stop()  # None - because coroutine was stopped before completion.\n    print(result)  # Hello world\n\n    # via await\n    coro = Coroutine()\n    result = await coro  # You can also start, and await later.\n    print(result)  # Hello World\n\n    # via context manager\n    async with Coroutine() as coro:\n        result = await coro\n    print(result)  # Hello World\n```\n\u003c/details\u003e\n\n### `builtins`\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/builtins.html#toolbox.builtins.property.classproperty\"\u003e\u003ccode\u003eclassproperty\u003c/code\u003e\u003c/a\u003e — Decorator for defining a method as a property and classmethod.\u003c/summary\u003e\u003cbr\u003e\n\nAllows access to computed class attributes.\n\n```python\nfrom toolbox import classproperty\n\nclass Animal:\n    @classproperty\n    def dog(cls):\n        return \"whoof!\"\n\nprint(Animal.dog) #  'whoof!'\n```\n\u003c/details\u003e\n\n### `collections`\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/collections.html#toolbox.collections.item.Item\"\u003e\u003ccode\u003eItem\u003c/code\u003e\u003c/a\u003e — An interface for type-agnostic operations between different types.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import Item\n\nitem = Item(100)\nprint(item == b\"100\" == \"100\" == 100) #  True\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/collections.html#toolbox.collections.namedtuple.nestednamedtuple\"\u003e\u003ccode\u003enestednamedtuple\u003c/code\u003e\u003c/a\u003e — Creates a nested \u003ccode\u003enamedtuple\u003c/code\u003e.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import nestednamedtuple\n\nnt = nestednamedtuple({\"hello\": {\"ola\": \"mundo\"}})\nprint(nt)           #  namedtupled(hello=namedtupled(ola='mundo'))\nprint(nt.hello.ola) #  mundo\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/collections.html#toolbox.collections.namedtuple.fdict\"\u003e\u003ccode\u003efdict\u003c/code\u003e\u003c/a\u003e — Forces \u003ccode\u003enestednamedtuple\u003c/code\u003e to not convert \u003ccode\u003edict\u003c/code\u003e to \u003ccode\u003enamedtuple\u003c/code\u003e. \u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import nestednamedtuple, fdict\n\nd = {\"hello\": \"world\"}\nnt = nestednamedtuple({\"forced\": fdict(d), \"notforced\": d})\n\nprint(nt.notforced) #  namedtupled(hello='world')\nprint(nt.forced)    #  {'hello': 'world'}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/collections.html#toolbox.collections.mapping.BidirectionalDict\"\u003e\u003ccode\u003eBidirectionalDict\u003c/code\u003e\u003c/a\u003e — Dictionary with two-way capabilities.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import BidirectionalDict\n\nd = BidirectionalDict({\"hello\": \"world\"})\nprint(d) #  {'hello': 'world', 'world': 'hello'}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/collections.html#toolbox.collections.mapping.ObjectDict\"\u003e\u003ccode\u003eObjectDict\u003c/code\u003e\u003c/a\u003e — Dictionary that can be accessed as though it was an object.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import ObjectDict\n\nd = ObjectDict({\"hello\": \"world\"})\nprint(d.hello) #  'world'\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/collections.html#toolbox.collections.mapping.OverloadedDict\"\u003e\u003ccode\u003eOverloadedDict\u003c/code\u003e\u003c/a\u003e — Dictionary that can be added or subtracted to.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import OverloadedDict\n\nd1 = OverloadedDict({\"hello\": \"world\"})\nd2 = OverloadedDict({\"ola\": \"mundo\"})\n\nd1 += d2\nprint(d1) #  {'hello': 'world', 'ola': 'mundo'}\n\nd1 -= d2\nprint(d1) #  {'hello': 'world'}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/collections.html#toolbox.collections.mapping.UnderscoreAccessDict\"\u003e\u003ccode\u003eUnderscoreAccessDict\u003c/code\u003e\u003c/a\u003e — Dictionary with underscore access.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import UnderscoreAccessDict\n\nd = UnderscoreAccessDict({\"hello\": \"world\"})\nprint(d.hello) #  'world'\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/collections.html#toolbox.collections.mapping.FrozenDict\"\u003e\u003ccode\u003eFrozenDict\u003c/code\u003e\u003c/a\u003e — Dictionary that is frozen.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import FrozenDict\n\nd = FrozenDict({\"hello\": \"world\"})\nd[\"hello\"] = \"mundo\" # KeyError: Cannot set key and value because this is a frozen dictionary.\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/collections.html#toolbox.collections.mapping.MultiEntryDict\"\u003e\u003ccode\u003eMultiEntryDict\u003c/code\u003e\u003c/a\u003e — Dictionary that can have multiple entries for the same key.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import MultiEntryDict\n\nd = MultiEntryDict({\"hello\": \"world\"})\nd[\"hello\"] = \"mundo\"\nprint(d) #  {'hello': ['world', 'mundo']}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/collections.html#toolbox.collections.mapping.ItemDict\"\u003e\u003ccode\u003eItemDict\u003c/code\u003e\u003c/a\u003e — Dictionary that utilizes \u003ca href=\"#Item\"\u003e\u003ccode\u003eItem\u003c/code\u003e\u003c/a\u003e for key and values.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import ItemDict, Item\n\nd = ItemDict({\"100\": \"one hundred\"})\nprint(d[100])                                          #  one hundred\nprint(d[100] == d['100'] == d[b'100'] == d[Item(100)]) #  True\n```\n\u003c/details\u003e\n\nAll `*Dict` types above can be combined together (as mixins) to create unique dictionary types.\n\n### `config`\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/config.html#toolbox.config.globalconfig.make_config\"\u003e\u003ccode\u003emake_config\u003c/code\u003e\u003c/a\u003e — Stores configuration dictionary in-memory.\u003c/summary\u003e\u003cbr\u003e\n\nCreates a global configuration that can be accessed by other portions of the code via `conf` or `config` function calls. Minimizes the need to create `Config` objects and pass them around different modules, classes, functions, etc.\n\n```python\nfrom toolbox import make_config\n\nmake_config(hello=\"world\")\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/config.html#toolbox.config.globalconfig.config\"\u003e\u003ccode\u003econfig\u003c/code\u003e\u003c/a\u003e — Access in-memory configuration as dictionary.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import config\n\nprint(config()['hello']) #  'world'\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/config.html#toolbox.config.globalconfig.conf\"\u003e\u003ccode\u003econf\u003c/code\u003e\u003c/a\u003e — Access in-memory configuration as \u003ccode\u003enestednametuple\u003c/code\u003e.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import conf\n\nprint(conf().hello) #  'world'\n```\n\u003c/details\u003e\n\n### `functools`\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/functools.html#toolbox.functools.timeout.timeout\"\u003e\u003ccode\u003etimeout\u003c/code\u003e\u003c/a\u003e — Decorator to add timeout for synchronous and asychronous functions.\u003c/summary\u003e\u003cbr\u003e\n\nDecorator that adds support for synchronous and asynchronous function timeout. Quits function after an amount of time passes.\n\n```python\nfrom toolbox import timeout\nimport asyncio\nimport time\n\n@timeout(seconds=1)\ndef func():\n    time.sleep(15)\n\n@timeout(seconds=1)\nasync def func():\n    await asyncio.sleep(15)\n```\n\u003c/details\u003e\n\n### `pdb`\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/pdb.html#toolbox.pdb.sprinke.sprinkle\"\u003e\u003ccode\u003esprinkle\u003c/code\u003e\u003c/a\u003e —  Prints the line and file that this function was just called from.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox.pdb.sprinkle import sprinkle\n\nsprinkle() # \u003e\u003e\u003e 3 this_file.py\nsprinkle(\"hello\", \"world\") # \u003e\u003e\u003e 4 this_file.py hello world\n```\n\u003c/details\u003e\n\n### `pkgutil`\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/pkgutil.html#toolbox.pkgutil.package.search_package\"\u003e\u003ccode\u003esearch_package\u003c/code\u003e\u003c/a\u003e — Searches for packages installed in the system.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import search_package\n\nprint(search_package(\"toolbox\", method=\"is\"))\n#  {'toolbox': \u003cmodule 'toolbox' from '.../toolbox/__init__.py'\u003e}\n```\n\u003c/details\u003e\n\n### `sockets`\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/sockets.html#toolbox.sockets.ip.is_ip\"\u003e\u003ccode\u003eis_ip\u003c/code\u003e\u003c/a\u003e — Checks if a string is an IP address.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import is_ip\n\nprint(is_ip('127.0.0.1')) # True\nprint(is_ip('localhost')) # False\n```\n\u003c/details\u003e\n\n### `string`\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/string.html#color\"\u003eANSI Formatting\u003c/a\u003e — Color formatting.\u003c/summary\u003e\u003cbr\u003e\n\nCheck documentation [here](https://synchronizing.github.io/toolbox/module/string.html#color) for further information on all built-in formats.\n\n```python\nfrom toolbox import bold, red\n\nprint(red(\"This text is red!\"))\nprint(bold(\"This text is bolded!\"))\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/string.html#toolbox.string.color.Format\"\u003e\u003ccode\u003eFormat\u003c/code\u003e\u003c/a\u003e — Persistent ANSI formatter that takes a custom ANSI code.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import Format\n\nbold = Format(code=1)\nprint(bold(\"hello world\"))\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/string.html#toolbox.string.color.Style\"\u003e\u003ccode\u003eStyle\u003c/code\u003e\u003c/a\u003e — Persistent ANSI formatter that allows multiple ANSI codes.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import Style, red, bold\n\nerror = Style(red, bold)\nprint(error(\"This is red \u0026 bolded error.\"))\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/string.html#toolbox.string.color.supports_color\"\u003e\u003ccode\u003esupports_color\u003c/code\u003e\u003c/a\u003e — Check's if the user's terminal supports color.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import supports_color\n\nprint(supports_color()) # True\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/string.html#toolbox.string.color.strip_ansi\"\u003e\u003ccode\u003estrip_ansi\u003c/code\u003e\u003c/a\u003e — Removes ANSI codes from string.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import strip_ansi\n\nprint(strip_ansi(\"\\x1b[1mhello world\\x1b[0m\")) #  hello world\n```\n\u003c/details\u003e\n\n### `textwrap`\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ca href=\"https://synchronizing.github.io/toolbox/module/textwrap.html#toolbox.textwrap.text.unindent\"\u003e\u003ccode\u003eunindent\u003c/code\u003e\u003c/a\u003e — Removes indent and white-space from docstrings.\u003c/summary\u003e\u003cbr\u003e\n\n```python\nfrom toolbox import unindent\n\ndef test():\n    text = \"\"\"\n           hello world\n           this is a test\n           \"\"\"\n    print(text)\n\n    text = unindent(\n        \"\"\"\n        hello world\n        this is a test\n        \"\"\"\n    )\n    print(text)\n\ntest()\n#           hello world\n#           this is a test\n#\n# hello world\n# this is a test\n```\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsynchronizing%2Ftoolbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsynchronizing%2Ftoolbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsynchronizing%2Ftoolbox/lists"}