ruamel.std.pathlib


Nameruamel.std.pathlib JSON
Version 0.13.0 PyPI version JSON
download
home_page
Summaryimprovements over the standard pathlib module and pathlib2 package
upload_time2024-03-03 06:56:51
maintainer
docs_urlNone
authorAnthon van der Neut
requires_python>=3
licenseMIT License
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
# ruamel.std.pathlib

[package ruamel.std.pathlib](https://bitbucket.org/ruamel/std.pathlib)
is a drop-in replacement to extend the Python standard
`pathlib` module.

You can just replace:

    from pathlib import PosixPath, Path

with:

    from ruamel.std.pathlib import PosixPath, Path

[![image](https://sourceforge.net/p/ruamel-std-pathlib/code/ci/default/tree/_doc/_static/pypi.svg?format=raw)](https://pypi.org/project/ruamel.std.pathlib)
[![image](https://sourceforge.net/p/ruamel-std-pathlib/code/ci/default/tree/_doc/_static/license.svg?format=raw)](https://opensource.org/licenses/MIT)
[![image](https://sourceforge.net/p/oitnb/code/ci/default/tree/_doc/_static/oitnb.svg?format=raw)](https://pypi.org/project/oitnb/)

Starting with 0.8.0 `ruamel.std.pathlib` no longer supports Python 2

## Extra Path functionality

- alias `remove` for `unlink` on Path
- add `copy()` and `rmtree()` from shutil to Path
- add `hash()` to path return the `hashlib.new()` value on the file
  content (defaults to \'sha224\', other algorithms can be given as
  parameter: `print(p.hash('md5').hexdigest())`)
- add `pushd()` and `popd()` to a (directory) Path (this keeps a stack
  of potentially more than one entry).
- add `rmtree()`, to call `shutil.rmtree()` on the Path
- add `chdir()` to a (directory) Path
- add `stabilise()` to a Path, to wait for it to no longer change,
  `duration` (default 5 seconds), `recheck` (default 0.2s) can be set,
  as well as message that is displayed once if not stable yet.

### blake3

when you have `blake3` installed (this is not a dependency for this package) and do
`import ruamel.std.pathlib.blake3`, you can also use that method on
`Path` instances.

### json

when you do `import ruamel.std.pathlib.json` this loads orjson/ujson/json (in that order)
to a Path so you can do
`data = path.json.load()` and `path.json.dump(data)`

### msgpack

when you have `ruamel.ext.msgpack` installed and do `import ruamel.std.pathlib.msgpack`
and you have a `Path` instance `path` you can do
`data = path.msgpack.load()` and `path.msgpack.dump(data)`

### tar

when you have `zstandard` installed and do `import ruamel.std.pathlib.tar`
and you have a `Path` instance `path` you can do
`with path.tar.open()` on a `.tar.zst` file with in memory decompression.


## Transition helper

If you are starting to use the standard pathlib library, it is
cumbersome to change everything at once, and also to change all the
arguments to calls to `os.path.join`, `os.rename`, `os.path.dirname` to
be made encapsulated in `str()`

By making an instance of `PathLibConversionHelper` named `pl` you can
change `os.path.join()` to `pl.path.join()`, etc., and then start
passing in Path instances instead of strings.

`PathLibConversionHelper` currently supports the following replacements for `os`,

:   `os.path`, `shutil` and built-in functions:

        .chdir()             replaces: os.chdir()
        .copy()              replaces: shutil.copy()
        .glob()              replaces: glob.glob()
        .listdir()           replaces: os.listdir()
        .makedirs()          replaces: os.makedirs()
        .mkstemp()           replaces: tempfile.mkstemp()
        .open()              replaces: built-in open()
        .path.basename()     replaces: os.path.basename()
        .path.dirname()      replaces: os.path.dirname()
        .path.exists()       replaces: os.path.exists()
        .path.expanduser()   replaces: os.path.expanduser()
        .path.getmtime()     replaces: os.path.getmtime()
        .path.isdir()        replaces: os.path.isdir()
        .path.join()         replaces: os.path.join()
        .path.splitext()     replaces: os.path.splitext()
        .remove()            replaces: os.remove()
        .rename()            replaces: os.rename()
        .rmdir()             replaces: os.rmdir()
        .rmtree()            replaces: shutil.rmtree()
        .walk()              replaces: os.walk()

You can provide a check level when you create the
`PathLibConversionHelper()` instance.

-   If check is non-zero, all calls are being logged and the invocations
    can be dumped e.g. at the end of the program with
    `pl.dump(stream, show_all=False)` This will include the number of
    invocations not using Path (and using Path uniquely as well if
    `show_all=True`)
-   If check is greater than 1, first usage is dumped immediately.

If you start with the following code:

    # coding: utf-8

    import os
    import glob
    import tempfile
    import shutil
    import random


    class TempDir(object):
        """self removing (unless keep=True) temporary directory"""
        def __init__(self, keep=False, basedir=None, prefix=None):
            self._keep = keep
            # mkdtemp creates with permissions rwx------
            kw = dict(dir=basedir)
            if prefix is not None:
                kw['prefix'] = prefix
            # mkdtemp doesn't do the right thing if None is passed in
            # as it has prefix=template in definition
            self._tmpdir = tempfile.mkdtemp(**kw)

        def remove(self):
            shutil.rmtree(self._tmpdir)

        def chdir(self):
            os.chdir(self._tmpdir)

        def tempfilename(self, extension=''):
            fd, name = tempfile.mkstemp(suffix=extension, dir=self._tmpdir)
            os.close(fd)
            return name

        def tempfilename2(self, extension=''):
            while True:
                name = os.path.join(
                    self._tmpdir,
                    '%08d' % random.randint(0, 100000) + extension
                )
                if not os.path.exists(name):
                    break
            return name

        @property
        def directory(self):
            return self._tmpdir

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc_val, exc_tb):
            if not self._keep:
                self.remove()


    def main():
        """contrived example using TempDir"""
        org_dir = os.getcwd()
        with TempDir() as td:
            for n in range(3):
                t1 = td.tempfilename(extension='.sample')
                with open(t1, 'w') as fp:
                    fp.write('content\n')
            t2 = td.tempfilename2(extension='.sample2')
            with open(t2, 'w') as fp:
                fp.write('content\n')
            os.chdir(td.directory)
            count = 0
            for file_name in glob.glob('*.samp*'):
                full_name = os.path.join(os.getcwd(), file_name)  # noqa
                # print(full_name)
                count += 1
            os.chdir('/tmp')  # not using Path
            os.chdir(org_dir)
        print('{} files found in temporary directory'.format(count))

    main()

you get:

    4 files found in temporary directory

When you start to change `TempDir()` to store the actual directory as a
Path, things start to break immediately:

    # coding: utf-8

    import os
    import glob
    import tempfile
    import shutil
    import random

    from ruamel.std.pathlib import Path                                   # added


    class TempDir(object):
        """self removing (unless keep=True) temporary directory"""
        def __init__(self, keep=False, basedir=None, prefix=None):
            self._keep = keep
            # mkdtemp creates with permissions rwx------
            kw = dict(dir=basedir)
            if prefix is not None:
                kw['prefix'] = prefix
            # mkdtemp doesn't do the right thing if None is passed in
            # as it has prefix=template in definition
            self._tmpdir = Path(tempfile.mkdtemp(**kw))                   # changed

        def remove(self):
            shutil.rmtree(self._tmpdir)

        def chdir(self):
            os.chdir(self._tmpdir)

        def tempfilename(self, extension=''):
            fd, name = tempfile.mkstemp(suffix=extension, dir=self._tmpdir)
            os.close(fd)
            return name

        def tempfilename2(self, extension=''):
            while True:
                name = os.path.join(
                    self._tmpdir,
                    '%08d' % random.randint(0, 100000) + extension
                )
                if not os.path.exists(name):
                    break
            return name

        @property
        def directory(self):
            return self._tmpdir

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc_val, exc_tb):
            if not self._keep:
                self.remove()


    def main():
        """contrived example using TempDir"""
        org_dir = os.getcwd()
        with TempDir() as td:
            for n in range(3):
                t1 = td.tempfilename(extension='.sample')
                with open(t1, 'w') as fp:
                    fp.write('content\n')
            t2 = td.tempfilename2(extension='.sample2')
            with open(t2, 'w') as fp:
                fp.write('content\n')
            os.chdir(td.directory)
            count = 0
            for file_name in glob.glob('*.samp*'):
                full_name = os.path.join(os.getcwd(), file_name)  # noqa
                # print(full_name)
                count += 1
            os.chdir('/tmp')  # not using Path
            os.chdir(org_dir)
        print('{} files found in temporary directory'.format(count))

    main()

With some errors:

    Traceback (most recent call last):
      File "_example/stage1.py", line 80, in <module>
        main()
      File "_example/stage1.py", line 77, in main
        os.chdir(org_dir)
      File "_example/stage1.py", line 56, in __exit__
        self.remove()
      File "_example/stage1.py", line 27, in remove
        shutil.rmtree(self._tmpdir)
      File "/opt/python/2.7.13/lib/python2.7/shutil.py", line 228, in rmtree
        if os.path.islink(path):
      File "/home/venv/dev/lib/python2.7/posixpath.py", line 135, in islink
        st = os.lstat(path)
    TypeError: coercing to Unicode: need string or buffer, PosixPath found

Instead of changing every usage in your program in one go, and hope it
will work again, you replace the routines from the standard module:

    # coding: utf-8

    import os
    import glob
    import tempfile
    import shutil                       # noqa
    import random

    from ruamel.std.pathlib import Path, PathLibConversionHelper            # changed
    pl = PathLibConversionHelper()                                          # added


    class TempDir(object):
        """self removing (unless keep=True) temporary directory"""
        def __init__(self, keep=False, basedir=None, prefix=None):
            self._keep = keep
            # mkdtemp creates with permissions rwx------
            kw = dict(dir=basedir)
            if prefix is not None:
                kw['prefix'] = prefix
            # mkdtemp doesn't do the right thing if None is passed in
            # as it has prefix=template in definition
            self._tmpdir = Path(tempfile.mkdtemp(**kw))

        def remove(self):
            pl.rmtree(self._tmpdir)

        def chdir(self):
            os.chdir(self._tmpdir)

        def tempfilename(self, extension=''):
            fd, name = pl.mkstemp(suffix=extension, dir=self._tmpdir)     # changed
            os.close(fd)
            return name

        def tempfilename2(self, extension=''):
            while True:
                name = pl.path.join(
                    self._tmpdir,
                    '%08d' % random.randint(0, 100000) + extension
                )
                if not pl.path.exists(name):                              # changed
                    break
            return name

        @property
        def directory(self):
            return self._tmpdir

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc_val, exc_tb):
            if not self._keep:
                self.remove()


    def main():
        """contrived example using TempDir"""
        org_dir = os.getcwd()
        with TempDir() as td:
            for n in range(3):
                t1 = td.tempfilename(extension='.sample')
                with open(t1, 'w') as fp:
                    fp.write('content\n')
            t2 = td.tempfilename2(extension='.sample2')
            with pl.open(t2, 'w') as fp:
                c = 'content\n'                                           # added
                if not isinstance(fp, file):                              # added
                    c = unicode(c)                                        # added
                fp.write(c)                                               # changed
            pl.chdir(td.directory)
            count = 0
            for file_name in glob.glob('*.samp*'):
                full_name = pl.path.join(os.getcwd(), file_name)  # noqa  # changed
                # print(full_name)
                count += 1
            pl.chdir('/tmp')  # not using Path
            pl.chdir(org_dir)                                             # changed
        print('{} files found in temporary directory'.format(count))

    main()

giving (again):

    4 files found in temporary directory

Change back just the creation of `self._tempdir` to the original:

    self._tmpdir = tempfile.mkdtemp(**kw)

and the output stays:

    4 files found in temporary directory

If you now change the creation of `pl` to:

    pl = PathLibConversionHelper(check=2)

you get as output:

    update .mkstemp to use Path.mkstemp() [_example/stage3.py:34 / Path (True,)]
    update .path.join to use "/" [_example/stage3.py:42 / Path (True, False)]
    update .exists to use Path.exists() [_example/stage3.py:44 / Path (True,)]
    update .open to use Path.open() [_example/stage3.py:69 / Path (True,)]
    update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage3.py:74 / Path (True,)]
    update .path.join to use "/" [_example/stage3.py:77 / Path (False, False)]
    update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage3.py:80 / Path (False,)]
    update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage3.py:81 / Path (False,)]
    update .rmtree to use Path.rmtree() or shutil.rmtree(str(Path)) [_example/stage3.py:28 / Path (True,)]
    4 files found in temporary directory

If you use `check=1` and at the end `pl.dump()`, you get:

    4 files found in temporary directory
    update .path.join to use "/" [_example/stage4.py:42 / 1 / Path (True, False)]
    update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage4.py:81 / 1 / Path (False,)]
    update .path.join to use "/" [_example/stage4.py:77 / 4 / Path (False, False)]
    update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage4.py:80 / 1 / Path (False,)]

