# Support for pathlib

**URL:** https://discourse.vtk.org/t/support-for-pathlib/5085
**Category:** Development
**Created:** [January 28, 2021, 11:17pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085 "2021-01-28T23:17:47Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![fepegar](https://discourse.vtk.org/user_avatar/discourse.vtk.org/fepegar/32/2244_2.png) [@fepegar](https://discourse.vtk.org/u/fepegar)
#### Post date: [January 28, 2021, 11:17pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/1 "2021-01-28T23:17:47Z")

</div>

Hi all,

Are there any plans to add [`pathlib`](https://docs.python.org/3/library/pathlib.html) support for the Python wrappers?

(I’ve been recommended to ping @dgobbi about this)

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [January 29, 2021, 4:51am UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/2 "2021-01-29T04:51:51Z")

</div>

No, there are no plans. I’m not sure what pathlib has to do with VTK? What VTK-related problems does it solve?

---

<div class="post-metadata">

### Author: ![fepegar](https://discourse.vtk.org/user_avatar/discourse.vtk.org/fepegar/32/2244_2.png) [@fepegar](https://discourse.vtk.org/u/fepegar)
#### Post date: [January 29, 2021, 9:34am UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/3 "2021-01-29T09:34:04Z")

</div>

Hi @dgobbi, thanks for your reply.

It’s a built-in Python module that helps with path handling. It was introduced in Python 3.4, for which VTK has support, so it’s indirectly related to VTK through the Python wrappers. It wouldn’t solve VTK-related problems, but it would improve Python support.

This is an example form [the Slicer forum](https://discourse.slicer.org/t/support-for-pathlib/9131?u=fernando) before and after using `pathlib`:

```python
import os
myDir = '/tmp/images'
for root, dirs, files in os.walk(myDir, topdown=False):
    for name in files:
        _, ext = os.splitext(name)
        if ext == '.nrrd':
            loadVolume(os.path.join(root, name))

```

```python
from pathlib import Path
myDir = Path('/tmp/images')
for file in myDir.glob('**/*.nrrd'):
    loadVolume(str(file)) # need str until pathlib is supported

```

Here are some large Python libraries getting adapted to `pathlib`:

[`nibabel`](https://github.com/nipy/nibabel/pull/610) (23/10/2019)  
[`pandas`](https://github.com/pandas-dev/pandas/blob/325dd686de1589c17731cf93b649ed5ccb5a99b4/pandas/io/common.py#L131-L160) ([10/9/2015](https://github.com/pandas-dev/pandas/pull/11051))  
[`numpy`](https://github.com/numpy/numpy/issues/6418) (6/10/2015)  
[`Pillow`](https://github.com/python-pillow/Pillow/issues/1368) (3/8/2015)  
[`matplotlib`](https://github.com/matplotlib/matplotlib/pull/6788) (18/7/2016)

Related Python Enhancement Proposals (PEP):  
[PEP 428 – The pathlib module – object-oriented filesystem paths](https://www.python.org/dev/peps/pep-0428/)  
[PEP 519 – Adding a file system path protocol](https://www.python.org/dev/peps/pep-0519/)

Some more context on the advantages of `pathlib`: [https://realpython.com/python-pathlib/#the-problem-with-python-file-path-handling](https://realpython.com/python-pathlib/#the-problem-with-python-file-path-handling)

I hope that makes sense and is a bit more clear than my previous post.

---

<div class="post-metadata">

### Author: ![efahl](https://discourse.vtk.org/user_avatar/discourse.vtk.org/efahl/32/1087_2.png) [@efahl](https://discourse.vtk.org/u/efahl)
#### Post date: [January 29, 2021, 2:26pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/4 "2021-01-29T14:26:39Z")

</div>

I believe you have a bug in your example, as `str()` will format a bytes-containing object into a nonsensical file name, e.g., `"b'/some/where'"`. That last line should read

```auto
    loadVolume(os.fspath(file))

```

Given that, I’m guessing what you’re looking for is a change to the generated wrappers that automatically calls `os.fspath` for all path-like arguments as described in PEP 519?

If so, have you made a list of the touch points within the VTK source code where this would be applied? That seems like it would be a good first step towards seeing if your idea is feasible.

Taking a cursory look at some of the code that opens files, I see a lot of generic `const char *` declarations for file name parameters, meaning that this couldn’t be automated substantially, so would entail reading through all of VTK and somehow building a table of signatures to indicate where to call `os.fspath` and where not to (which seems like a huge amount of work).

---

<div class="post-metadata">

### Author: ![fepegar](https://discourse.vtk.org/user_avatar/discourse.vtk.org/fepegar/32/2244_2.png) [@fepegar](https://discourse.vtk.org/u/fepegar)
#### Post date: [January 29, 2021, 2:59pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/5 "2021-01-29T14:59:37Z")

</div>

Hi @efahl, thanks for replying.

> [@efahl](#):
>
> I believe you have a bug in your example, as `str()` will format a bytes-containing object into a nonsensical file name

`Path.glob` returns `Path` objects, so I’m not sure what you mean. That code works fine on my computer.

To be clear, I’m a very basic VTK user. I know very little of C++ and don’t know how the wrappers work. I was just curious about whether this had ever been discussed, or whether some of the main developers thought it would be a good feature to add. I don’t think this is an essential feature or it solves and VTK problems. I asked something similar on the Slicer forum and I was suggested to extend my question to VTK and PythonQt. And here I am, because I thought it would be helpful for the three libraries to have `pathlib` support. I understand that if this would need a big effort, it’s just not worth it.

So to answer your question, I haven’t made the list of touch points. I wouldn’t know where to start! I just searched for `SetFileName` but got overwhelmed by the results. I think there’s really not much I can do to help here, unfortunately.

---

<div class="post-metadata">

### Author: ![efahl](https://discourse.vtk.org/user_avatar/discourse.vtk.org/efahl/32/1087_2.png) [@efahl](https://discourse.vtk.org/u/efahl)
#### Post date: [January 29, 2021, 4:13pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/6 "2021-01-29T16:13:26Z")

</div>

> [@fepegar](#):
>
> `Path.glob` returns `Path` objects, so I’m not sure what you mean. That code works fine on my computer.

Correct for your specific use, but generic `os.PathLike` objects can contain `str` _or_ `bytes`, depending on how you got your `path` object, so if you just do `str(path)`, it could produce an unexpected result. The point of `os.fspath()` is to avoid this issue by looking at the type of `path` and “doing the right thing”.

So, if this goes anywhere, it would be best to do it once in a way that handles not just `pathlib.Path`, but anything that implements the ` __fspath__ ` protocol (I’m thinking specifically of `os.scandir` and its `os.DirEntry` objects).

Sort of an aside…  
Back when PEP 519 was being finalized, I converted a large path handling library to support it, and found that since we dealt with VTK on the back end, I had to further transform the output of `os.fspath()` with something like this, as we were getting some wacky bytes paths for files that had names in, if I remember right, Chinese. This ensured that the C++ code only ever got UTF-8 and made everything happy.

```auto
def _fspath(path: PathLike) -> str:
    _path = os.fspath(path)
    return _path.decode('UTF-8') if isinstance(_path, bytes) else _path

```

---

<div class="post-metadata">

### Author: ![lassoan](https://discourse.vtk.org/user_avatar/discourse.vtk.org/lassoan/32/50_2.png) [@lassoan](https://discourse.vtk.org/u/lassoan)
#### Post date: [February 9, 2021, 5:09pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/7 "2021-02-09T17:09:55Z")

</div>

Pathlib support would make Python-wrapped VTK a bit more modern. Personally, I’m not fond of pathlib, because it brings in a little convenience, but also make things a little opaque and causes friction with libraries that do not support it. However, pathlib seems to have a growing user base that is increasingly demanding support for it everywhere (and I admit that if path objects were universally used in all Python libraries then it would be better than using strings). Since VTK is an actively maintained and widely used library, it will have to implement path object support at some point.

I assume that it could be implemented similarly to other wrapper hints. For example this is an existing hint:

```plaintext
  double* GetTuple4(vtkIdType tupleIdx)
    VTK_EXPECTS(0 <= tupleIdx && tupleIdx < GetNumberOfTuples())
    VTK_SIZEHINT(4); 

```

and this could be a new hint that would tell the VTK wrapper to add in some extra code to allow conversion to/from pathlike object:

```plaintext
  void SetFileName(const char* fname) VTK_EXPECTS_PATHLIKE(fname);
  const char* GetFileName() VTK_PATHLIKE();

```

> [@fepegar](#):
>
> Here are some large Python libraries getting adapted to `pathlib`:
> 
> [`nibabel`](https://github.com/nipy/nibabel/pull/610) (23/10/2019)  
> [`pandas`](https://github.com/pandas-dev/pandas/blob/325dd686de1589c17731cf93b649ed5ccb5a99b4/pandas/io/common.py#L131-L160) ([10/9/2015](https://github.com/pandas-dev/pandas/pull/11051))  
> [`numpy`](https://github.com/numpy/numpy/issues/6418) (6/10/2015)  
> [`Pillow`](https://github.com/python-pillow/Pillow/issues/1368) (3/8/2015)  
> [`matplotlib`](https://github.com/matplotlib/matplotlib/pull/6788) (18/7/2016)

@fepegar When these libraries _return_ a path, do they return it as a string or path object? If they return path object, how did they do the transition from using string (wasn’t it a breaking change)?

---

<div class="post-metadata">

### Author: ![fepegar](https://discourse.vtk.org/user_avatar/discourse.vtk.org/fepegar/32/2244_2.png) [@fepegar](https://discourse.vtk.org/u/fepegar)
#### Post date: [February 9, 2021, 5:33pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/8 "2021-02-09T17:33:36Z")

</div>

> [@lassoan](#):
>
> When these libraries _return_ a path, do they return it as a string or path object?

I can’t really think of an example of any of these libraries ever returning a path. The closest could be for example the `filename` property of a Pillow image, which returns a string. I suspect most of these libraries convert the path to string as soon it is passed to them. For example, NiBabel has a `stringify` function

> <https://github.com/nipy/nibabel/blob/7ce84f3e357dd39d280def45ce6b29c7f195e715/nibabel/filename_parser.py#L19-L46>

which they use for loading

> <https://github.com/nipy/nibabel/blob/7ce84f3e357dd39d280def45ce6b29c7f195e715/nibabel/loadsave.py#L23-L38>

and saving

> <https://github.com/nipy/nibabel/blob/7ce84f3e357dd39d280def45ce6b29c7f195e715/nibabel/loadsave.py#L81-L95>

---

<div class="post-metadata">

### Author: ![lassoan](https://discourse.vtk.org/user_avatar/discourse.vtk.org/lassoan/32/50_2.png) [@lassoan](https://discourse.vtk.org/u/lassoan)
#### Post date: [February 9, 2021, 5:38pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/9 "2021-02-09T17:38:57Z")

</div>

> [@fepegar](#):
>
> I can’t really think of an example of any of these libraries ever returning a path.

It would help if you could do some more investigation into what are the best practices for this, because VTK clearly needs to store and return paths in many cases. If a library only accept path object but then return path as string then I would consider the library only to “tolerate” path objects, not really supporting them.

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [February 9, 2021, 5:52pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/10 "2021-02-09T17:52:45Z")

</div>

Since the `SetFileName()` methods are used so much more often than the `GetFileName()`, I think it’s reasonable to take a pragmatic approach and only modify `SetFileName()`. Basically the idea is just to make VTK a little more convenient to use.

In any case, the wrappers are not going to import pathlib at the very low level of individual class wrapping. That would be an invasive change, and there’s no precedent for it. On the other hand, it’s straightforward to make `SetFileName()` look for an ` __fspath__ ` attribute, either with manual or automatic hinting.

---

<div class="post-metadata">

### Author: ![fepegar](https://discourse.vtk.org/user_avatar/discourse.vtk.org/fepegar/32/2244_2.png) [@fepegar](https://discourse.vtk.org/u/fepegar)
#### Post date: [February 9, 2021, 5:57pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/11 "2021-02-09T17:57:32Z")

</div>

> [@lassoan](#):
>
> If a library only accept path object but then return path as string then I would consider the library only to “tolerate” path objects, not really supporting them.

It seems to be the case that these libraries just _tolerate_ `pathlib` then, as all they do is covert to string as soon as they can. I’m not sure it makes sense to modify current implementations to be based on `pathlib`. But if I had to, for example, write a library to read DICOM, I think it would be very handy. But that’s a different issue.

Here are the aforementioned libraries tolerating a path-like object:

> <https://github.com/nipy/nibabel/blob/7ce84f3e357dd39d280def45ce6b29c7f195e715/nibabel/loadsave.py#L38>

> <https://github.com/pandas-dev/pandas/blob/413eba4a480b9ffa28da2aa8a258e9bc0f5a9b1d/pandas/io/html.py#L1079>

> <https://github.com/numpy/numpy/blob/b4491833d636344ef295f1609bcf4742c1d94d10/numpy/core/src/multiarray/multiarraymodule.c#L2145>

> <https://github.com/matplotlib/matplotlib/blob/6290958bd39c196a351893a69f5c1da9f0d4fa92/lib/matplotlib/image.py#L1550>

> <https://github.com/python-pillow/Pillow/blob/cc4ed21f191760fbf36417d79eca3ed3555245ea/src/PIL/Image.py#L2127>

> [@dgobbi](#):
>
> Since the `SetFileName()` methods are used so much more often than the `GetFileName()`, I think it’s reasonable to take a pragmatic approach and only modify `SetFileName()`. Basically the idea is just to make VTK a little more convenient to use.

I agree, I think modifying `SetFileName` would be the change we are after.

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [February 9, 2021, 6:03pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/12 "2021-02-09T18:03:16Z")

</div>

> [@fepegar](#):
>
> I agree, I think modifying `SetFileName` would be the change we are after.

What about `vtkStringArray`, which is often used to store a list of filenames? Have you (or other users you are aware of) run into situations where you tried putting a Path object into a `vtkStringArray`?

---

<div class="post-metadata">

### Author: ![fepegar](https://discourse.vtk.org/user_avatar/discourse.vtk.org/fepegar/32/2244_2.png) [@fepegar](https://discourse.vtk.org/u/fepegar)
#### Post date: [February 9, 2021, 6:09pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/13 "2021-02-09T18:09:00Z")

</div>

> [@dgobbi](#):
>
> What about `vtkStringArray`, which is often used to store a list of filenames? Have you (or other users you are aware of) run into situations where you tried putting a Path object into a `vtkStringArray`?

No. But I think in that case it would make sense that only strings are accepted as input, as it’s not a `vtkPathArray`…

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [February 9, 2021, 6:31pm UTC](https://discourse.vtk.org/t/support-for-pathlib/5085/14 "2021-02-09T18:31:08Z")

</div>

I’ve submitted [#18120](https://gitlab.kitware.com/vtk/vtk/-/issues/18120) to get this on the tracker. No timeline, though.
