CINXE.COM
PEP 428 – The pathlib module – object-oriented filesystem paths | peps.python.org
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 428 – The pathlib module – object-oriented filesystem paths | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0428/"> <link rel="stylesheet" href="../_static/style.css" type="text/css"> <link rel="stylesheet" href="../_static/mq.css" type="text/css"> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light"> <link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark"> <link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss"> <meta property="og:title" content='PEP 428 – The pathlib module – object-oriented filesystem paths | peps.python.org'> <meta property="og:description" content="This PEP proposes the inclusion of a third-party module, pathlib, in the standard library. The inclusion is proposed under the provisional label, as described in PEP 411. Therefore, API changes can be done, either as part of the PEP process, or after ..."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0428/"> <meta property="og:site_name" content="Python Enhancement Proposals (PEPs)"> <meta property="og:image" content="https://peps.python.org/_static/og-image.png"> <meta property="og:image:alt" content="Python PEPs"> <meta property="og:image:width" content="200"> <meta property="og:image:height" content="200"> <meta name="description" content="This PEP proposes the inclusion of a third-party module, pathlib, in the standard library. The inclusion is proposed under the provisional label, as described in PEP 411. Therefore, API changes can be done, either as part of the PEP process, or after ..."> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 428</li> </ul> <button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())"> <svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg> <span class="visually-hidden">Toggle light / dark / auto colour theme</span> </button> </header> <article> <section id="pep-content"> <h1 class="page-title">PEP 428 – The pathlib module – object-oriented filesystem paths</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Antoine Pitrou <solipsis at pitrou.net></dd> <dt class="field-even">Status<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd> <dt class="field-odd">Type<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd> <dt class="field-even">Created<span class="colon">:</span></dt> <dd class="field-even">30-Jul-2012</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">3.4</dd> <dt class="field-even">Post-History<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2012-October/016338.html" title="Python-Ideas message">05-Oct-2012</a></dd> <dt class="field-odd">Resolution<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2013-November/130424.html">Python-Dev message</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#related-work">Related work</a></li> <li><a class="reference internal" href="#implementation">Implementation</a></li> <li><a class="reference internal" href="#why-an-object-oriented-api">Why an object-oriented API</a></li> <li><a class="reference internal" href="#proposal">Proposal</a><ul> <li><a class="reference internal" href="#class-hierarchy">Class hierarchy</a></li> <li><a class="reference internal" href="#no-confusion-with-builtins">No confusion with builtins</a></li> <li><a class="reference internal" href="#immutability">Immutability</a></li> <li><a class="reference internal" href="#sane-behaviour">Sane behaviour</a></li> <li><a class="reference internal" href="#comparisons">Comparisons</a></li> <li><a class="reference internal" href="#useful-notations">Useful notations</a></li> </ul> </li> <li><a class="reference internal" href="#pure-paths-api">Pure paths API</a><ul> <li><a class="reference internal" href="#definitions">Definitions</a></li> <li><a class="reference internal" href="#construction">Construction</a></li> <li><a class="reference internal" href="#representing">Representing</a></li> <li><a class="reference internal" href="#properties">Properties</a></li> <li><a class="reference internal" href="#deriving-new-paths">Deriving new paths</a><ul> <li><a class="reference internal" href="#joining">Joining</a></li> <li><a class="reference internal" href="#changing-the-path-s-final-component">Changing the path’s final component</a></li> <li><a class="reference internal" href="#making-the-path-relative">Making the path relative</a></li> </ul> </li> <li><a class="reference internal" href="#sequence-like-access">Sequence-like access</a></li> <li><a class="reference internal" href="#querying">Querying</a></li> </ul> </li> <li><a class="reference internal" href="#concrete-paths-api">Concrete paths API</a><ul> <li><a class="reference internal" href="#constructing">Constructing</a></li> <li><a class="reference internal" href="#file-metadata">File metadata</a></li> <li><a class="reference internal" href="#path-resolution">Path resolution</a></li> <li><a class="reference internal" href="#directory-walking">Directory walking</a></li> <li><a class="reference internal" href="#file-opening">File opening</a></li> <li><a class="reference internal" href="#filesystem-modification">Filesystem modification</a></li> </ul> </li> <li><a class="reference internal" href="#discussion">Discussion</a><ul> <li><a class="reference internal" href="#division-operator">Division operator</a></li> <li><a class="reference internal" href="#joinpath">joinpath()</a></li> <li><a class="reference internal" href="#case-sensitivity">Case-sensitivity</a></li> </ul> </li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>This PEP proposes the inclusion of a third-party module, <a class="reference external" href="http://pypi.python.org/pypi/pathlib/">pathlib</a>, in the standard library. The inclusion is proposed under the provisional label, as described in <a class="pep reference internal" href="../pep-0411/" title="PEP 411 – Provisional packages in the Python standard library">PEP 411</a>. Therefore, API changes can be done, either as part of the PEP process, or after acceptance in the standard library (and until the provisional label is removed).</p> <p>The aim of this library is to provide a simple hierarchy of classes to handle filesystem paths and the common operations users do over them.</p> </section> <section id="related-work"> <h2><a class="toc-backref" href="#related-work" role="doc-backlink">Related work</a></h2> <p>An object-oriented API for filesystem paths has already been proposed and rejected in <a class="pep reference internal" href="../pep-0355/" title="PEP 355 – Path - Object oriented filesystem paths">PEP 355</a>. Several third-party implementations of the idea of object-oriented filesystem paths exist in the wild:</p> <ul class="simple"> <li>The historical <a class="reference external" href="https://github.com/jaraco/path.py">path.py module</a> by Jason Orendorff, Jason R. Coombs and others, which provides a <code class="docutils literal notranslate"><span class="pre">str</span></code>-subclassing <code class="docutils literal notranslate"><span class="pre">Path</span></code> class;</li> <li>Twisted’s slightly specialized <a class="reference external" href="http://twistedmatrix.com/documents/current/api/twisted.python.filepath.FilePath.html">FilePath class</a>;</li> <li>An <a class="reference external" href="http://wiki.python.org/moin/AlternativePathClass">AlternativePathClass proposal</a>, subclassing <code class="docutils literal notranslate"><span class="pre">tuple</span></code> rather than <code class="docutils literal notranslate"><span class="pre">str</span></code>;</li> <li><a class="reference external" href="https://bitbucket.org/sluggo/unipath/overview">Unipath</a>, a variation on the str-subclassing approach with two public classes, an <code class="docutils literal notranslate"><span class="pre">AbstractPath</span></code> class for operations which don’t do I/O and a <code class="docutils literal notranslate"><span class="pre">Path</span></code> class for all common operations.</li> </ul> <p>This proposal attempts to learn from these previous attempts and the rejection of <a class="pep reference internal" href="../pep-0355/" title="PEP 355 – Path - Object oriented filesystem paths">PEP 355</a>.</p> </section> <section id="implementation"> <h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2> <p>The implementation of this proposal is tracked in the <code class="docutils literal notranslate"><span class="pre">pep428</span></code> branch of pathlib’s <a class="reference external" href="https://bitbucket.org/pitrou/pathlib/">Mercurial repository</a>.</p> </section> <section id="why-an-object-oriented-api"> <h2><a class="toc-backref" href="#why-an-object-oriented-api" role="doc-backlink">Why an object-oriented API</a></h2> <p>The rationale to represent filesystem paths using dedicated classes is the same as for other kinds of stateless objects, such as dates, times or IP addresses. Python has been slowly moving away from strictly replicating the C language’s APIs to providing better, more helpful abstractions around all kinds of common functionality. Even if this PEP isn’t accepted, it is likely that another form of filesystem handling abstraction will be adopted one day into the standard library.</p> <p>Indeed, many people will prefer handling dates and times using the high-level objects provided by the <code class="docutils literal notranslate"><span class="pre">datetime</span></code> module, rather than using numeric timestamps and the <code class="docutils literal notranslate"><span class="pre">time</span></code> module API. Moreover, using a dedicated class allows to enable desirable behaviours by default, for example the case insensitivity of Windows paths.</p> </section> <section id="proposal"> <h2><a class="toc-backref" href="#proposal" role="doc-backlink">Proposal</a></h2> <section id="class-hierarchy"> <h3><a class="toc-backref" href="#class-hierarchy" role="doc-backlink">Class hierarchy</a></h3> <p>The <a class="reference external" href="http://pypi.python.org/pypi/pathlib/">pathlib</a> module implements a simple hierarchy of classes:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="o">+----------+</span> <span class="o">|</span> <span class="o">|</span> <span class="o">---------|</span> <span class="n">PurePath</span> <span class="o">|--------</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">+----------+</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="n">v</span> <span class="o">|</span> <span class="n">v</span> <span class="o">+---------------+</span> <span class="o">|</span> <span class="o">+-----------------+</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="n">PurePosixPath</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="n">PureWindowsPath</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">+---------------+</span> <span class="o">|</span> <span class="o">+-----------------+</span> <span class="o">|</span> <span class="n">v</span> <span class="o">|</span> <span class="o">|</span> <span class="o">+------+</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">-------|</span> <span class="n">Path</span> <span class="o">|------</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">+------+</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="n">v</span> <span class="n">v</span> <span class="n">v</span> <span class="n">v</span> <span class="o">+-----------+</span> <span class="o">+-------------+</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="n">PosixPath</span> <span class="o">|</span> <span class="o">|</span> <span class="n">WindowsPath</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">+-----------+</span> <span class="o">+-------------+</span> </pre></div> </div> <p>This hierarchy divides path classes along two dimensions:</p> <ul class="simple"> <li>a path class can be either pure or concrete: pure classes support only operations that don’t need to do any actual I/O, which are most path manipulation operations; concrete classes support all the operations of pure classes, plus operations that do I/O.</li> <li>a path class is of a given flavour according to the kind of operating system paths it represents. <a class="reference external" href="http://pypi.python.org/pypi/pathlib/">pathlib</a> implements two flavours: Windows paths for the filesystem semantics embodied in Windows systems, POSIX paths for other systems.</li> </ul> <p>Any pure class can be instantiated on any system: for example, you can manipulate <code class="docutils literal notranslate"><span class="pre">PurePosixPath</span></code> objects under Windows, <code class="docutils literal notranslate"><span class="pre">PureWindowsPath</span></code> objects under Unix, and so on. However, concrete classes can only be instantiated on a matching system: indeed, it would be error-prone to start doing I/O with <code class="docutils literal notranslate"><span class="pre">WindowsPath</span></code> objects under Unix, or vice-versa.</p> <p>Furthermore, there are two base classes which also act as system-dependent factories: <code class="docutils literal notranslate"><span class="pre">PurePath</span></code> will instantiate either a <code class="docutils literal notranslate"><span class="pre">PurePosixPath</span></code> or a <code class="docutils literal notranslate"><span class="pre">PureWindowsPath</span></code> depending on the operating system. Similarly, <code class="docutils literal notranslate"><span class="pre">Path</span></code> will instantiate either a <code class="docutils literal notranslate"><span class="pre">PosixPath</span></code> or a <code class="docutils literal notranslate"><span class="pre">WindowsPath</span></code>.</p> <p>It is expected that, in most uses, using the <code class="docutils literal notranslate"><span class="pre">Path</span></code> class is adequate, which is why it has the shortest name of all.</p> </section> <section id="no-confusion-with-builtins"> <h3><a class="toc-backref" href="#no-confusion-with-builtins" role="doc-backlink">No confusion with builtins</a></h3> <p>In this proposal, the path classes do not derive from a builtin type. This contrasts with some other Path class proposals which were derived from <code class="docutils literal notranslate"><span class="pre">str</span></code>. They also do not pretend to implement the sequence protocol: if you want a path to act as a sequence, you have to lookup a dedicated attribute (the <code class="docutils literal notranslate"><span class="pre">parts</span></code> attribute).</p> <p>The key reasoning behind not inheriting from <code class="docutils literal notranslate"><span class="pre">str</span></code> is to prevent accidentally performing operations with a string representing a path and a string that doesn’t, e.g. <code class="docutils literal notranslate"><span class="pre">path</span> <span class="pre">+</span> <span class="pre">an_accident</span></code>. Since operations with a string will not necessarily lead to a valid or expected file system path, “explicit is better than implicit” by avoiding accidental operations with strings by not subclassing it. A <a class="reference external" href="http://www.snarky.ca/why-pathlib-path-doesn-t-inherit-from-str">blog post</a> by a Python core developer goes into more detail on the reasons behind this specific design decision.</p> </section> <section id="immutability"> <h3><a class="toc-backref" href="#immutability" role="doc-backlink">Immutability</a></h3> <p>Path objects are immutable, which makes them hashable and also prevents a class of programming errors.</p> </section> <section id="sane-behaviour"> <h3><a class="toc-backref" href="#sane-behaviour" role="doc-backlink">Sane behaviour</a></h3> <p>Little of the functionality from os.path is reused. Many os.path functions are tied by backwards compatibility to confusing or plain wrong behaviour (for example, the fact that <code class="docutils literal notranslate"><span class="pre">os.path.abspath()</span></code> simplifies “..” path components without resolving symlinks first).</p> </section> <section id="comparisons"> <h3><a class="toc-backref" href="#comparisons" role="doc-backlink">Comparisons</a></h3> <p>Paths of the same flavour are comparable and orderable, whether pure or not:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span> <span class="o">==</span> <span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'b'</span><span class="p">)</span> <span class="go">False</span> <span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span> <span class="o"><</span> <span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'b'</span><span class="p">)</span> <span class="go">True</span> <span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span> <span class="o">==</span> <span class="n">PosixPath</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span> <span class="go">True</span> </pre></div> </div> <p>Comparing and ordering Windows path objects is case-insensitive:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span> <span class="o">==</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)</span> <span class="go">True</span> </pre></div> </div> <p>Paths of different flavours always compare unequal, and cannot be ordered:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span> <span class="o">==</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span> <span class="go">False</span> <span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span> <span class="o"><</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span> <span class="gt">Traceback (most recent call last):</span> File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span> <span class="gr">TypeError</span>: <span class="n">unorderable types: PurePosixPath() < PureWindowsPath()</span> </pre></div> </div> <p>Paths compare unequal to, and are not orderable with instances of builtin types (such as <code class="docutils literal notranslate"><span class="pre">str</span></code>) and any other types.</p> </section> <section id="useful-notations"> <h3><a class="toc-backref" href="#useful-notations" role="doc-backlink">Useful notations</a></h3> <p>The API tries to provide useful notations all the while avoiding magic. Some examples:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s1">'/home/antoine/pathlib/setup.py'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">name</span> <span class="go">'setup.py'</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">suffix</span> <span class="go">'.py'</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">root</span> <span class="go">'/'</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">parts</span> <span class="go">('/', 'home', 'antoine', 'pathlib', 'setup.py')</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">relative_to</span><span class="p">(</span><span class="s1">'/home/antoine'</span><span class="p">)</span> <span class="go">PosixPath('pathlib/setup.py')</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span> <span class="go">True</span> </pre></div> </div> </section> </section> <section id="pure-paths-api"> <h2><a class="toc-backref" href="#pure-paths-api" role="doc-backlink">Pure paths API</a></h2> <p>The philosophy of the <code class="docutils literal notranslate"><span class="pre">PurePath</span></code> API is to provide a consistent array of useful path manipulation operations, without exposing a hodge-podge of functions like <code class="docutils literal notranslate"><span class="pre">os.path</span></code> does.</p> <section id="definitions"> <h3><a class="toc-backref" href="#definitions" role="doc-backlink">Definitions</a></h3> <p>First a couple of conventions:</p> <ul class="simple"> <li>All paths can have a drive and a root. For POSIX paths, the drive is always empty.</li> <li>A relative path has neither drive nor root.</li> <li>A POSIX path is absolute if it has a root. A Windows path is absolute if it has both a drive <em>and</em> a root. A Windows UNC path (e.g. <code class="docutils literal notranslate"><span class="pre">\\host\share\myfile.txt</span></code>) always has a drive and a root (here, <code class="docutils literal notranslate"><span class="pre">\\host\share</span></code> and <code class="docutils literal notranslate"><span class="pre">\</span></code>, respectively).</li> <li>A path which has either a drive <em>or</em> a root is said to be anchored. Its anchor is the concatenation of the drive and root. Under POSIX, “anchored” is the same as “absolute”.</li> </ul> </section> <section id="construction"> <h3><a class="toc-backref" href="#construction" role="doc-backlink">Construction</a></h3> <p>We will present construction and joining together since they expose similar semantics.</p> <p>The simplest way to construct a path is to pass it its string representation:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PurePath</span><span class="p">(</span><span class="s1">'setup.py'</span><span class="p">)</span> <span class="go">PurePosixPath('setup.py')</span> </pre></div> </div> <p>Extraneous path separators and <code class="docutils literal notranslate"><span class="pre">"."</span></code> components are eliminated:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PurePath</span><span class="p">(</span><span class="s1">'a///b/c/./d/'</span><span class="p">)</span> <span class="go">PurePosixPath('a/b/c/d')</span> </pre></div> </div> <p>If you pass several arguments, they will be automatically joined:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PurePath</span><span class="p">(</span><span class="s1">'docs'</span><span class="p">,</span> <span class="s1">'Makefile'</span><span class="p">)</span> <span class="go">PurePosixPath('docs/Makefile')</span> </pre></div> </div> <p>Joining semantics are similar to os.path.join, in that anchored paths ignore the information from the previously joined components:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PurePath</span><span class="p">(</span><span class="s1">'/etc'</span><span class="p">,</span> <span class="s1">'/usr'</span><span class="p">,</span> <span class="s1">'bin'</span><span class="p">)</span> <span class="go">PurePosixPath('/usr/bin')</span> </pre></div> </div> <p>However, with Windows paths, the drive is retained as necessary:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/foo'</span><span class="p">,</span> <span class="s1">'/Windows'</span><span class="p">)</span> <span class="go">PureWindowsPath('c:/Windows')</span> <span class="gp">>>> </span><span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/foo'</span><span class="p">,</span> <span class="s1">'d:'</span><span class="p">)</span> <span class="go">PureWindowsPath('d:')</span> </pre></div> </div> <p>Also, path separators are normalized to the platform default:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'a/b'</span><span class="p">)</span> <span class="o">==</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'a</span><span class="se">\\</span><span class="s1">b'</span><span class="p">)</span> <span class="go">True</span> </pre></div> </div> <p>Extraneous path separators and <code class="docutils literal notranslate"><span class="pre">"."</span></code> components are eliminated, but not <code class="docutils literal notranslate"><span class="pre">".."</span></code> components:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'a//b/./c/'</span><span class="p">)</span> <span class="go">PurePosixPath('a/b/c')</span> <span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'a/../b'</span><span class="p">)</span> <span class="go">PurePosixPath('a/../b')</span> </pre></div> </div> <p>Multiple leading slashes are treated differently depending on the path flavour. They are always retained on Windows paths (because of the UNC notation):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'//some/path'</span><span class="p">)</span> <span class="go">PureWindowsPath('//some/path/')</span> </pre></div> </div> <p>On POSIX, they are collapsed except if there are exactly two leading slashes, which is a special case in the POSIX specification on <a class="reference external" href="http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11">pathname resolution</a> (this is also necessary for Cygwin compatibility):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'///some/path'</span><span class="p">)</span> <span class="go">PurePosixPath('/some/path')</span> <span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'//some/path'</span><span class="p">)</span> <span class="go">PurePosixPath('//some/path')</span> </pre></div> </div> <p>Calling the constructor without any argument creates a path object pointing to the logical “current directory” (without looking up its absolute path, which is the job of the <code class="docutils literal notranslate"><span class="pre">cwd()</span></code> classmethod on concrete paths):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">()</span> <span class="go">PurePosixPath('.')</span> </pre></div> </div> </section> <section id="representing"> <h3><a class="toc-backref" href="#representing" role="doc-backlink">Representing</a></h3> <p>To represent a path (e.g. to pass it to third-party libraries), just call <code class="docutils literal notranslate"><span class="pre">str()</span></code> on it:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PurePath</span><span class="p">(</span><span class="s1">'/home/antoine/pathlib/setup.py'</span><span class="p">)</span> <span class="gp">>>> </span><span class="nb">str</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="go">'/home/antoine/pathlib/setup.py'</span> <span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/windows'</span><span class="p">)</span> <span class="gp">>>> </span><span class="nb">str</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="go">'c:\\windows'</span> </pre></div> </div> <p>To force the string representation with forward slashes, use the <code class="docutils literal notranslate"><span class="pre">as_posix()</span></code> method:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">as_posix</span><span class="p">()</span> <span class="go">'c:/windows'</span> </pre></div> </div> <p>To get the bytes representation (which might be useful under Unix systems), call <code class="docutils literal notranslate"><span class="pre">bytes()</span></code> on it, which internally uses <code class="docutils literal notranslate"><span class="pre">os.fsencode()</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">bytes</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="go">b'/home/antoine/pathlib/setup.py'</span> </pre></div> </div> <p>To represent the path as a <code class="docutils literal notranslate"><span class="pre">file:</span></code> URI, call the <code class="docutils literal notranslate"><span class="pre">as_uri()</span></code> method:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'/etc/passwd'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">as_uri</span><span class="p">()</span> <span class="go">'file:///etc/passwd'</span> <span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/Windows'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">as_uri</span><span class="p">()</span> <span class="go">'file:///c:/Windows'</span> </pre></div> </div> <p>The repr() of a path always uses forward slashes, even under Windows, for readability and to remind users that forward slashes are ok:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/Windows'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span> <span class="go">PureWindowsPath('c:/Windows')</span> </pre></div> </div> </section> <section id="properties"> <h3><a class="toc-backref" href="#properties" role="doc-backlink">Properties</a></h3> <p>Several simple properties are provided on every path (each can be empty):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/Downloads/pathlib.tar.gz'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">drive</span> <span class="go">'c:'</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">root</span> <span class="go">'\\'</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">anchor</span> <span class="go">'c:\\'</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">name</span> <span class="go">'pathlib.tar.gz'</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">stem</span> <span class="go">'pathlib.tar'</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">suffix</span> <span class="go">'.gz'</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">suffixes</span> <span class="go">['.tar', '.gz']</span> </pre></div> </div> </section> <section id="deriving-new-paths"> <h3><a class="toc-backref" href="#deriving-new-paths" role="doc-backlink">Deriving new paths</a></h3> <section id="joining"> <h4><a class="toc-backref" href="#joining" role="doc-backlink">Joining</a></h4> <p>A path can be joined with another using the <code class="docutils literal notranslate"><span class="pre">/</span></code> operator:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'foo'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span> <span class="o">/</span> <span class="s1">'bar'</span> <span class="go">PurePosixPath('foo/bar')</span> <span class="gp">>>> </span><span class="n">p</span> <span class="o">/</span> <span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'bar'</span><span class="p">)</span> <span class="go">PurePosixPath('foo/bar')</span> <span class="gp">>>> </span><span class="s1">'bar'</span> <span class="o">/</span> <span class="n">p</span> <span class="go">PurePosixPath('bar/foo')</span> </pre></div> </div> <p>As with the constructor, multiple path components can be specified, either collapsed or separately:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">/</span> <span class="s1">'bar/xyzzy'</span> <span class="go">PurePosixPath('foo/bar/xyzzy')</span> <span class="gp">>>> </span><span class="n">p</span> <span class="o">/</span> <span class="s1">'bar'</span> <span class="o">/</span> <span class="s1">'xyzzy'</span> <span class="go">PurePosixPath('foo/bar/xyzzy')</span> </pre></div> </div> <p>A joinpath() method is also provided, with the same behaviour:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s1">'Python'</span><span class="p">)</span> <span class="go">PurePosixPath('foo/Python')</span> </pre></div> </div> </section> <section id="changing-the-path-s-final-component"> <h4><a class="toc-backref" href="#changing-the-path-s-final-component" role="doc-backlink">Changing the path’s final component</a></h4> <p>The <code class="docutils literal notranslate"><span class="pre">with_name()</span></code> method returns a new path, with the name changed:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/Downloads/pathlib.tar.gz'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">with_name</span><span class="p">(</span><span class="s1">'setup.py'</span><span class="p">)</span> <span class="go">PureWindowsPath('c:/Downloads/setup.py')</span> </pre></div> </div> <p>It fails with a <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> if the path doesn’t have an actual name:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">with_name</span><span class="p">(</span><span class="s1">'setup.py'</span><span class="p">)</span> <span class="gt">Traceback (most recent call last):</span> File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span> File <span class="nb">"pathlib.py"</span>, line <span class="m">875</span>, in <span class="n">with_name</span> <span class="w"> </span><span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">"</span><span class="si">%r</span><span class="s2"> has an empty name"</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="p">,))</span> <span class="gr">ValueError</span>: <span class="n">PureWindowsPath('c:/') has an empty name</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">name</span> <span class="go">''</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">with_suffix()</span></code> method returns a new path with the suffix changed. However, if the path has no suffix, the new suffix is added:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/Downloads/pathlib.tar.gz'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">with_suffix</span><span class="p">(</span><span class="s1">'.bz2'</span><span class="p">)</span> <span class="go">PureWindowsPath('c:/Downloads/pathlib.tar.bz2')</span> <span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'README'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">with_suffix</span><span class="p">(</span><span class="s1">'.bz2'</span><span class="p">)</span> <span class="go">PureWindowsPath('README.bz2')</span> </pre></div> </div> </section> <section id="making-the-path-relative"> <h4><a class="toc-backref" href="#making-the-path-relative" role="doc-backlink">Making the path relative</a></h4> <p>The <code class="docutils literal notranslate"><span class="pre">relative_to()</span></code> method computes the relative difference of a path to another:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'/usr/bin/python'</span><span class="p">)</span><span class="o">.</span><span class="n">relative_to</span><span class="p">(</span><span class="s1">'/usr'</span><span class="p">)</span> <span class="go">PurePosixPath('bin/python')</span> </pre></div> </div> <p>ValueError is raised if the method cannot return a meaningful value:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'/usr/bin/python'</span><span class="p">)</span><span class="o">.</span><span class="n">relative_to</span><span class="p">(</span><span class="s1">'/etc'</span><span class="p">)</span> <span class="gt">Traceback (most recent call last):</span> File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span> File <span class="nb">"pathlib.py"</span>, line <span class="m">926</span>, in <span class="n">relative_to</span> <span class="w"> </span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="p">),</span> <span class="nb">str</span><span class="p">(</span><span class="n">formatted</span><span class="p">)))</span> <span class="gr">ValueError</span>: <span class="n">'/usr/bin/python' does not start with '/etc'</span> </pre></div> </div> </section> </section> <section id="sequence-like-access"> <h3><a class="toc-backref" href="#sequence-like-access" role="doc-backlink">Sequence-like access</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">parts</span></code> property returns a tuple providing read-only sequence access to a path’s components:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'/etc/init.d'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">parts</span> <span class="go">('/', 'etc', 'init.d')</span> </pre></div> </div> <p>Windows paths handle the drive and the root as a single path component:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/setup.py'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">parts</span> <span class="go">('c:\\', 'setup.py')</span> </pre></div> </div> <p>(separating them would be wrong, since <code class="docutils literal notranslate"><span class="pre">C:</span></code> is not the parent of <code class="docutils literal notranslate"><span class="pre">C:\\</span></code>).</p> <p>The <code class="docutils literal notranslate"><span class="pre">parent</span></code> property returns the logical parent of the path:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/python33/bin/python.exe'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">parent</span> <span class="go">PureWindowsPath('c:/python33/bin')</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">parents</span></code> property returns an immutable sequence of the path’s logical ancestors:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PureWindowsPath</span><span class="p">(</span><span class="s1">'c:/python33/bin/python.exe'</span><span class="p">)</span> <span class="gp">>>> </span><span class="nb">len</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">parents</span><span class="p">)</span> <span class="go">3</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">parents</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="go">PureWindowsPath('c:/python33/bin')</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">parents</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="go">PureWindowsPath('c:/python33')</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">parents</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="go">PureWindowsPath('c:/')</span> </pre></div> </div> </section> <section id="querying"> <h3><a class="toc-backref" href="#querying" role="doc-backlink">Querying</a></h3> <p><code class="docutils literal notranslate"><span class="pre">is_relative()</span></code> returns True if the path is relative (see definition above), False otherwise.</p> <p><code class="docutils literal notranslate"><span class="pre">is_reserved()</span></code> returns True if a Windows path is a reserved path such as <code class="docutils literal notranslate"><span class="pre">CON</span></code> or <code class="docutils literal notranslate"><span class="pre">NUL</span></code>. It always returns False for POSIX paths.</p> <p><code class="docutils literal notranslate"><span class="pre">match()</span></code> matches the path against a glob pattern. It operates on individual parts and matches from the right:</p> <div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">PurePosixPath</span><span class="p">(</span><span class="s1">'/usr/bin'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="s1">'/usr/b*'</span><span class="p">)</span> <span class="go">True</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="s1">'usr/b*'</span><span class="p">)</span> <span class="go">True</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="s1">'b*'</span><span class="p">)</span> <span class="go">True</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="s1">'/u*'</span><span class="p">)</span> <span class="go">False</span> </pre></div> </div> <p>This behaviour respects the following expectations:</p> <ul class="simple"> <li>A simple pattern such as “*.py” matches arbitrarily long paths as long as the last part matches, e.g. “/usr/foo/bar.py”.</li> <li>Longer patterns can be used as well for more complex matching, e.g. “/usr/foo/*.py” matches “/usr/foo/bar.py”.</li> </ul> </section> </section> <section id="concrete-paths-api"> <h2><a class="toc-backref" href="#concrete-paths-api" role="doc-backlink">Concrete paths API</a></h2> <p>In addition to the operations of the pure API, concrete paths provide additional methods which actually access the filesystem to query or mutate information.</p> <section id="constructing"> <h3><a class="toc-backref" href="#constructing" role="doc-backlink">Constructing</a></h3> <p>The classmethod <code class="docutils literal notranslate"><span class="pre">cwd()</span></code> creates a path object pointing to the current working directory in absolute form:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">Path</span><span class="o">.</span><span class="n">cwd</span><span class="p">()</span> <span class="go">PosixPath('/home/antoine/pathlib')</span> </pre></div> </div> </section> <section id="file-metadata"> <h3><a class="toc-backref" href="#file-metadata" role="doc-backlink">File metadata</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">stat()</span></code> returns the file’s stat() result; similarly, <code class="docutils literal notranslate"><span class="pre">lstat()</span></code> returns the file’s lstat() result (which is different iff the file is a symbolic link):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">stat</span><span class="p">()</span> <span class="go">posix.stat_result(st_mode=33277, st_ino=7483155, st_dev=2053, st_nlink=1, st_uid=500, st_gid=500, st_size=928, st_atime=1343597970, st_mtime=1328287308, st_ctime=1343597964)</span> </pre></div> </div> <p>Higher-level methods help examine the kind of the file:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span> <span class="go">True</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">is_file</span><span class="p">()</span> <span class="go">True</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">is_dir</span><span class="p">()</span> <span class="go">False</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">is_symlink</span><span class="p">()</span> <span class="go">False</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">is_socket</span><span class="p">()</span> <span class="go">False</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">is_fifo</span><span class="p">()</span> <span class="go">False</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">is_block_device</span><span class="p">()</span> <span class="go">False</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">is_char_device</span><span class="p">()</span> <span class="go">False</span> </pre></div> </div> <p>The file owner and group names (rather than numeric ids) are queried through corresponding methods:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s1">'/etc/shadow'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">owner</span><span class="p">()</span> <span class="go">'root'</span> <span class="gp">>>> </span><span class="n">p</span><span class="o">.</span><span class="n">group</span><span class="p">()</span> <span class="go">'shadow'</span> </pre></div> </div> </section> <section id="path-resolution"> <h3><a class="toc-backref" href="#path-resolution" role="doc-backlink">Path resolution</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">resolve()</span></code> method makes a path absolute, resolving any symlink on the way (like the POSIX realpath() call). It is the only operation which will remove “<code class="docutils literal notranslate"><span class="pre">..</span></code>” path components. On Windows, this method will also take care to return the canonical path (with the right casing).</p> </section> <section id="directory-walking"> <h3><a class="toc-backref" href="#directory-walking" role="doc-backlink">Directory walking</a></h3> <p>Simple (non-recursive) directory access is done by calling the iterdir() method, which returns an iterator over the child paths:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s1">'docs'</span><span class="p">)</span> <span class="gp">>>> </span><span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">iterdir</span><span class="p">():</span> <span class="n">child</span> <span class="gp">...</span> <span class="go">PosixPath('docs/conf.py')</span> <span class="go">PosixPath('docs/_templates')</span> <span class="go">PosixPath('docs/make.bat')</span> <span class="go">PosixPath('docs/index.rst')</span> <span class="go">PosixPath('docs/_build')</span> <span class="go">PosixPath('docs/_static')</span> <span class="go">PosixPath('docs/Makefile')</span> </pre></div> </div> <p>This allows simple filtering through list comprehensions:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s1">'.'</span><span class="p">)</span> <span class="gp">>>> </span><span class="p">[</span><span class="n">child</span> <span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">iterdir</span><span class="p">()</span> <span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">is_dir</span><span class="p">()]</span> <span class="go">[PosixPath('.hg'), PosixPath('docs'), PosixPath('dist'), PosixPath('__pycache__'), PosixPath('build')]</span> </pre></div> </div> <p>Simple and recursive globbing is also provided:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s1">'**/*.py'</span><span class="p">):</span> <span class="n">child</span> <span class="gp">...</span> <span class="go">PosixPath('test_pathlib.py')</span> <span class="go">PosixPath('setup.py')</span> <span class="go">PosixPath('pathlib.py')</span> <span class="go">PosixPath('docs/conf.py')</span> <span class="go">PosixPath('build/lib/pathlib.py')</span> </pre></div> </div> </section> <section id="file-opening"> <h3><a class="toc-backref" href="#file-opening" role="doc-backlink">File opening</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">open()</span></code> method provides a file opening API similar to the builtin <code class="docutils literal notranslate"><span class="pre">open()</span></code> method:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s1">'setup.py'</span><span class="p">)</span> <span class="gp">>>> </span><span class="k">with</span> <span class="n">p</span><span class="o">.</span><span class="n">open</span><span class="p">()</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span> <span class="n">f</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span> <span class="gp">...</span> <span class="go">'#!/usr/bin/env python3\n'</span> </pre></div> </div> </section> <section id="filesystem-modification"> <h3><a class="toc-backref" href="#filesystem-modification" role="doc-backlink">Filesystem modification</a></h3> <p>Several common filesystem operations are provided as methods: <code class="docutils literal notranslate"><span class="pre">touch()</span></code>, <code class="docutils literal notranslate"><span class="pre">mkdir()</span></code>, <code class="docutils literal notranslate"><span class="pre">rename()</span></code>, <code class="docutils literal notranslate"><span class="pre">replace()</span></code>, <code class="docutils literal notranslate"><span class="pre">unlink()</span></code>, <code class="docutils literal notranslate"><span class="pre">rmdir()</span></code>, <code class="docutils literal notranslate"><span class="pre">chmod()</span></code>, <code class="docutils literal notranslate"><span class="pre">lchmod()</span></code>, <code class="docutils literal notranslate"><span class="pre">symlink_to()</span></code>. More operations could be provided, for example some of the functionality of the shutil module.</p> <p>Detailed documentation of the proposed API can be found at the <a class="reference external" href="https://pathlib.readthedocs.org/en/pep428/">pathlib docs</a>.</p> </section> </section> <section id="discussion"> <h2><a class="toc-backref" href="#discussion" role="doc-backlink">Discussion</a></h2> <section id="division-operator"> <h3><a class="toc-backref" href="#division-operator" role="doc-backlink">Division operator</a></h3> <p>The division operator came out first in a <a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2012-October/016544.html">poll</a> about the path joining operator. Initial versions of <a class="reference external" href="http://pypi.python.org/pypi/pathlib/">pathlib</a> used square brackets (i.e. <code class="docutils literal notranslate"><span class="pre">__getitem__</span></code>) instead.</p> </section> <section id="joinpath"> <h3><a class="toc-backref" href="#joinpath" role="doc-backlink">joinpath()</a></h3> <p>The joinpath() method was initially called join(), but several people objected that it could be confused with str.join() which has different semantics. Therefore, it was renamed to joinpath().</p> </section> <section id="case-sensitivity"> <h3><a class="toc-backref" href="#case-sensitivity" role="doc-backlink">Case-sensitivity</a></h3> <p>Windows users consider filesystem paths to be case-insensitive and expect path objects to observe that characteristic, even though in some rare situations some foreign filesystem mounts may be case-sensitive under Windows.</p> <p>In the words of one commenter,</p> <blockquote> <div>“If glob(”*.py”) failed to find SETUP.PY on Windows, that would be a usability disaster”.<p class="attribution">—Paul Moore in <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2013-April/125254.html">https://mail.python.org/pipermail/python-dev/2013-April/125254.html</a></p> </div></blockquote> </section> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document has been placed into the public domain.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0428.rst">https://github.com/python/peps/blob/main/peps/pep-0428.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0428.rst">2025-02-01 08:59:27 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#related-work">Related work</a></li> <li><a class="reference internal" href="#implementation">Implementation</a></li> <li><a class="reference internal" href="#why-an-object-oriented-api">Why an object-oriented API</a></li> <li><a class="reference internal" href="#proposal">Proposal</a><ul> <li><a class="reference internal" href="#class-hierarchy">Class hierarchy</a></li> <li><a class="reference internal" href="#no-confusion-with-builtins">No confusion with builtins</a></li> <li><a class="reference internal" href="#immutability">Immutability</a></li> <li><a class="reference internal" href="#sane-behaviour">Sane behaviour</a></li> <li><a class="reference internal" href="#comparisons">Comparisons</a></li> <li><a class="reference internal" href="#useful-notations">Useful notations</a></li> </ul> </li> <li><a class="reference internal" href="#pure-paths-api">Pure paths API</a><ul> <li><a class="reference internal" href="#definitions">Definitions</a></li> <li><a class="reference internal" href="#construction">Construction</a></li> <li><a class="reference internal" href="#representing">Representing</a></li> <li><a class="reference internal" href="#properties">Properties</a></li> <li><a class="reference internal" href="#deriving-new-paths">Deriving new paths</a><ul> <li><a class="reference internal" href="#joining">Joining</a></li> <li><a class="reference internal" href="#changing-the-path-s-final-component">Changing the path’s final component</a></li> <li><a class="reference internal" href="#making-the-path-relative">Making the path relative</a></li> </ul> </li> <li><a class="reference internal" href="#sequence-like-access">Sequence-like access</a></li> <li><a class="reference internal" href="#querying">Querying</a></li> </ul> </li> <li><a class="reference internal" href="#concrete-paths-api">Concrete paths API</a><ul> <li><a class="reference internal" href="#constructing">Constructing</a></li> <li><a class="reference internal" href="#file-metadata">File metadata</a></li> <li><a class="reference internal" href="#path-resolution">Path resolution</a></li> <li><a class="reference internal" href="#directory-walking">Directory walking</a></li> <li><a class="reference internal" href="#file-opening">File opening</a></li> <li><a class="reference internal" href="#filesystem-modification">Filesystem modification</a></li> </ul> </li> <li><a class="reference internal" href="#discussion">Discussion</a><ul> <li><a class="reference internal" href="#division-operator">Division operator</a></li> <li><a class="reference internal" href="#joinpath">joinpath()</a></li> <li><a class="reference internal" href="#case-sensitivity">Case-sensitivity</a></li> </ul> </li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0428.rst">Page Source (GitHub)</a> </nav> </section> <script src="../_static/colour_scheme.js"></script> <script src="../_static/wrap_tables.js"></script> <script src="../_static/sticky_banner.js"></script> </body> </html>