showing where you still use string based paths/filenames.

The message part `file_name.py: 123 / 2 / Path (True, False)` means that
there were two calls on line 123 in `file_name.py` and that they were
called with the first parameter being a Path, the second not being a
Path (when replacing `os.path.join()` with Path\'s `"/"` concatenation
operator that would be a good starting point, for other situation you
might want to convert the second parameter to a Path instance as well).

## Extending `PathLibConversionHelper`

If `PathLibConversionHelper` doesn\'t contain a particular function
(yet) you can easily subclass it and add your own:

    from ruamel.std.pathlib import Path, PathLibConversionHelper


    class MyPLCH(PathLibConversionHelper):
        # an example, ruamel.std.pathlib already adds mkstemp
        def mkstemp(self, suffix="", prefix=None, dir=None, text=False):
            import tempfile
            # would be much better if prefix defaults to built-in value (int, None, string)
            if prefix is None:
                prefix = tempfile.template
            self.__add_usage(dir, 'update .mkstemp to use Path.mkstemp()')
            if isinstance(dir, Path):
                dir = str(dir)
            return tempfile.mkstemp(suffix, prefix, dir, text)

    pl = MyPLCH(check=1)

The first parameter for `self.add_usage()` is used to determine if a
Path is used or not. This should be a list of all relevant variables
(that could be `Path` instances or not). If the list would only have a
single element it doesn\'t have to be passed in as a list (as in the
example). The second parameter should be a string with some help on
further getting rid of the call to `.mkstemp()`.

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "ruamel.std.pathlib",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3",
    "maintainer_email": "",
    "keywords": "",
    "author": "Anthon van der Neut",
    "author_email": "a.van.der.neut@ruamel.eu",
    "download_url": "https://files.pythonhosted.org/packages/1a/1d/f7a7fdf3765f5b05b595c9ac6e4ee1fffc990512b475f6a71abd1da341b4/ruamel.std.pathlib-0.13.0.tar.gz",
    "platform": null,
    "description": "\n# ruamel.std.pathlib\n\n[package ruamel.std.pathlib](https://bitbucket.org/ruamel/std.pathlib)\nis a drop-in replacement to extend the Python standard\n`pathlib` module.\n\nYou can just replace:\n\n    from pathlib import PosixPath, Path\n\nwith:\n\n    from ruamel.std.pathlib import PosixPath, Path\n\n[![image](https://sourceforge.net/p/ruamel-std-pathlib/code/ci/default/tree/_doc/_static/pypi.svg?format=raw)](https://pypi.org/project/ruamel.std.pathlib)\n[![image](https://sourceforge.net/p/ruamel-std-pathlib/code/ci/default/tree/_doc/_static/license.svg?format=raw)](https://opensource.org/licenses/MIT)\n[![image](https://sourceforge.net/p/oitnb/code/ci/default/tree/_doc/_static/oitnb.svg?format=raw)](https://pypi.org/project/oitnb/)\n\nStarting with 0.8.0 `ruamel.std.pathlib` no longer supports Python 2\n\n## Extra Path functionality\n\n- alias `remove` for `unlink` on Path\n- add `copy()` and `rmtree()` from shutil to Path\n- add `hash()` to path return the `hashlib.new()` value on the file\n  content (defaults to \\'sha224\\', other algorithms can be given as\n  parameter: `print(p.hash('md5').hexdigest())`)\n- add `pushd()` and `popd()` to a (directory) Path (this keeps a stack\n  of potentially more than one entry).\n- add `rmtree()`, to call `shutil.rmtree()` on the Path\n- add `chdir()` to a (directory) Path\n- add `stabilise()` to a Path, to wait for it to no longer change,\n  `duration` (default 5 seconds), `recheck` (default 0.2s) can be set,\n  as well as message that is displayed once if not stable yet.\n\n### blake3\n\nwhen you have `blake3` installed (this is not a dependency for this package) and do\n`import ruamel.std.pathlib.blake3`, you can also use that method on\n`Path` instances.\n\n### json\n\nwhen you do `import ruamel.std.pathlib.json` this loads orjson/ujson/json (in that order)\nto a Path so you can do\n`data = path.json.load()` and `path.json.dump(data)`\n\n### msgpack\n\nwhen you have `ruamel.ext.msgpack` installed and do `import ruamel.std.pathlib.msgpack`\nand you have a `Path` instance `path` you can do\n`data = path.msgpack.load()` and `path.msgpack.dump(data)`\n\n### tar\n\nwhen you have `zstandard` installed and do `import ruamel.std.pathlib.tar`\nand you have a `Path` instance `path` you can do\n`with path.tar.open()` on a `.tar.zst` file with in memory decompression.\n\n\n## Transition helper\n\nIf you are starting to use the standard pathlib library, it is\ncumbersome to change everything at once, and also to change all the\narguments to calls to `os.path.join`, `os.rename`, `os.path.dirname` to\nbe made encapsulated in `str()`\n\nBy making an instance of `PathLibConversionHelper` named `pl` you can\nchange `os.path.join()` to `pl.path.join()`, etc., and then start\npassing in Path instances instead of strings.\n\n`PathLibConversionHelper` currently supports the following replacements for `os`,\n\n:   `os.path`, `shutil` and built-in functions:\n\n        .chdir()             replaces: os.chdir()\n        .copy()              replaces: shutil.copy()\n        .glob()              replaces: glob.glob()\n        .listdir()           replaces: os.listdir()\n        .makedirs()          replaces: os.makedirs()\n        .mkstemp()           replaces: tempfile.mkstemp()\n        .open()              replaces: built-in open()\n        .path.basename()     replaces: os.path.basename()\n        .path.dirname()      replaces: os.path.dirname()\n        .path.exists()       replaces: os.path.exists()\n        .path.expanduser()   replaces: os.path.expanduser()\n        .path.getmtime()     replaces: os.path.getmtime()\n        .path.isdir()        replaces: os.path.isdir()\n        .path.join()         replaces: os.path.join()\n        .path.splitext()     replaces: os.path.splitext()\n        .remove()            replaces: os.remove()\n        .rename()            replaces: os.rename()\n        .rmdir()             replaces: os.rmdir()\n        .rmtree()            replaces: shutil.rmtree()\n        .walk()              replaces: os.walk()\n\nYou can provide a check level when you create the\n`PathLibConversionHelper()` instance.\n\n-   If check is non-zero, all calls are being logged and the invocations\n    can be dumped e.g. at the end of the program with\n    `pl.dump(stream, show_all=False)` This will include the number of\n    invocations not using Path (and using Path uniquely as well if\n    `show_all=True`)\n-   If check is greater than 1, first usage is dumped immediately.\n\nIf you start with the following code:\n\n    # coding: utf-8\n\n    import os\n    import glob\n    import tempfile\n    import shutil\n    import random\n\n\n    class TempDir(object):\n        \"\"\"self removing (unless keep=True) temporary directory\"\"\"\n        def __init__(self, keep=False, basedir=None, prefix=None):\n            self._keep = keep\n            # mkdtemp creates with permissions rwx------\n            kw = dict(dir=basedir)\n            if prefix is not None:\n                kw['prefix'] = prefix\n            # mkdtemp doesn't do the right thing if None is passed in\n            # as it has prefix=template in definition\n            self._tmpdir = tempfile.mkdtemp(**kw)\n\n        def remove(self):\n            shutil.rmtree(self._tmpdir)\n\n        def chdir(self):\n            os.chdir(self._tmpdir)\n\n        def tempfilename(self, extension=''):\n            fd, name = tempfile.mkstemp(suffix=extension, dir=self._tmpdir)\n            os.close(fd)\n            return name\n\n        def tempfilename2(self, extension=''):\n            while True:\n                name = os.path.join(\n                    self._tmpdir,\n                    '%08d' % random.randint(0, 100000) + extension\n                )\n                if not os.path.exists(name):\n                    break\n            return name\n\n        @property\n        def directory(self):\n            return self._tmpdir\n\n        def __enter__(self):\n            return self\n\n        def __exit__(self, exc_type, exc_val, exc_tb):\n            if not self._keep:\n                self.remove()\n\n\n    def main():\n        \"\"\"contrived example using TempDir\"\"\"\n        org_dir = os.getcwd()\n        with TempDir() as td:\n            for n in range(3):\n                t1 = td.tempfilename(extension='.sample')\n                with open(t1, 'w') as fp:\n                    fp.write('content\\n')\n            t2 = td.tempfilename2(extension='.sample2')\n            with open(t2, 'w') as fp:\n                fp.write('content\\n')\n            os.chdir(td.directory)\n            count = 0\n            for file_name in glob.glob('*.samp*'):\n                full_name = os.path.join(os.getcwd(), file_name)  # noqa\n                # print(full_name)\n                count += 1\n            os.chdir('/tmp')  # not using Path\n            os.chdir(org_dir)\n        print('{} files found in temporary directory'.format(count))\n\n    main()\n\nyou get:\n\n    4 files found in temporary directory\n\nWhen you start to change `TempDir()` to store the actual directory as a\nPath, things start to break immediately:\n\n    # coding: utf-8\n\n    import os\n    import glob\n    import tempfile\n    import shutil\n    import random\n\n    from ruamel.std.pathlib import Path                                   # added\n\n\n    class TempDir(object):\n        \"\"\"self removing (unless keep=True) temporary directory\"\"\"\n        def __init__(self, keep=False, basedir=None, prefix=None):\n            self._keep = keep\n            # mkdtemp creates with permissions rwx------\n            kw = dict(dir=basedir)\n            if prefix is not None:\n                kw['prefix'] = prefix\n            # mkdtemp doesn't do the right thing if None is passed in\n            # as it has prefix=template in definition\n            self._tmpdir = Path(tempfile.mkdtemp(**kw))                   # changed\n\n        def remove(self):\n            shutil.rmtree(self._tmpdir)\n\n        def chdir(self):\n            os.chdir(self._tmpdir)\n\n        def tempfilename(self, extension=''):\n            fd, name = tempfile.mkstemp(suffix=extension, dir=self._tmpdir)\n            os.close(fd)\n            return name\n\n        def tempfilename2(self, extension=''):\n            while True:\n                name = os.path.join(\n                    self._tmpdir,\n                    '%08d' % random.randint(0, 100000) + extension\n                )\n                if not os.path.exists(name):\n                    break\n            return name\n\n        @property\n        def directory(self):\n            return self._tmpdir\n\n        def __enter__(self):\n            return self\n\n        def __exit__(self, exc_type, exc_val, exc_tb):\n            if not self._keep:\n                self.remove()\n\n\n    def main():\n        \"\"\"contrived example using TempDir\"\"\"\n        org_dir = os.getcwd()\n        with TempDir() as td:\n            for n in range(3):\n                t1 = td.tempfilename(extension='.sample')\n                with open(t1, 'w') as fp:\n                    fp.write('content\\n')\n            t2 = td.tempfilename2(extension='.sample2')\n            with open(t2, 'w') as fp:\n                fp.write('content\\n')\n            os.chdir(td.directory)\n            count = 0\n            for file_name in glob.glob('*.samp*'):\n                full_name = os.path.join(os.getcwd(), file_name)  # noqa\n                # print(full_name)\n                count += 1\n            os.chdir('/tmp')  # not using Path\n            os.chdir(org_dir)\n        print('{} files found in temporary directory'.format(count))\n\n    main()\n\nWith some errors:\n\n    Traceback (most recent call last):\n      File \"_example/stage1.py\", line 80, in <module>\n        main()\n      File \"_example/stage1.py\", line 77, in main\n        os.chdir(org_dir)\n      File \"_example/stage1.py\", line 56, in __exit__\n        self.remove()\n      File \"_example/stage1.py\", line 27, in remove\n        shutil.rmtree(self._tmpdir)\n      File \"/opt/python/2.7.13/lib/python2.7/shutil.py\", line 228, in rmtree\n        if os.path.islink(path):\n      File \"/home/venv/dev/lib/python2.7/posixpath.py\", line 135, in islink\n        st = os.lstat(path)\n    TypeError: coercing to Unicode: need string or buffer, PosixPath found\n\nInstead of changing every usage in your program in one go, and hope it\nwill work again, you replace the routines from the standard module:\n\n    # coding: utf-8\n\n    import os\n    import glob\n    import tempfile\n    import shutil                       # noqa\n    import random\n\n    from ruamel.std.pathlib import Path, PathLibConversionHelper            # changed\n    pl = PathLibConversionHelper()                                          # added\n\n\n    class TempDir(object):\n        \"\"\"self removing (unless keep=True) temporary directory\"\"\"\n        def __init__(self, keep=False, basedir=None, prefix=None):\n            self._keep = keep\n            # mkdtemp creates with permissions rwx------\n            kw = dict(dir=basedir)\n            if prefix is not None:\n                kw['prefix'] = prefix\n            # mkdtemp doesn't do the right thing if None is passed in\n            # as it has prefix=template in definition\n            self._tmpdir = Path(tempfile.mkdtemp(**kw))\n\n        def remove(self):\n            pl.rmtree(self._tmpdir)\n\n        def chdir(self):\n            os.chdir(self._tmpdir)\n\n        def tempfilename(self, extension=''):\n            fd, name = pl.mkstemp(suffix=extension, dir=self._tmpdir)     # changed\n            os.close(fd)\n            return name\n\n        def tempfilename2(self, extension=''):\n            while True:\n                name = pl.path.join(\n                    self._tmpdir,\n                    '%08d' % random.randint(0, 100000) + extension\n                )\n                if not pl.path.exists(name):                              # changed\n                    break\n            return name\n\n        @property\n        def directory(self):\n            return self._tmpdir\n\n        def __enter__(self):\n            return self\n\n        def __exit__(self, exc_type, exc_val, exc_tb):\n            if not self._keep:\n                self.remove()\n\n\n    def main():\n        \"\"\"contrived example using TempDir\"\"\"\n        org_dir = os.getcwd()\n        with TempDir() as td:\n            for n in range(3):\n                t1 = td.tempfilename(extension='.sample')\n                with open(t1, 'w') as fp:\n                    fp.write('content\\n')\n            t2 = td.tempfilename2(extension='.sample2')\n            with pl.open(t2, 'w') as fp:\n                c = 'content\\n'                                           # added\n                if not isinstance(fp, file):                              # added\n                    c = unicode(c)                                        # added\n                fp.write(c)                                               # changed\n            pl.chdir(td.directory)\n            count = 0\n            for file_name in glob.glob('*.samp*'):\n                full_name = pl.path.join(os.getcwd(), file_name)  # noqa  # changed\n                # print(full_name)\n                count += 1\n            pl.chdir('/tmp')  # not using Path\n            pl.chdir(org_dir)                                             # changed\n        print('{} files found in temporary directory'.format(count))\n\n    main()\n\ngiving (again):\n\n    4 files found in temporary directory\n\nChange back just the creation of `self._tempdir` to the original:\n\n    self._tmpdir = tempfile.mkdtemp(**kw)\n\nand the output stays:\n\n    4 files found in temporary directory\n\nIf you now change the creation of `pl` to:\n\n    pl = PathLibConversionHelper(check=2)\n\nyou get as output:\n\n    update .mkstemp to use Path.mkstemp() [_example/stage3.py:34 / Path (True,)]\n    update .path.join to use \"/\" [_example/stage3.py:42 / Path (True, False)]\n    update .exists to use Path.exists() [_example/stage3.py:44 / Path (True,)]\n    update .open to use Path.open() [_example/stage3.py:69 / Path (True,)]\n    update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage3.py:74 / Path (True,)]\n    update .path.join to use \"/\" [_example/stage3.py:77 / Path (False, False)]\n    update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage3.py:80 / Path (False,)]\n    update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage3.py:81 / Path (False,)]\n    update .rmtree to use Path.rmtree() or shutil.rmtree(str(Path)) [_example/stage3.py:28 / Path (True,)]\n    4 files found in temporary directory\n\nIf you use `check=1` and at the end `pl.dump()`, you get:\n\n    4 files found in temporary directory\n    update .path.join to use \"/\" [_example/stage4.py:42 / 1 / Path (True, False)]\n    update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage4.py:81 / 1 / Path (False,)]\n    update .path.join to use \"/\" [_example/stage4.py:77 / 4 / Path (False, False)]\n    update .chdir to use Path.chdir() or os.chdir(str(Path)) [_example/stage4.py:80 / 1 / Path (False,)]\n\nshowing where you still use string based paths/filenames.\n\nThe message part `file_name.py: 123 / 2 / Path (True, False)` means that\nthere were two calls on line 123 in `file_name.py` and that they were\ncalled with the first parameter being a Path, the second not being a\nPath (when replacing `os.path.join()` with Path\\'s `\"/\"` concatenation\noperator that would be a good starting point, for other situation you\nmight want to convert the second parameter to a Path instance as well).\n\n## Extending `PathLibConversionHelper`\n\nIf `PathLibConversionHelper` doesn\\'t contain a particular function\n(yet) you can easily subclass it and add your own:\n\n    from ruamel.std.pathlib import Path, PathLibConversionHelper\n\n\n    class MyPLCH(PathLibConversionHelper):\n        # an example, ruamel.std.pathlib already adds mkstemp\n        def mkstemp(self, suffix=\"\", prefix=None, dir=None, text=False):\n            import tempfile\n            # would be much better if prefix defaults to built-in value (int, None, string)\n            if prefix is None:\n                prefix = tempfile.template\n            self.__add_usage(dir, 'update .mkstemp to use Path.mkstemp()')\n            if isinstance(dir, Path):\n                dir = str(dir)\n            return tempfile.mkstemp(suffix, prefix, dir, text)\n\n    pl = MyPLCH(check=1)\n\nThe first parameter for `self.add_usage()` is used to determine if a\nPath is used or not. This should be a list of all relevant variables\n(that could be `Path` instances or not). If the list would only have a\nsingle element it doesn\\'t have to be passed in as a list (as in the\nexample). The second parameter should be a string with some help on\nfurther getting rid of the call to `.mkstemp()`.\n",
    "bugtrack_url": null,
    "license": "MIT License",
    "summary": "improvements over the standard pathlib module and pathlib2 package",
    "version": "0.13.0",
    "project_urls": {
        "Home": "https://sourceforge.net/p/ruamel-std-pathlib/",
        "Source": "https://sourceforge.net/p/ruamel-std-pathlib/code/ci/default/tree/",
        "Tracker": "https://sourceforge.net/p/ruamel-std-pathlib/tickets/"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c935bce6e350012133d93075e14a604efd02c09b78788f8042b070192ded7a6d",
                "md5": "ed67a133d08eb109df498ca5c8d834e0",
                "sha256": "3af398d4f7294ca449890a2b33f8d0068471c2d3888da3b3e37fc025ea137229"
            },
            "downloads": -1,
            "filename": "ruamel.std.pathlib-0.13.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ed67a133d08eb109df498ca5c8d834e0",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3",
            "size": 14541,
            "upload_time": "2024-03-03T06:56:48",
            "upload_time_iso_8601": "2024-03-03T06:56:48.843621Z",
            "url": "https://files.pythonhosted.org/packages/c9/35/bce6e350012133d93075e14a604efd02c09b78788f8042b070192ded7a6d/ruamel.std.pathlib-0.13.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1a1df7a7fdf3765f5b05b595c9ac6e4ee1fffc990512b475f6a71abd1da341b4",
                "md5": "1a92e5eb5577815ad08dcf71d66aa1c0",
                "sha256": "1387e81655999851241b07f68569901ba4d502804094cde3c327b849ae702bb8"
            },
            "downloads": -1,
            "filename": "ruamel.std.pathlib-0.13.0.tar.gz",
            "has_sig": false,
            "md5_digest": "1a92e5eb5577815ad08dcf71d66aa1c0",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3",
            "size": 25509,
            "upload_time": "2024-03-03T06:56:51",
            "upload_time_iso_8601": "2024-03-03T06:56:51.383130Z",
            "url": "https://files.pythonhosted.org/packages/1a/1d/f7a7fdf3765f5b05b595c9ac6e4ee1fffc990512b475f6a71abd1da341b4/ruamel.std.pathlib-0.13.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-03 06:56:51",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "ruamel.std.pathlib"
}
        
Elapsed time: 0.19435s