{ "info": { "author": "visig", "author_email": "visig@protonmail.ch", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing" ], "description": "# Unoccupied\n\nFind an unoccupied name from `basename` & `occupied names`.\n\nIf you tired to write a bunch of code to deal `unnamed note 02`, `pic-03.jpg`, `archive.part4.zip` naming problem. It's for you.\n\n\n\n## Features\n\n- Based on basename: find an unoccupied name as close as user wanted, not randomly.\n- Isolated: pure function API, no related outer environment like filesystem or DB.\n- Stable: consider edge situations and already be tested.\n- Flexible: library user can choice / overwrite naming algorithm easily.\n\n\n\n## Usage\n\n### Basic Usage\n\nUse `basename` and `occupied` container (an iterable) to find a unoccupied name:\n\n```python3\nfrom unoccupied import unoccupied\n\nbasename = 'foo'\n\n\n\nunoccupied(basename, []) # 'foo' not be occupied\n# >>> 'foo'\n\nunoccupied(basename, ['foo']) # 'foo' already be occupied\n# >>> 'foo-1'\n\nunoccupied(basename, ['foo', 'foo-1']) # 'foo' & 'foo-1' already be occupied\n# >>> 'foo-2'\n```\n\n\n\n### Name Finder\n\nName finder offer an algorithm to find (or generate) an unoccupied name.\n\nLet's try to change the default name finder:\n\n```python3\nfrom unoccupied import unoccupied\nfrom unoccupied import NumberNameFinder # A built-in name finder generator\n\n# test data\nbasename = 'foo'\noccupied = ['foo', 'bar', 'foo-1']\n\n\n\nunoccupied(basename, occupied) # use defualt name finder\n# >>> 'foo-2'\n\nname_finder = NumberNameFinder(template='{basename}-{num:02}') # <- look here\nunoccupied(basename, occupied, name_finder)\n# >>> 'foo-01'\n```\n\nAnother case: Assume we need to find an unoccupied filename, but, we don't want the base filename `foo.txt` become `foo.txt-1`. The `foo-1.txt` is much suitable name. Try the built-in `FileNameFinder()`.\n\n```python3\nfrom unoccupied import unoccupied\nfrom unoccupied import FileNameFinder # here\n\n# test data\nbasename = 'pic.jpg'\noccupied = ['pic.jpg', 'pic-1.jpg', 'foo'] # may use os.listdir() in real case\n\n\n\nunoccupied(basename, occupied, FileNameFinder()) # <- look here\n# >>> 'pic-2.jpg'\n\nname_finder = FileNameFinder(template='{base}.{num:02}', start=0)\nunoccupied(basename, occupied, name_finder)\n# >>> 'pic.00.jpg'\n```\n\n\n\n#### Build a Name Finder\n\nA `name_finder` is just a callable accept 2 arguments: (`basename`, `norm_occupied`), so feel free to build your own. e.g.:\n\n```python3\nimport string\nfrom unoccupied import unoccupied\n\ndef alphabet_name_finder(basename, norm_occupied):\n for char in string.ascii_lowercase:\n testing_name = '{}-{}'.format(basename, char)\n if testing_name not in norm_occupied:\n return testing_name\n\nunoccupied('foo', ['foo'], alphabet_name_finder)\n# >>> 'foo-a'\n```\n\nOr, using `BaseNameFinder` class to build a `name_finder`:\n\n```python3\nimport string\nfrom unoccupied import unoccupied\nfrom unoccupied import BaseNameFinder\n\n\nclass AlphabetNameFinder(BaseNameFinder):\n \"\"\"Basic alphabet name finder.\"\"\"\n def ids_generator(self):\n return string.ascii_lowercase\n\nalphabet_name_finder = AlphabetNameFinder()\n\nunoccupied('foo', ['foo'], alphabet_name_finder)\n# >>> 'foo-a'\n\n\nclass AlphabetNameFinder2(BaseNameFinder):\n \"\"\"Configurable alphabet name finder.\"\"\"\n def __init__(self, template): # here is a configurable option.\n self.template = template\n\n def ids_generator(self):\n return string.ascii_lowercase\n\n def formatter(self, basename, id): # change formatting algorithm\n return self.template.format(basename=basename, id=id)\n\nalphabet_name_finder2 = AlphabetNameFinder2(template='{basename}.{id}')\n\nunoccupied('foo', ['foo'], alphabet_name_finder2)\n# >>> 'foo.a'\n```\n\nAs you see. `BaseNameFinder` packed some tedious work like for-loop & infinite loop checking. And good for offer some configurable options for further usage.\n\n\n\n## Reference\n\n### function unoccupied(basename, occupied, name_finder=NumberNameFinder(), skipbase=False)\n\nFind a unoccupied name.\n\n- `basename`: (str) the wanted basename.\n- `occupied`: (str of iterable) the names already be occupied.\n\n`name_finder` is a callable with 2 arguments (`basename`, `norm_occupied`). This function only be called when `basename` cannot use directly, and it should return `None` or string. Return `None` mean it can't find any unoccupied name and cause `unoccupied()` raise `UnoccupiedNameNotFound` exception.\n\n> Hint: `occupied` will be convert to `frozenset` data type (we call it `norm_occupied`) and inject to `name_finder`. If and only if you try to build a `name_finder` by yourself, you may need to know that.\n\n`skipbase` is a boolean value. If `True`, `basename` will not return directly, no matter the `basename` already in `occupied` or not. So user can generate a consistent name series like `pic-01`, `pic-02` and without `pic`.\n\n\n\n### class BaseNameFinder()\n\nThis is the base class of built-in NameFinder class. It has 2 method which can (but not necessary) be overwrited:\n\n\n\n#### method ids_generator(self) -> Iterable\n\nThis method will create a series of `id` and push into `self.formatter()`.\n\n\n\n#### method formatter(self, basename, id) -> str\n\nThis method can assemble `basename` and `id` then return a string by any algorithm.\n\n\n\n### class NumberNameFinder(template='{basename}-{num}', start=1)\n\nGenerate a `name_finder` to find an unoccupied name with `basename` and an increasing number.\n\nThe `template` argument is a python `str.format()` template. This template can include 2 keyword params. `{basename}` represent the original `basename`. `{num}` represent an increasing number.\n\n`start` argument can define what `{num}` starts from.\n\n\n\n### class FileNameFinder(template='{base}-{num}', start=1)\n\nGenerate a `name_finder` to find an unoccupied name with processed filename and an increasing number.\n\nThe `template` argument is a python `str.format()` template. This template can include 2 keyword params. `{base}` represent the filename without extension. `{num}` represent an increasing number. Hint: the filename extension will be appended automatically.\n\n`start` argument can define what `{num}` starts from.\n\n\n\n## Test\n\n```sh\n./setup.py test # or pytest\n```\n\n\n## Install\n\n```sh\npip install unoccupied\n```\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/civalin/unoccupied", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "unoccupied", "package_url": "https://pypi.org/project/unoccupied/", "platform": "", "project_url": "https://pypi.org/project/unoccupied/", "project_urls": { "Homepage": "https://github.com/civalin/unoccupied" }, "release_url": "https://pypi.org/project/unoccupied/0.2.2/", "requires_dist": null, "requires_python": "", "summary": "Generate unoccupied name.", "version": "0.2.2" }, "last_serial": 4028677, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "c147bc277ec3e8a96c122f6af11d0965", "sha256": "70a2b7646a3b1f6f6ff4007e6b25cbe07b408f841bbbe8fafbf742ed690792aa" }, "downloads": -1, "filename": "unoccupied-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "c147bc277ec3e8a96c122f6af11d0965", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 4642, "upload_time": "2018-07-01T06:52:11", "url": "https://files.pythonhosted.org/packages/2d/f5/844d9c93266d2bc15751a1d37d66ec2f7a21d56702740e71048c8849c482/unoccupied-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e473c924ce5c85677b6af25a4d054e57", "sha256": "44377fcae93ef52f2c0e6318ca63bce267bb2c66c0c0dd5a4997f1dd1dc650ee" }, "downloads": -1, "filename": "unoccupied-0.1.0.tar.gz", "has_sig": false, "md5_digest": "e473c924ce5c85677b6af25a4d054e57", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5645, "upload_time": "2018-07-01T06:52:12", "url": "https://files.pythonhosted.org/packages/a2/27/9780acf34e3ce19084edcbdaa89027327666de58c31591e6dbc10810c42b/unoccupied-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "ce066c0dccf79c732c16d9cfd21a4e00", "sha256": "3a368a6687e587b926e9dafbf6801e10b093b00e412797180500a5ef016cc3ae" }, "downloads": -1, "filename": "unoccupied-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "ce066c0dccf79c732c16d9cfd21a4e00", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 6873, "upload_time": "2018-07-01T10:13:09", "url": "https://files.pythonhosted.org/packages/a6/70/f13f58c58cc58b8a4de39ade92695eff082f386f8c6cedea7e1c6bce39bf/unoccupied-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8a67bc4a611289112466cdbc680e3660", "sha256": "3f34de89fd32d6bc00066ee65afdb8ab1069d61e4326af4f94a4e340c18131a0" }, "downloads": -1, "filename": "unoccupied-0.1.1.tar.gz", "has_sig": false, "md5_digest": "8a67bc4a611289112466cdbc680e3660", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5767, "upload_time": "2018-07-01T10:13:10", "url": "https://files.pythonhosted.org/packages/f3/ab/eb3f34f4c96ed333c812ad088e0706980e57af7687e5815147dd264a1f6f/unoccupied-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "5f6c7420b688e6409950e31fd9e06b41", "sha256": "880c9c514abc32eef1b3185c93f1c59ccf1122eb69e7ad4bf1c6cb1e0f52125f" }, "downloads": -1, "filename": "unoccupied-0.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "5f6c7420b688e6409950e31fd9e06b41", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5072, "upload_time": "2018-07-01T12:28:39", "url": "https://files.pythonhosted.org/packages/fa/98/fd4771ba5f5f173140fb8c7f79039f5c7df4942bb255811d7cb4b46da7ae/unoccupied-0.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "85cb0293a8a4ccf55e3452ecd1f2b8e6", "sha256": "1021f3ffe87e688ca62af3d1dc63e0df98bf1d43a86f674bffe435b0992bb73d" }, "downloads": -1, "filename": "unoccupied-0.1.2.tar.gz", "has_sig": false, "md5_digest": "85cb0293a8a4ccf55e3452ecd1f2b8e6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6108, "upload_time": "2018-07-01T12:28:41", "url": "https://files.pythonhosted.org/packages/9f/c5/9c359fea27a3833832a88a471b001e145833ff16e9268efafec346d08775/unoccupied-0.1.2.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "4243ac73912c603de445b4c585fdba82", "sha256": "3f694553bef86368642093a406c8374c33625485d9a9e910f5b3b7cb4dc244bd" }, "downloads": -1, "filename": "unoccupied-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "4243ac73912c603de445b4c585fdba82", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5675, "upload_time": "2018-07-03T03:44:04", "url": "https://files.pythonhosted.org/packages/10/64/772d80b0f6078a3a3292c139d3bb70be74a5505cd68300c6d2b465682652/unoccupied-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "779b383715db434b73df364c9a9236e1", "sha256": "2ec138e465c16c0596cc7ac1900bea6c57d31137287d8b31a115b28ff20ad2a5" }, "downloads": -1, "filename": "unoccupied-0.2.0.tar.gz", "has_sig": false, "md5_digest": "779b383715db434b73df364c9a9236e1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6935, "upload_time": "2018-07-03T03:44:05", "url": "https://files.pythonhosted.org/packages/dc/15/376f89eb0b84fb490c680ea83d1b4facb1dd13c2756b1c15e2c8b3953911/unoccupied-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "e7357314bc4ec503438fad2c4ed99dca", "sha256": "4ef801cdba0f837ca25a0d1c4512f8c2b6fc9fa3ad1a70f4699fbb716ebb9665" }, "downloads": -1, "filename": "unoccupied-0.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "e7357314bc4ec503438fad2c4ed99dca", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5785, "upload_time": "2018-07-04T03:47:48", "url": "https://files.pythonhosted.org/packages/77/6f/293ced439e67250dbcfb4e4171633a1525c3ab53f871794efbb507ac38ba/unoccupied-0.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "be035e92f18d59bbbc838443ac8f4bcb", "sha256": "d7871168d775e38e04916cfc9d5bc9a190075ff82fd01f3b3e5851673a7c6d8f" }, "downloads": -1, "filename": "unoccupied-0.2.1.tar.gz", "has_sig": false, "md5_digest": "be035e92f18d59bbbc838443ac8f4bcb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7046, "upload_time": "2018-07-04T03:47:50", "url": "https://files.pythonhosted.org/packages/d2/fd/b65cec8089acb4fb2080f237770d55bf4661d2a419a1394eca15ce896a08/unoccupied-0.2.1.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "90ce8f80ab8210ddea4558b99e92d2e4", "sha256": "f0c667e33447ca87e2e99237e051681207da767643b032e10efdb442baef71d5" }, "downloads": -1, "filename": "unoccupied-0.2.2-py3-none-any.whl", "has_sig": false, "md5_digest": "90ce8f80ab8210ddea4558b99e92d2e4", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5629, "upload_time": "2018-07-04T03:58:38", "url": "https://files.pythonhosted.org/packages/c4/f9/456dc9af4858fed2b9b642278e737ccf09850dd3d31d83212037e62e1f72/unoccupied-0.2.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a3393e9eb42db782482c29c6f6c596eb", "sha256": "a1e949106c844bb0c250f6e43c7c037383f02ecb0a5d78e95ef4f4b32d081483" }, "downloads": -1, "filename": "unoccupied-0.2.2.tar.gz", "has_sig": false, "md5_digest": "a3393e9eb42db782482c29c6f6c596eb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6891, "upload_time": "2018-07-04T03:58:39", "url": "https://files.pythonhosted.org/packages/95/31/8f82e086bb72fb8cf124fcf4eea7d8fa01d5fbb4e74dbbb5e2fcc9cc2a18/unoccupied-0.2.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "90ce8f80ab8210ddea4558b99e92d2e4", "sha256": "f0c667e33447ca87e2e99237e051681207da767643b032e10efdb442baef71d5" }, "downloads": -1, "filename": "unoccupied-0.2.2-py3-none-any.whl", "has_sig": false, "md5_digest": "90ce8f80ab8210ddea4558b99e92d2e4", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5629, "upload_time": "2018-07-04T03:58:38", "url": "https://files.pythonhosted.org/packages/c4/f9/456dc9af4858fed2b9b642278e737ccf09850dd3d31d83212037e62e1f72/unoccupied-0.2.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a3393e9eb42db782482c29c6f6c596eb", "sha256": "a1e949106c844bb0c250f6e43c7c037383f02ecb0a5d78e95ef4f4b32d081483" }, "downloads": -1, "filename": "unoccupied-0.2.2.tar.gz", "has_sig": false, "md5_digest": "a3393e9eb42db782482c29c6f6c596eb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6891, "upload_time": "2018-07-04T03:58:39", "url": "https://files.pythonhosted.org/packages/95/31/8f82e086bb72fb8cf124fcf4eea7d8fa01d5fbb4e74dbbb5e2fcc9cc2a18/unoccupied-0.2.2.tar.gz" } ] }