v
v copied to clipboard
WIP: pathlib: add a pathlib module
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 justpath
? -
This module reuses a lot of functions from the
os
module. For example,pathlib.touch()
just callsos.create()
. Should we keep the Python names or use the function names fromos
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 constructorpath_from_parts
be public? -
Rename
iterdir
->listdir
orls
because it's not an iterator? -
Implement
next()
method to be able to usefor file in path(dir)
? (python does not) -
as_uri()
: Python errors on relative files, we just callabsolute()
first? -
expanduser()
: Python supports ~user, v's os.expand_tilde_to_home() does not -
Maybe merge
rmdir
andunlink
torm
(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?
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.
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)
This kind of systematic and complete consideration towards a full treatment and coverage of such a topic is nice to see.
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
It will have to be the 2nd, as a doc comment must start with the function name.
Thanks! I will indeed use that format.
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 | }
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 useos.FileMode
as return value, because it is private in theos
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.
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.