v icon indicating copy to clipboard operation
v copied to clipboard

WIP: pathlib: add a pathlib module

Open yochem opened this issue 1 year ago • 9 comments

I noticed people have been requesting a module inspired on Python's pathlib and that you mentioned it in #14504. This is my attempt at it. Of course, I've not written a lot of V code, so feedback is very welcome.

To Do:

  • [ ] Complete all methods (see below)
  • [ ] Write tests
  • [ ] Comments and documentation
  • [ ] Implementation details, should we go for a V approach or not, etc.
  • [ ] Windows support
  • [x] Include pathlib errors

Methods

Module functions status:

Python V Code Comments Tests Notes
cwd() cwd() os.getwd()
home() home() os.home_dir()
:x: path() Path{} constructor from string
:x: path_from_parts() Path{} constructor from []string (currently private)

Path attributes status:

Python Renamed/Replaced by Code Comments Tests Notes
anchor Windows
drive Windows
name os.file_name()
parent parent() As method due to V's structs not being recursive
parents parents() As method due to V's structs not being recursive
parts
root
stem
suffix
suffixes

Path methods status:

Python Renamed/replaced by Code Comments Tests Notes
absolute() os.abs_path()
as_posix()
as_uri() Python errors when not full path, V just converts it first
chmod() os.chmod()
exists() os.exists()
expanduser() V only supports ~, Python supports ~username
glob() os.glob()
group()
hardlink_to() link_to() os.link()
is_absolute() os.is_abs_path()
is_block_device()
is_char_device()
is_dir() os.is_dir()
is_fifo()
is_file() os.is_file()
is_mount()
is_regular()
is_relative_to()
is_reserved()
is_socket()
is_symlink() is_link() os.is_link()
iterdir() os.ls()
joinpath() join() os.join_path_single()
lchmod()
link_to() link() os.link()
lstat()
match()
mkdir() os.mkdir(), but maybe use/include mkdir_all()?
open() os.open_file()
owner()
quoted() os.quoted_path()
read_bytes()
read_text()
readlink()
relative_to()
rename()
replace()
resolve() os.real_path()
rglob()
rmdir() os.rmdir()
samefile()
stat() inode() os.inode()
symlink_to()
touch() os.create()
unlink() os.rm()
with_name()
with_stem()
with_suffix()
write_bytes()
write_text() os.write_text()
__str__() str()
__div__() / Do we want operator overload?

Questions

  • The name: pathlib or just path?

  • This module reuses a lot of functions from the os module. For example, pathlib.touch() just calls os.create(). Should we keep the Python names or use the function names from os to be consistent? (I feel like the Python names are very UNIX-based, which I like but other people may not.)

  • A nice thing about pathlib that is commonly used is the overloaded /. This makes it possible to add paths together like this: path/filename, if both path and filename are of type Path. Do we want this?

  • Should the parts field of Path and the constructor path_from_parts be public?

  • Rename iterdir -> listdir or ls because it's not an iterator?

  • Implement next() method to be able to use for file in path(dir)? (python does not)

  • as_uri(): Python errors on relative files, we just call absolute() first?

  • expanduser(): Python supports ~user, v's os.expand_tilde_to_home() does not

  • Maybe merge rmdir and unlink to rm (which removes the file / directory)?

  • Python has multiple Path classes: PurePath for Paths without I/O and Windows*, Posix* Paths for either system. Should we do this too, or just keep it at Path for now?

yochem avatar Dec 27 '22 17:12 yochem

While V could use some of the pathlib stuff from Python, many of these routines are already in V, just not in a pathlib module.

Things like os.getwd() to get the current dir, os.chdir() to change dir, etc.

JalonSolov avatar Dec 27 '22 18:12 JalonSolov

While V could use some of the pathlib stuff from Python, many of these routines are already in V, just not in a pathlib module.

Things like os.getwd() to get the current dir, os.chdir() to change dir, etc.

True, as is the case with Python. This module wraps those functions from the os module, to be used on the Path 'object'.

EDIT: As example:

path := 'v/vlib/pathlib/pathlib.v'
target := 'v/pathlib.v'
os.link(path, target)

To:

path := path('v/vlib/pathlib/pathlib.v')
target := path('v/pathlib.v')
path.link(target)

yochem avatar Dec 27 '22 19:12 yochem

This kind of systematic and complete consideration towards a full treatment and coverage of such a topic is nice to see.

ylluminate avatar Dec 28 '22 05:12 ylluminate

Heads up: The CI will fail you if your public functions don't have proper doc comments.

https://github.com/vlang/v/blob/master/doc/docs.md#writing-documentation

JalonSolov avatar Jan 05 '23 14:01 JalonSolov

It will have to be the 2nd, as a doc comment must start with the function name.

JalonSolov avatar Jan 05 '23 15:01 JalonSolov

Thanks! I will indeed use that format.

yochem avatar Jan 05 '23 15:01 yochem

I have the following code for the inode method:

pub fn (p Path) inode() os.FileMode {
    return os.inode(p.str())
}

But v complains that I can't use os.FileMode as return value, because it is private in the os module. How would one get around this problem?

vlib/pathlib/pathlib.v:187:25: error: struct `os.FileMode` was declared as private to module `os`, so it can not be used inside module `pathlib`
  185 | // }
  186 |
  187 | pub fn (p Path) inode() os.FileMode {
      |                         ~~~~~~~~~~~
  188 |     return os.inode(p.str())
  189 | }

yochem avatar Jan 09 '23 12:01 yochem

I have the following code for the inode method:

pub fn (p Path) inode() os.FileMode {
    return os.inode(p.str())
}

But v complains that I can't use os.FileMode as return value, because it is private in the os module. How would one get around this problem?

vlib/pathlib/pathlib.v:187:25: error: struct `os.FileMode` was declared as private to module `os`, so it can not be used inside module `pathlib`
  185 | // }
  186 |
  187 | pub fn (p Path) inode() os.FileMode {
      |                         ~~~~~~~~~~~
  188 |     return os.inode(p.str())
  189 | }

Make it public by adding a pub prefix to the struct declaration.

Delta456 avatar Jan 09 '23 12:01 Delta456

Make it public by adding a pub prefix to the struct declaration.

Inside the os module right? I thought there would be a good reason for them to keep it private. I can open an issue for it though.

yochem avatar Jan 09 '23 12:01 yochem