8000 Stdlib tempfile by sbinet · Pull Request #189 · go-python/gpython · GitHub
[go: up one dir, main page]

Skip to content

Stdlib tempfile #189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 25, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
stdlib/os: add mkdir, makedirs, remove, removedirs and rmdir
Signed-off-by: Sebastien Binet <binet@cern.ch>
  • Loading branch information
sbinet committed May 25, 2022
commit 795df15d5e0e3cf40c46fa3a57b6820a0deb7a8a
216 changes: 214 additions & 2 deletions stdlib/os/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,20 @@ func init() {
initGlobals()

methods := []*py.Method{
py.MustNewMethod("_exit", _exit, 0, "Immediate program termination."),
py.MustNewMethod("getcwd", getCwd, 0, "Get the current working directory"),
py.MustNewMethod("getcwdb", getCwdb, 0, "Get the current working directory in a byte slice"),
py.MustNewMethod("chdir", chdir, 0, "Change the current working directory"),
py.MustNewMethod("getenv", getenv, 0, "Return the value of the environment variable key if it exists, or default if it doesn’t. key, default and the result are str."),
py.MustNewMethod("getpid", getpid, 0, "Return the current process id."),
py.MustNewMethod("makedirs", makedirs, 0, makedirs_doc),
py.MustNewMethod("mkdir", mkdir, 0, mkdir_doc),
py.MustNewMethod("putenv", putenv, 0, "Set the environment variable named key to the string value."),
py.MustNewMethod("remove", remove, 0, remove_doc),
py.MustNewMethod("removedirs", removedirs, 0, removedirs_doc),
py.MustNewMethod("rmdir", rmdir, 0, rmdir_doc),
py.MustNewMethod("system", system, 0, "Run shell commands, prints stdout directly to default"),
py.MustNewMethod("unsetenv", unsetenv, 0, "Unset (delete) the environment variable named key."),
py.MustNewMethod("_exit", _exit, 0, "Immediate program termination."),
py.MustNewMethod("system", system, 0, "Run shell commands, prints stdout directly to deault"),
}
globals := py.StringDict{
"error": py.OSError,
Expand Down Expand Up @@ -150,6 +155,105 @@ func getpid(self py.Object, args py.Tuple) (py.Object, error) {
return py.Int(os.Getpid()), nil
}

const makedirs_doc = `makedirs(name [, mode=0o777][, exist_ok=False])

Super-mkdir; create a leaf directory and all intermediate ones. Works like
mkdir, except that any intermediate path segment (not just the rightmost)
will be created if it does not exist. If the target directory already
exists, raise an OSError if exist_ok is False. Otherwise no exception is
raised. This is recursive.`

func makedirs(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Object, error) {
var (
pypath py.Object
pymode py.Object = py.Int(0o777)
pyok py.Object = py.False
)
err := py.ParseTupleAndKeywords(
args, kwargs,
"s#|ip:makedirs", []string{"path", "mode", "exist_ok"},
&pypath, &pymode, &pyok,
)
if err != nil {
return nil, err
}

var (
path = ""
mode = os.FileMode(pymode.(py.Int))
)
switch v := pypath.(type) {
case py.String:
path = string(v)
case py.Bytes:
path = string(v)
}

if pyok.(py.Bool) == py.False {
// check if leaf exists.
_, err := os.Stat(path)
// FIXME(sbinet): handle other errors.
if err == nil {
return nil, py.ExceptionNewf(py.FileExistsError, "File exists: '%s'", path)
}
}

err = os.MkdirAll(path, mode)
if err != nil {
return nil, err
}

10000 return py.None, nil
}

const mkdir_doc = `Create a directory.

If dir_fd is not None, it should be a file descriptor open to a directory,
and path should be relative; path will then be relative to that directory.
dir_fd may not be implemented on your platform.
If it is unavailable, using it will raise a NotImplementedError.

The mode argument is ignored on Windows.`

func mkdir(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Object, error) {
var (
pypath py.Object
pymode py.Object = py.Int(511)
pydirfd py.Object = py.None
)
err := py.ParseTupleAndKeywords(
args, kwargs,
"s#|ii:mkdir", []string{"path", "mode", "dir_fd"},
&pypath, &pymode, &pydirfd,
)
if err != nil {
return nil, err
}

var (
path = ""
mode = os.FileMode(pymode.(py.Int))
)
switch v := pypath.(type) {
case py.String:
path = string(v)
case py.Bytes:
path = string(v)
}

if pydirfd != py.None {
// FIXME(sbinet)
return nil, py.ExceptionNewf(py.NotImplementedError, "mkdir(dir_fd=XXX) not implemented")
}

err = os.Mkdir(path, mode)
if err != nil {
return nil, err
}

return py.None, nil
}

// putenv sets the value of an environment variable named by the key.
func putenv(self py.Object, args py.Tuple) (py.Object, error) {
if len(args) != 2 {
Expand Down Expand Up @@ -199,6 +303,114 @@ func _exit(self py.Object, args py.Tuple) (py.Object, error) { // can never retu
return nil, nil
}

const remove_doc = `Remove a file (same as unlink()).

If dir_fd is not None, it should be a file descriptor open to a directory,
and path should be relative; path will then be relative to that directory.
dir_fd may not be implemented on your platform.
If it is unavailable, using it will raise a NotImplementedError.`

func remove(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Object, error) {
var (
pypath py.Object
pydir py.Object = py.None
)
err := py.ParseTupleAndKeywords(args, kwargs, "s#|i:remove", []string{"path", "dir_fd"}, &pypath, &pydir)
if err != nil {
return nil, err
}

if pydir != py.None {
// FIXME(sbinet) ?
return nil, py.ExceptionNewf(py.NotImplementedError, "remove(dir_fd=XXX) not implemented")
}

var name string
switch v := pypath.(type) {
case py.String:
name = string(v)
case py.Bytes:
name = string(v)
}

err = os.Remove(name)
if err != nil {
return nil, err
}

return py.None, nil
}

const removedirs_doc = `removedirs(name)

Super-rmdir; remove a leaf directory and all empty intermediate
ones. Works like rmdir except that, if the leaf directory is
successfully removed, directories corresponding to rightmost path
segments will be pruned away until either the whole path is
consumed or an error occurs. Errors during this latter phase are
ignored -- they generally mean that a directory was not empty.`

func removedirs(self py.Object, args py.Tuple) (py.Object, error) {
var pypath py.Object
err := py.ParseTuple(args, "s#:rmdir", &pypath)
if err != nil {
return nil, err
}

var name string
switch v := pypath.(type) {
case py.String:
name = string(v)
case py.Bytes:
name = string(v)
}

err = os.RemoveAll(name)
if err != nil {
return nil, err
}

return py.None, nil
}

const rmdir_doc = `Remove a directory.

If dir_fd is not None, it should be a file descriptor open to a directory,
and path should be relative; path will then be relative to that directory.
dir_fd may not be implemented on your platform.
If it is unavailable, using it will raise a NotImplementedError.`

func rmdir(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Object, error) {
var (
pypath py.Object
pydir py.Object = py.None
)
err := py.ParseTupleAndKeywords(args, kwargs, "s#|i:rmdir", []string{"path", "dir_fd"}, &pypath, &pydir)
if err != nil {
return nil, err
}

if pydir != py.None {
// FIXME(sbinet) ?
return nil, py.ExceptionNewf(py.NotImplementedError, "rmdir(dir_fd=XXX) not implemented")
}

var name string
switch v := pypath.(type) {
case py.String:
name = string(v)
case py.Bytes:
name = string(v)
}

err = os.Remove(name)
if err != nil {
return nil, err
}

return py.None, nil
}

// os.system(command string) this function runs a shell command and directs the output to standard output.
func system(self py.Object, args py.Tuple) (py.Object, error) {
if len(args) != 1 {
Expand Down
8000
49 changes: 49 additions & 0 deletions stdlib/os/testdata/test.py
67ED
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,53 @@
else:
print("os."+k+": [OK]")

## mkdir,rmdir,remove,removedirs
import tempfile
try:
top = tempfile.mkdtemp(prefix="gpython-os-test-")
dir1 = top + os.sep + "dir1"
dir2 = top + os.sep + "dir2"
dir11 = top + os.sep + "dir1" + os.sep + "dir11"
fname = dir2 + os.sep + "foo.txt"
os.mkdir(dir1)
os.rmdir(dir1)
os.mkdir(dir1)
os.mkdir(dir2)
os.mkdir(dir11)
os.removedirs(dir1)
try:
os.mkdir(dir11)
print("creating nested dirs with os.mkdir should have failed")
except SystemError as e:
print("caught: SystemError - no such file or directory [OK]")
except Exception as e:
print("caught: %s" % e)

os.makedirs(dir11)
try:
os.makedirs(dir11)
print("creating already existing dirs should have failed")
except FileExistsError as e:
print("caught: FileExistsError [OK]")
except Exception as e:
print("INVALID error caught: %s" % e)
os.makedirs(dir11, exist_ok=True)

with open(fname, "w+") as f:
pass
try:
os.rmdir(dir2)
print("removing a non-empty directory should have failed")
except SystemError as e:
print("caught: SystemError - directory not empty [OK]")
except Exception as e:
print("INVALID error caught: %s" % e)
os.remove(fname)
os.rmdir(dir2)
except Exception as e:
print("could not create/remove directories: %s" % e)
finally:
os.removedirs(top)
print("os.{mkdir,rmdir,remove,removedirs} worked as expected")

print("OK")
4 changes: 4 additions & 0 deletions stdlib/os/testdata/test_golden.txt
Original file line number Diff line number Diff line change
50F3 Expand Up @@ -24,4 +24,8 @@ os.pathsep: [OK]
os.linesep: [OK]
os.devnull: [OK]
os.altsep: [OK]
caught: SystemError - no such file or directory [OK]
caught: FileExistsError [OK]
caught: SystemError - directory not empty [OK]
os.{mkdir,rmdir,remove,removedirs} worked as expected
OK
0