{"id":26590487,"url":"https://github.com/d-chris/pathlibutil","last_synced_at":"2025-03-23T13:40:14.642Z","repository":{"id":214849912,"uuid":"737504102","full_name":"d-chris/pathlibutil","owner":"d-chris","description":"python __class__ inherits from pathlib.Path with methods for hashing, copying, deleting and more","archived":false,"fork":false,"pushed_at":"2025-03-06T18:16:56.000Z","size":899,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-06T19:24:56.673Z","etag":null,"topics":["json","pathlib","python","shutils","urllib"],"latest_commit_sha":null,"homepage":"https://d-chris.github.io/pathlibutil","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/d-chris.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,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-12-31T09:43:09.000Z","updated_at":"2025-02-26T19:18:57.000Z","dependencies_parsed_at":"2024-03-18T22:39:29.513Z","dependency_job_id":"5130c658-360d-4dfd-81b2-3cd21eb39cce","html_url":"https://github.com/d-chris/pathlibutil","commit_stats":null,"previous_names":["d-chris/pathlibutil"],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-chris%2Fpathlibutil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-chris%2Fpathlibutil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-chris%2Fpathlibutil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-chris%2Fpathlibutil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/d-chris","download_url":"https://codeload.github.com/d-chris/pathlibutil/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245111403,"owners_count":20562510,"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":["json","pathlib","python","shutils","urllib"],"created_at":"2025-03-23T13:40:14.054Z","updated_at":"2025-03-23T13:40:14.624Z","avatar_url":"https://github.com/d-chris.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\nfilename: ./README.md\n--\u003e\n\n# pathlibutil\n\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pathlibutil)](https://pypi.org/project/pathlibutil/)\n[![PyPI - Version](https://img.shields.io/pypi/v/pathlibutil)](https://pypi.org/project/pathlibutil/)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/pathlibutil)](https://pypi.org/project/pathlibutil/)\n[![PyPI - License](https://img.shields.io/pypi/l/pathlibutil)](https://raw.githubusercontent.com/d-chris/pathlibutil/main/LICENSE)\n[![GitHub - Pytest](https://img.shields.io/github/actions/workflow/status/d-chris/pathlibutil/pytest.yml?logo=github\u0026label=pytest)](https://github.com/d-chris/pathlibutil/actions/workflows/pytest.yml)\n[![GitHub - Page](https://img.shields.io/website?url=https%3A%2F%2Fd-chris.github.io%2Fpathlibutil\u0026up_message=pdoc\u0026logo=github\u0026label=documentation)](https://d-chris.github.io/pathlibutil)\n[![GitHub - Release](https://img.shields.io/github/v/tag/d-chris/pathlibutil?logo=github\u0026label=github)](https://github.com/d-chris/pathlibutil)\n[![codecov](https://codecov.io/gh/d-chris/pathlibutil/graph/badge.svg?token=U7I9FYMRSR)](https://codecov.io/gh/d-chris/pathlibutil)\n[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://raw.githubusercontent.com/d-chris/pathlibutil/main/.pre-commit-config.yaml)\n\n---\n\n`pathlibutil.Path` inherits from  `pathlib.Path` with some useful built-in python functions from `shutil` and `hashlib`\n\n- `Path.hexdigest()` to calculate and `Path.verify()` for verification of hexdigest from a file\n- `Path.default_hash` to configurate default hash algorithm for `Path` class (default: *'md5'*)\n- `Path.size()` to get size in bytes of a file or directory\n  - `byteint` function decorator converts the return value of `int` to a `ByteInt` object\n- `Path.read_lines()` to yield over all lines from a file until EOF\n- `contextmanager` to change current working directory with `with` statement\n- `Path.copy()` copy a file or directory to a new path destination\n- `Path.delete()` delete a file or directory-tree\n- `Path.move()` move a file or directory to a new path destination\n- `Path.make_archive()` creates and `Path.unpack_archive()` uncompresses an archive from a file or directory\n- `Path.archive_formats` to get all available archive formats\n- `Path.stat()` returns a `StatResult` object to get file or directory information containing\n  - `TimeInt` objects for `atime`, `ctime`, `mtime` and `birthtime`\n  - `ByteInt` object for `size`\n- `Path.relative_to()` to get relative path from a file or directory, `walk_up` to walk up the directory tree.\n- `Path.with_suffix()` to change the multiple suffixes of a file\n- `Path.cwd()` to get the current working directory or executable path when script is bundled, e.g. with `pyinstaller`\n- `Path.resolve()` to resolve a unc path to a mapped windows drive.\n- `Path.walk()` to walk over a directory tree like `os.walk()`\n- `Path.iterdir()` with `recursive` all files from the directory tree will be yielded and `exclude_dirs` via callable.\n- `Path.is_expired()` to check if a file is expired by a given `datetime.timedelta`\n- `Path.expand()` yields file paths for multiple file patterns if they exsits.\n\nJSON serialization of `Path` objects is supported in `pathlibutil.json`.\n\n- `pathlibutil.json.dumps()` and `pathlibutil.json.dump()` to serialize `Path` objects as posix paths.\n\nParse and modify URLs with `pathlibutil.urlpath`.\n\n- `pathlibutil.urlpath.UrlPath()` modify URL and easy access the `path` of the url like a `pathlib.PurePosixPath` object.\n- `pathlibutil.urlpath.UrlNetloc()` to parse and modify the `netloc` part of a URL.\n- `pathlibutil.urlpath.normalize()` to normalize a URL string.\n- `pathlibutil.urlpath.url_from()` to create a URL from an UNC path object.\n\n\n## Installation\n\n```bash\npip install pathlibutil\n```\n\n### 7zip support\n\nto handle 7zip archives, an extra package `py7zr\u003e=0.20.2` is required!\n\n[![PyPI - Version](https://img.shields.io/pypi/v/py7zr?logo=python\u0026logoColor=white\u0026label=py7zr\u0026color=FFFF33)](https://pypi.org/project/py7zr/)\n\n```bash\n# install as extra dependency\npip install pathlibutil[7z]\n```\n\n## Usage\n\n```python\nfrom pathlibutil import Path\n\nreadme = Path('README.md')\n\nprint(f'File size: {readme.size()} Bytes')\n```\n\n## Example 1\n\nRead a file and print its content and some file information to stdout.\n\u003e `Path.read_lines()`\n\n```python\nfrom pathlibutil import Path\n\nreadme = Path(\"README.md\")\n\nprint(f\"File size: {readme.size()} Bytes\")\nprint(f'File sha1: {readme.hexdigest(\"sha1\")}')\n\nprint(\"File content\".center(80, \"=\"))\n\nfor line in readme.read_lines(encoding=\"utf-8\"):\n  print(line, end=\"\")\n\nprint(\"EOF\".center(80, \"=\"))\n```\n\n## Example 2\n\nWrite a file with md5 checksums of all python files in the pathlibutil-directory.\n\u003e `Path.hexdigest()`\n\n```python\nfrom pathlibutil import Path\n\nfile = Path(\"pathlibutil.md5\")\n\nwith file.open(\"w\") as f:\n  f.write(\n      \"# MD5 checksums generated with pathlibutil \"\n      \"(https://pypi.org/project/pathlibutil/)\\n\\n\"\n  )\n\n  i = 0\n  for i, filename in enumerate(Path(\"./pathlibutil\").glob(\"*.py\"), start=1):\n    f.write(f\"{filename.hexdigest()} *{filename}\\n\")\n\nprint(f\"\\nwritten: {i:\u003e5} {file.default_hash}-hashes to: {file}\")\n```\n\n## Example 3\n\nRead a file with md5 checksums and verify them.\n\u003e `Path.verify()`, `Path.default_hash` and `contextmanager`\n\n```python\nfrom pathlibutil import Path\n\nfile = Path(\"pathlibutil.md5\")\n\n\ndef no_comment(line: str) -\u003e bool:\n  return not line.startswith(\"#\")\n\n\nwith file.parent as cwd:\n  miss = 0\n  ok = 0\n  fail = 0\n\n  for line in filter(no_comment, file.read_lines()):\n    try:\n      digest, filename = line.strip().split(\" *\")\n      verification = Path(filename).verify(digest, \"md5\")\n    except ValueError as split_failed:\n      continue\n    except FileNotFoundError as verify_failed:\n      tag = \"missing\"\n      miss += 1\n    else:\n      if verification:\n        tag = \"ok\"\n        ok += 1\n      else:\n        tag = \"fail\"\n        fail += 1\n\n    print(f'{tag.ljust(len(digest), \".\")} *{filename}')\n\n  print(f\"\\nok: {ok:\u003c5} fail: {fail:\u003c5} missing: {miss}\")\n```\n\n## Example 4\n\nSearch all pycache directories and free the memory and display the number of\ndeleted directories and the amount of memory freed in MB.\n\u003e `Path.delete()`, `Path.size()` and `ByteInt`\n\n```python\nfrom pathlibutil import ByteInt, Path\n\nmem = ByteInt(0)\ni = 0\n\nfor i, cache in enumerate(Path(\".\").rglob(\"*/__pycache__/\"), start=1):\n  cache_size = cache.size()\n  try:\n    cache.delete(recursive=True)\n  except OSError:\n    print(f\"Failed to delete {cache}\")\n  else:\n    mem += cache_size\n\nprint(f\"{i} cache directories deleted, {mem:.1mb} MB freed.\")\n```\n\n## Example 5\n\nInherit from `pathlibutil.Path` to register new a archive format. Specify a\n`archive` as keyword argument in the new subclass, which has to be the suffix\nwithout `.` of the archives. Implement a classmethod `_register_archive_format()`\nto register new archive formats.\n\n\u003e Path.make_archive(), Path.archive_formats and Path.move()\n\n```python\nimport shutil\n\nimport pathlibutil\n\n\nclass RegisterFooBarFormat(pathlibutil.Path, archive=\"foobar\"):\n  @classmethod\n  def _register_archive_format(cls):\n    \"\"\"\n    implement new register functions for given `archive`\n    \"\"\"\n    try:\n      import required_package_name\n    except ModuleNotFoundError:\n      raise ModuleNotFoundError(\"pip install \u003crequired_package_name\u003e\")\n\n    def pack_foobar(\n        base_name, base_dir, owner=None, group=None, dry_run=None, logger=None\n    ) -\u003e str:\n      \"\"\"callable that will be used to unpack archives.\n\n      Args:\n          base_name (`str`): name of the file to create\n          base_dir (`str`): directory to start archiving from, defaults to `os.curdir`\n          owner (`Any`, optional): as passed in `make_archive(*args, owner=None, **kwargs)`. Defaults to None.\n          group (`Any`, optional): as passed in `make_archive(*args, group=None, **kwargs)`. Defaults to None.\n          dry_run (`Any`, optional): as passed in `make_archive(*args, dry_run=None, **kwargs)`. Defaults to None.\n          logger (`logging.Logger`, optional): as passed in `make_archive(*args, logger=None, **kwargs)`. Defaults to None.\n\n      Returns:\n          str: path of the new created archive\n      \"\"\"\n      raise NotImplementedError(\"implement your own pack function\")\n\n    def unpack_foobar(archive, path, filter=None, extra_args=None) -\u003e None:\n      \"\"\"callable that will be used to unpack archives.\n\n      Args:\n          archive (`str`): path of the archive\n          path (`str`): directory the archive must be extracted to\n          filter (`Any`, optional): as passed in `unpack_archive(*args, filter=None, **kwargs)`. Defaults to None.\n          extra_args (`Sequence[Tuple[name, value]]`, optional): additional keyword arguments, specified by `register_unpack_format(*args, extra_args=None, **kwargs)`. Defaults to None.\n      \"\"\"\n      raise NotImplementedError(\"implement your own unpack function\")\n\n    shutil.register_archive_format(\n        \"foobar\", pack_foobar, description=\"foobar archives\"\n    )\n    shutil.register_unpack_format(\"foobar\", [\".foo.bar\"], unpack_foobar)\n\n\nfile = pathlibutil.Path(\"README.md\")\n\nprint(f\"available archive formats: {file.archive_formats}\")\n\narchive = file.make_archive(\"README.foo.bar\")\n\nbackup = archive.move(\"./backup/\")\n\nprint(f\"archive created: {archive.name} and moved to: {backup.parent}\")\n```\n\n## Example 6\n\nAccess the current working directory with optional parameter `frozen` to determine\ndifferent directories when script is bundled to an executable,\ne.g. with `pyinstaller`.\n\u003e `Path.cwd()`\n\n```cmd\n\u003e\u003e\u003e poetry run examples/example6.py -b\nBuilding frozen: K:/pathlibutil/examples/example6.exe\nBuild succeeded: 0\n\n\u003e\u003e\u003e poetry run examples/example6.py\nwe are                          not frozen\n\nbundle dir is                   K:/pathlibutil/examples\nsys.argv[0] is                  K:/pathlibutil/examples/example6.py\nsys.executable is               K:/pathlibutil/.venv/Scripts/python.exe\nos.getcwd is                    K:/pathlibutil\n\nPath.cwd(frozen=True) is        K:/pathlibutil\nPath.cwd(frozen=False) is       K:/pathlibutil\nPath.cwd(frozen=_MEIPASS) is    K:/pathlibutil\n\n\u003e\u003e\u003e examples/example6.exe\nwe are                          ever so frozen\n\nbundle dir is                   C:/Users/CHRIST~1.DOE/AppData/Local/Temp/_MEI106042\nsys.argv[0] is                  examples/example6.exe\nsys.executable is               K:/pathlibutil/examples/example6.exe\nos.getcwd is                    K:/pathlibutil\n\nPath.cwd(frozen=True) is        K:/pathlibutil/examples\nPath.cwd(frozen=False) is       K:/pathlibutil\nPath.cwd(frozen=_MEIPASS) is    C:/Users/CHRIST~1.DOE/AppData/Local/Temp/_MEI106042\n```\n\n## Example 7\n\nConsole application to convert UNC paths to intranet URLs.\n\nBy default, it checks if the filename and URL are available and copies the\nnormalized URL to the clipboard.\n\n\u003e `pathlibutil.urlpath.url_from()`\n\n```python\nimport argparse\nimport sys\n\ntry:\n    import pyperclip\n\n    import pathlibutil.urlpath as up\nexcept ModuleNotFoundError as e:\n    raise ModuleNotFoundError(f\"pip install {e.name.split('.')[0]}\") from e\n\n\ndef intranet_from(uncpath: str, check: bool = True) -\u003e str:\n    \"\"\"\n    Return the intranet URL for the given UNC path.\n    \"\"\"\n\n    url = up.url_from(\n        uncpath,\n        hostname=\"http://intranet.example.de\",\n        strict=check,\n    )\n\n    return url.normalize()\n\n\ndef cli():\n\n    parser = argparse.ArgumentParser(\n        description=intranet_from.__doc__,\n        formatter_class=argparse.ArgumentDefaultsHelpFormatter,\n    )\n\n    parser.add_argument(\n        \"filename\",\n        nargs=\"*\",\n        help=\"The UNC path to the file.\",\n    )\n    parser.add_argument(\n        \"-c\",\n        \"--no-check\",\n        action=\"store_false\",\n        dest=\"check\",\n        help=\"Don't check if filename and url is available.\",\n    )\n    parser.add_argument(\n        \"-s\",\n        \"--silent\",\n        action=\"store_true\",\n        help=\"Do not print the url to stdout.\",\n    )\n    parser.add_argument(\n        \"-n\",\n        \"--no-clip\",\n        action=\"store_false\",\n        dest=\"clip\",\n        help=\"Don't copy the url to the clipboard.\",\n    )\n\n    args = parser.parse_args()\n    filename = \" \".join(args.filename)\n\n    url = intranet_from(filename, check=args.check)\n\n    if not args.silent:\n        print(url)\n\n    if args.clip:\n        pyperclip.copy(url)\n\n\nif __name__ == \"__main__\":\n    try:\n        cli()\n    except Exception as e:\n        print(e, file=sys.stderr)\n        sys.exit(1)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fd-chris%2Fpathlibutil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fd-chris%2Fpathlibutil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fd-chris%2Fpathlibutil/lists"}