Python pathlib.Path - how do I get just a platform independent file separator as a string?
Asked Answered
D

3

8

I am creating a format string that is different based on class, that is used to generate a filename by a generic class method. I'm using the Python 3.4+ pathlib.Path module for object-oriented file I/O.

In building this string, the path separator is missing, and rather than just put the windows version in, I want to add a platform independent file separator.

I searched the pathlib docs, and answers here about this, but all the examples assume I'm building a Path object, not a string. The pathlib functions will add the correct separator in any string outputs, but those are actual paths - so it won't work.

Besides something hacky like writing a string and parsing it to figure out what the separator is, is there a way to directly get the current, correct file separator string?

Prefer an answer using pathlib.Path, rather than os or shutil packages.

Here's what the code looks like:

In the constructor:

    self.outputdir = Path('drive:\\dir\\file')
    self.indiv_fileformatstr = str(self.outputdir) + '{}_new.m'

In the final method used:

    indiv_filename = Path(self.indiv_fileformatstr.format(topic))

This leaves out the file separator

Dyke answered 26/9, 2019 at 21:14 Comment(0)
H
12

There is nothing public in the pathlib module providing the character used by the operating system to separate pathname components. If you really need it, import os and use os.sep.

But you likely don't need it in the first place - it's missing the point of pathlib if you convert to strings in order to join a filename. In typical usage, the separator string itself isn't used for concatenating path components because pathlib overrides division operators (__truediv__ and __rtruediv__) for this purpose. Similarly, it's not needed for splitting due to methods such as Path.parts.

Instead of:

self.indiv_fileformatstr = str(self.outputdir) + '{}_new.m'

You would usually do something like:

self.indiv_fileformatpath = self.outputdir / '{}_new.m'
self.indiv_fileformatstr = str(self.indiv_fileformatpath)
Hildehildebrand answered 26/9, 2019 at 21:31 Comment(4)
Oh, wait - so pathlib will just store the {} and that can be spit out by reading the file string back? Not sure why I was thinking something funky would happen. That's perfect - thanks! The reason this is needed is I have multiple child classes that have different prefix and postfix requirements (i.e. they are not all {}_new.m).Dyke
Slightly optimized: self.indiv_fileformatstr = str(self.outputdir / '{}_new.m'), and if you need to apply other variables, can use: self.indiv_fileformatstr = str(self.outputdir / '{pre}{{}}{post}.{ext}').format(pre=prefix, post=postfix, ext=extension), which will leave a bare {} for the bare filename when formatted in the future.Dyke
This does not answer the question.Threeply
@MaxRied Edited to answer the literal question first and foremost. Better?Hildehildebrand
K
4

The platform-independent separator is in pathlib.os.sep

Korenblat answered 16/2, 2020 at 9:21 Comment(4)
This is just a side-effect of the fact that pathlib.py happens to import os at the top.Hildehildebrand
Certainly, but thanks to it you have access to the path separator without explicitly loading os.Korenblat
I would not rely on that being available. Since it's not documented, it may just be implementation detail or may be removed in later version, which could be breaking your code for no good reason.Hildehildebrand
What is your answer? You provided a comment.Cimmerian
D
0

Solution using wim's answer

Based on wim's answer, the following works great:

  1. Save the format string in the Path object
  2. When needing to substitute into the templated filename in the future, just use str(path_object) to get the string back out.
import pathlib

# Start with following, with self.outputdir as pathlib.Path object
outputdir = 'c:\\myfolder'
file_template_path = outputdir / '{}_new.m'

# Then to make the final file object later (i.e. in a child class, etc.)
base_filename_string = 'myfile'
new_file = pathlib.Path(str(file_template).format(base_filename_string))

This creates:

pathlib.Path("c:\\myfolder\myfile_new.m")

Creating the template with prefix/postfix/etc.

If you need to apply other variables, you can use 2 levels of formatting to apply specialized prefixes/postfixes, etc., then store the final template in a Path object, as shown above.

When creating 2 levels of formatting, use double brackets where the first level formatter should just create a single bracket and not try to interpret a tag. i.e. {{basename}} becomes just {basename} without any variable substitution.

prefix = 'new_'
postfix = '_1'
ext = 'txt'
file_template_path = outputdir / f'{prefix}{{}}{postfix}.{ext}'

which becomes a path object with the following string:

$ file_template_path
pathlib.Path("c:\\myfolder\new_{}_1.txt")
Dyke answered 13/4, 2022 at 22:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.