Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pyfs
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
pyfs
Commits
60da3d53
Commit
60da3d53
authored
Jan 11, 2012
by
willmcgugan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixed copydir/movedir, added DeleteRootError
parent
db293aab
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
231 additions
and
55 deletions
+231
-55
ChangeLog
+1
-0
fs/__init__.py
+0
-3
fs/base.py
+11
-6
fs/errors.py
+5
-0
fs/ftpfs.py
+3
-0
fs/memoryfs.py
+6
-0
fs/mountfs.py
+2
-0
fs/multifs.py
+2
-0
fs/osfs/__init__.py
+3
-2
fs/osfs/watch.py
+2
-0
fs/osfs/xattrs.py
+7
-1
fs/s3fs.py
+2
-0
fs/sftpfs.py
+2
-2
fs/tests/__init__.py
+2
-0
fs/tests/test_expose.py
+1
-0
fs/tests/test_utils.py
+107
-0
fs/utils.py
+44
-22
fs/wrapfs/__init__.py
+3
-2
fs/wrapfs/lazyfs.py
+1
-1
fs/wrapfs/subfs.py
+27
-16
No files found.
ChangeLog
View file @
60da3d53
...
@@ -83,3 +83,4 @@
...
@@ -83,3 +83,4 @@
0.5:
0.5:
* Ported to Python 3.X
* Ported to Python 3.X
* Added a DeleteRootError to exceptions thrown when trying to delete '/'
fs/__init__.py
View file @
60da3d53
...
@@ -18,9 +18,6 @@ implementations of this interface such as:
...
@@ -18,9 +18,6 @@ implementations of this interface such as:
__version__
=
"0.4.1"
__version__
=
"0.4.1"
__author__
=
"Will McGugan (will@willmcgugan.com)"
__author__
=
"Will McGugan (will@willmcgugan.com)"
# No longer necessary - WM
#from base import *
# provide these by default so people can use 'fs.path.basename' etc.
# provide these by default so people can use 'fs.path.basename' etc.
import
errors
import
errors
import
path
import
path
...
...
fs/base.py
View file @
60da3d53
...
@@ -58,9 +58,9 @@ class DummyLock(object):
...
@@ -58,9 +58,9 @@ class DummyLock(object):
pass
pass
def
__enter__
(
self
):
def
__enter__
(
self
):
pass
return
self
def
__exit__
(
self
,
*
args
):
def
__exit__
(
self
,
exc_type
,
exc_value
,
traceback
):
pass
pass
...
@@ -154,7 +154,7 @@ class FS(object):
...
@@ -154,7 +154,7 @@ class FS(object):
_meta
=
{}
_meta
=
{}
def
__init__
(
self
,
thread_synchronize
=
Fals
e
):
def
__init__
(
self
,
thread_synchronize
=
Tru
e
):
"""The base class for Filesystem objects.
"""The base class for Filesystem objects.
:param thread_synconize: If True, a lock object will be created for the object, otherwise a dummy lock will be used.
:param thread_synconize: If True, a lock object will be created for the object, otherwise a dummy lock will be used.
...
@@ -657,6 +657,7 @@ class FS(object):
...
@@ -657,6 +657,7 @@ class FS(object):
"""
"""
with
self
.
_lock
:
sys_path
=
self
.
getsyspath
(
path
,
allow_none
=
True
)
sys_path
=
self
.
getsyspath
(
path
,
allow_none
=
True
)
if
sys_path
is
not
None
:
if
sys_path
is
not
None
:
now
=
datetime
.
datetime
.
now
()
now
=
datetime
.
datetime
.
now
()
...
@@ -1068,7 +1069,7 @@ class FS(object):
...
@@ -1068,7 +1069,7 @@ class FS(object):
:type chunk_size: bool
:type chunk_size: bool
"""
"""
with
self
.
_lock
:
if
not
self
.
isfile
(
src
):
if
not
self
.
isfile
(
src
):
if
self
.
isdir
(
src
):
if
self
.
isdir
(
src
):
raise
ResourceInvalidError
(
src
,
msg
=
"Source is not a file:
%(path)
s"
)
raise
ResourceInvalidError
(
src
,
msg
=
"Source is not a file:
%(path)
s"
)
...
@@ -1129,6 +1130,7 @@ class FS(object):
...
@@ -1129,6 +1130,7 @@ class FS(object):
"""
"""
with
self
.
_lock
:
src_syspath
=
self
.
getsyspath
(
src
,
allow_none
=
True
)
src_syspath
=
self
.
getsyspath
(
src
,
allow_none
=
True
)
dst_syspath
=
self
.
getsyspath
(
dst
,
allow_none
=
True
)
dst_syspath
=
self
.
getsyspath
(
dst
,
allow_none
=
True
)
...
@@ -1169,6 +1171,7 @@ class FS(object):
...
@@ -1169,6 +1171,7 @@ class FS(object):
:raise `fs.errors.DestinationExistsError`: if destination exists and `overwrite` is False
:raise `fs.errors.DestinationExistsError`: if destination exists and `overwrite` is False
"""
"""
with
self
.
_lock
:
if
not
self
.
isdir
(
src
):
if
not
self
.
isdir
(
src
):
if
self
.
isfile
(
src
):
if
self
.
isfile
(
src
):
raise
ResourceInvalidError
(
src
,
msg
=
"Source is not a directory:
%(path)
s"
)
raise
ResourceInvalidError
(
src
,
msg
=
"Source is not a directory:
%(path)
s"
)
...
@@ -1232,6 +1235,7 @@ class FS(object):
...
@@ -1232,6 +1235,7 @@ class FS(object):
is required (defaults to 16K)
is required (defaults to 16K)
"""
"""
with
self
.
_lock
:
if
not
self
.
isdir
(
src
):
if
not
self
.
isdir
(
src
):
raise
ResourceInvalidError
(
src
,
msg
=
"Source is not a directory:
%(path)
s"
)
raise
ResourceInvalidError
(
src
,
msg
=
"Source is not a directory:
%(path)
s"
)
def
copyfile_noerrors
(
src
,
dst
,
**
kwargs
):
def
copyfile_noerrors
(
src
,
dst
,
**
kwargs
):
...
@@ -1251,7 +1255,7 @@ class FS(object):
...
@@ -1251,7 +1255,7 @@ class FS(object):
raise
DestinationExistsError
(
dst
)
raise
DestinationExistsError
(
dst
)
if
dst
:
if
dst
:
self
.
makedir
(
dst
,
allow_recreate
=
overwrit
e
)
self
.
makedir
(
dst
,
allow_recreate
=
Tru
e
)
for
dirname
,
filenames
in
self
.
walk
(
src
):
for
dirname
,
filenames
in
self
.
walk
(
src
):
...
@@ -1273,6 +1277,7 @@ class FS(object):
...
@@ -1273,6 +1277,7 @@ class FS(object):
:rtype: bool
:rtype: bool
"""
"""
with
self
.
_lock
:
path
=
normpath
(
path
)
path
=
normpath
(
path
)
iter_dir
=
iter
(
self
.
listdir
(
path
))
iter_dir
=
iter
(
self
.
listdir
(
path
))
try
:
try
:
...
@@ -1292,7 +1297,7 @@ class FS(object):
...
@@ -1292,7 +1297,7 @@ class FS(object):
:rtype: an FS object
:rtype: an FS object
"""
"""
with
self
.
_lock
:
self
.
makedir
(
path
,
allow_recreate
=
True
,
recursive
=
recursive
)
self
.
makedir
(
path
,
allow_recreate
=
True
,
recursive
=
recursive
)
dir_fs
=
self
.
opendir
(
path
)
dir_fs
=
self
.
opendir
(
path
)
return
dir_fs
return
dir_fs
...
...
fs/errors.py
View file @
60da3d53
...
@@ -18,6 +18,7 @@ __all__ = ['FSError',
...
@@ -18,6 +18,7 @@ __all__ = ['FSError',
'PermissionDeniedError'
,
'PermissionDeniedError'
,
'FSClosedError'
,
'FSClosedError'
,
'OperationTimeoutError'
,
'OperationTimeoutError'
,
'DeleteRootError'
,
'ResourceError'
,
'ResourceError'
,
'NoSysPathError'
,
'NoSysPathError'
,
'NoMetaError'
,
'NoMetaError'
,
...
@@ -119,6 +120,10 @@ class OperationTimeoutError(OperationFailedError):
...
@@ -119,6 +120,10 @@ class OperationTimeoutError(OperationFailedError):
default_message
=
"Unable to
%(opname)
s: operation timed out"
default_message
=
"Unable to
%(opname)
s: operation timed out"
class
DeleteRootError
(
OperationFailedError
):
default_message
=
"Can't delete root dir"
class
ResourceError
(
FSError
):
class
ResourceError
(
FSError
):
"""Base exception class for error associated with a specific resource."""
"""Base exception class for error associated with a specific resource."""
default_message
=
"Unspecified resource error:
%(path)
s"
default_message
=
"Unspecified resource error:
%(path)
s"
...
...
fs/ftpfs.py
View file @
60da3d53
...
@@ -1299,6 +1299,8 @@ class FTPFS(FS):
...
@@ -1299,6 +1299,8 @@ class FTPFS(FS):
raise
ResourceNotFoundError
(
path
)
raise
ResourceNotFoundError
(
path
)
if
self
.
isfile
(
path
):
if
self
.
isfile
(
path
):
raise
ResourceInvalidError
(
path
)
raise
ResourceInvalidError
(
path
)
if
normpath
(
path
)
in
(
''
,
'/'
):
raise
DeleteRootError
(
path
)
if
not
force
:
if
not
force
:
for
_checkpath
in
self
.
listdir
(
path
):
for
_checkpath
in
self
.
listdir
(
path
):
...
@@ -1319,6 +1321,7 @@ class FTPFS(FS):
...
@@ -1319,6 +1321,7 @@ class FTPFS(FS):
pass
pass
if
recursive
:
if
recursive
:
try
:
try
:
if
dirname
(
path
)
not
in
(
''
,
'/'
):
self
.
removedir
(
dirname
(
path
),
recursive
=
True
)
self
.
removedir
(
dirname
(
path
),
recursive
=
True
)
except
DirectoryNotEmptyError
:
except
DirectoryNotEmptyError
:
pass
pass
...
...
fs/memoryfs.py
View file @
60da3d53
...
@@ -451,6 +451,8 @@ class MemoryFS(FS):
...
@@ -451,6 +451,8 @@ class MemoryFS(FS):
@synchronize
@synchronize
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
path
=
normpath
(
path
)
path
=
normpath
(
path
)
if
path
in
(
''
,
'/'
):
raise
DeleteRootError
(
path
)
dir_entry
=
self
.
_get_dir_entry
(
path
)
dir_entry
=
self
.
_get_dir_entry
(
path
)
if
dir_entry
is
None
:
if
dir_entry
is
None
:
...
@@ -466,10 +468,14 @@ class MemoryFS(FS):
...
@@ -466,10 +468,14 @@ class MemoryFS(FS):
while
rpathname
:
while
rpathname
:
rpathname
,
dirname
=
pathsplit
(
rpathname
)
rpathname
,
dirname
=
pathsplit
(
rpathname
)
parent_dir
=
self
.
_get_dir_entry
(
rpathname
)
parent_dir
=
self
.
_get_dir_entry
(
rpathname
)
if
not
dirname
:
raise
DeleteRootError
(
path
)
del
parent_dir
.
contents
[
dirname
]
del
parent_dir
.
contents
[
dirname
]
else
:
else
:
pathname
,
dirname
=
pathsplit
(
path
)
pathname
,
dirname
=
pathsplit
(
path
)
parent_dir
=
self
.
_get_dir_entry
(
pathname
)
parent_dir
=
self
.
_get_dir_entry
(
pathname
)
if
not
dirname
:
raise
DeleteRootError
(
path
)
del
parent_dir
.
contents
[
dirname
]
del
parent_dir
.
contents
[
dirname
]
@synchronize
@synchronize
...
...
fs/mountfs.py
View file @
60da3d53
...
@@ -331,6 +331,8 @@ class MountFS(FS):
...
@@ -331,6 +331,8 @@ class MountFS(FS):
@synchronize
@synchronize
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
path
=
normpath
(
path
)
path
=
normpath
(
path
)
if
path
in
(
''
,
'/'
):
raise
DeleteRootError
(
path
)
fs
,
_mount_path
,
delegate_path
=
self
.
_delegate
(
path
)
fs
,
_mount_path
,
delegate_path
=
self
.
_delegate
(
path
)
if
fs
is
self
or
fs
is
None
:
if
fs
is
self
or
fs
is
None
:
raise
ResourceInvalidError
(
path
,
msg
=
"Can not removedir for an un-mounted path"
)
raise
ResourceInvalidError
(
path
,
msg
=
"Can not removedir for an un-mounted path"
)
...
...
fs/multifs.py
View file @
60da3d53
...
@@ -293,6 +293,8 @@ class MultiFS(FS):
...
@@ -293,6 +293,8 @@ class MultiFS(FS):
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
if
self
.
writefs
is
None
:
if
self
.
writefs
is
None
:
raise
OperationFailedError
(
'removedir'
,
path
=
path
,
msg
=
"No writeable FS set"
)
raise
OperationFailedError
(
'removedir'
,
path
=
path
,
msg
=
"No writeable FS set"
)
if
normpath
(
path
)
in
(
''
,
'/'
):
raise
DeleteRootError
(
path
)
self
.
writefs
.
removedir
(
path
,
recursive
=
recursive
,
force
=
force
)
self
.
writefs
.
removedir
(
path
,
recursive
=
recursive
,
force
=
force
)
@synchronize
@synchronize
...
...
fs/osfs/__init__.py
View file @
60da3d53
...
@@ -286,13 +286,14 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
...
@@ -286,13 +286,14 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
except
ResourceNotFoundError
:
except
ResourceNotFoundError
:
pass
pass
# Don't remove the root directory of this FS
# Don't remove the root directory of this FS
if
path
in
(
""
,
"/"
):
if
path
in
(
''
,
'/'
):
r
eturn
r
aise
DeleteRootError
(
path
)
os
.
rmdir
(
sys_path
)
os
.
rmdir
(
sys_path
)
# Using os.removedirs() for this can result in dirs being
# Using os.removedirs() for this can result in dirs being
# removed outside the root of this FS, so we recurse manually.
# removed outside the root of this FS, so we recurse manually.
if
recursive
:
if
recursive
:
try
:
try
:
if
dirname
(
path
)
not
in
(
''
,
'/'
):
self
.
removedir
(
dirname
(
path
),
recursive
=
True
)
self
.
removedir
(
dirname
(
path
),
recursive
=
True
)
except
DirectoryNotEmptyError
:
except
DirectoryNotEmptyError
:
pass
pass
...
...
fs/osfs/watch.py
View file @
60da3d53
...
@@ -34,6 +34,8 @@ if OSFSWatchMixin is None:
...
@@ -34,6 +34,8 @@ if OSFSWatchMixin is None:
# Fall back to raising UnsupportedError
# Fall back to raising UnsupportedError
if
OSFSWatchMixin
is
None
:
if
OSFSWatchMixin
is
None
:
class
OSFSWatchMixin
(
object
):
class
OSFSWatchMixin
(
object
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
OSFSWatchMixin
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
add_watcher
(
self
,
*
args
,
**
kwds
):
def
add_watcher
(
self
,
*
args
,
**
kwds
):
raise
UnsupportedError
raise
UnsupportedError
def
del_watcher
(
self
,
watcher_or_callback
):
def
del_watcher
(
self
,
watcher_or_callback
):
...
...
fs/osfs/xattrs.py
View file @
60da3d53
...
@@ -23,9 +23,12 @@ except ImportError:
...
@@ -23,9 +23,12 @@ except ImportError:
if
xattr
is
not
None
:
if
xattr
is
not
None
:
class
OSFSXAttrMixin
(
FS
):
class
OSFSXAttrMixin
(
object
):
"""Mixin providing extended-attribute support via the 'xattr' module"""
"""Mixin providing extended-attribute support via the 'xattr' module"""
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
OSFSXAttrMixin
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
@convert_os_errors
@convert_os_errors
def
setxattr
(
self
,
path
,
key
,
value
):
def
setxattr
(
self
,
path
,
key
,
value
):
xattr
.
xattr
(
self
.
getsyspath
(
path
))[
key
]
=
value
xattr
.
xattr
(
self
.
getsyspath
(
path
))[
key
]
=
value
...
@@ -53,6 +56,9 @@ else:
...
@@ -53,6 +56,9 @@ else:
class
OSFSXAttrMixin
(
object
):
class
OSFSXAttrMixin
(
object
):
"""Mixin disable extended-attribute support."""
"""Mixin disable extended-attribute support."""
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
OSFSXAttrMixin
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
getxattr
(
self
,
path
,
key
,
default
=
None
):
def
getxattr
(
self
,
path
,
key
,
default
=
None
):
raise
UnsupportedError
raise
UnsupportedError
...
...
fs/s3fs.py
View file @
60da3d53
...
@@ -496,6 +496,8 @@ class S3FS(FS):
...
@@ -496,6 +496,8 @@ class S3FS(FS):
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
"""Remove the directory at the given path."""
"""Remove the directory at the given path."""
if
normpath
(
path
)
in
(
''
,
'/'
):
raise
DeleteRootError
(
path
)
s3path
=
self
.
_s3path
(
path
)
s3path
=
self
.
_s3path
(
path
)
if
s3path
!=
self
.
_prefix
:
if
s3path
!=
self
.
_prefix
:
s3path
=
s3path
+
self
.
_separator
s3path
=
s3path
+
self
.
_separator
...
...
fs/sftpfs.py
View file @
60da3d53
...
@@ -475,8 +475,8 @@ class SFTPFS(FS):
...
@@ -475,8 +475,8 @@ class SFTPFS(FS):
@convert_os_errors
@convert_os_errors
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
npath
=
self
.
_normpath
(
path
)
npath
=
self
.
_normpath
(
path
)
if
path
in
(
""
,
"/"
):
if
normpath
(
path
)
in
(
''
,
'/'
):
r
eturn
r
aise
DeleteRootError
(
path
)
if
force
:
if
force
:
for
path2
in
self
.
listdir
(
path
,
absolute
=
True
):
for
path2
in
self
.
listdir
(
path
,
absolute
=
True
):
try
:
try
:
...
...
fs/tests/__init__.py
View file @
60da3d53
...
@@ -840,6 +840,8 @@ class FSTestCases(object):
...
@@ -840,6 +840,8 @@ class FSTestCases(object):
self
.
assertTrue
(
cmp_datetimes
(
d1
,
info
[
'accessed_time'
]))
self
.
assertTrue
(
cmp_datetimes
(
d1
,
info
[
'accessed_time'
]))
self
.
assertTrue
(
cmp_datetimes
(
d2
,
info
[
'modified_time'
]))
self
.
assertTrue
(
cmp_datetimes
(
d2
,
info
[
'modified_time'
]))
def
test_removeroot
(
self
):
self
.
assertRaises
(
DeleteRootError
,
self
.
fs
.
removedir
,
"/"
)
# May be disabled - see end of file
# May be disabled - see end of file
class
ThreadingTestCases
(
object
):
class
ThreadingTestCases
(
object
):
...
...
fs/tests/test_expose.py
View file @
60da3d53
...
@@ -127,6 +127,7 @@ except ImportError:
...
@@ -127,6 +127,7 @@ except ImportError:
class
TestSFTPFS
(
TestRPCFS
):
class
TestSFTPFS
(
TestRPCFS
):
__test__
=
not
PY3
__test__
=
not
PY3
__test__
=
False
def
makeServer
(
self
,
fs
,
addr
):
def
makeServer
(
self
,
fs
,
addr
):
return
BaseSFTPServer
(
addr
,
fs
)
return
BaseSFTPServer
(
addr
,
fs
)
...
...
fs/tests/test_utils.py
0 → 100644
View file @
60da3d53
import
unittest
from
fs.tempfs
import
TempFS
from
fs.memoryfs
import
MemoryFS
from
fs
import
utils
class
TestUtils
(
unittest
.
TestCase
):
def
_make_fs
(
self
,
fs
):
fs
.
setcontents
(
"f1"
,
"file 1"
)
fs
.
setcontents
(
"f2"
,
"file 2"
)
fs
.
setcontents
(
"f3"
,
"file 3"
)
fs
.
makedir
(
"foo/bar"
,
recursive
=
True
)
fs
.
setcontents
(
"foo/bar/fruit"
,
"apple"
)
def
_check_fs
(
self
,
fs
):
self
.
assert_
(
fs
.
isfile
(
"f1"
))
self
.
assert_
(
fs
.
isfile
(
"f2"
))
self
.
assert_
(
fs
.
isfile
(
"f3"
))
self
.
assert_
(
fs
.
isdir
(
"foo/bar"
))
self
.
assert_
(
fs
.
isfile
(
"foo/bar/fruit"
))
self
.
assertEqual
(
fs
.
getcontents
(
"f1"
,
"rb"
),
"file 1"
)
self
.
assertEqual
(
fs
.
getcontents
(
"f2"
,
"rb"
),
"file 2"
)
self
.
assertEqual
(
fs
.
getcontents
(
"f3"
,
"rb"
),
"file 3"
)
self
.
assertEqual
(
fs
.
getcontents
(
"foo/bar/fruit"
,
"rb"
),
"apple"
)
def
test_copydir_root
(
self
):
"""Test copydir from root"""
fs1
=
MemoryFS
()
self
.
_make_fs
(
fs1
)
fs2
=
MemoryFS
()
utils
.
copydir
(
fs1
,
fs2
)
self
.
_check_fs
(
fs2
)
fs1
=
TempFS
()
self
.
_make_fs
(
fs1
)
fs2
=
TempFS
()
utils
.
copydir
(
fs1
,
fs2
)
self
.
_check_fs
(
fs2
)
def
test_copydir_indir
(
self
):
"""Test copydir in a directory"""
fs1
=
MemoryFS
()
fs2
=
MemoryFS
()
self
.
_make_fs
(
fs1
)
utils
.
copydir
(
fs1
,
(
fs2
,
"copy"
))
self
.
_check_fs
(
fs2
.
opendir
(
"copy"
))
fs1
=
TempFS
()
fs2
=
TempFS
()
self
.
_make_fs
(
fs1
)
utils
.
copydir
(
fs1
,
(
fs2
,
"copy"
))
self
.
_check_fs
(
fs2
.
opendir
(
"copy"
))
def
test_movedir_indir
(
self
):
"""Test movedir in a directory"""
fs1
=
MemoryFS
()
fs2
=
MemoryFS
()
fs1sub
=
fs1
.
makeopendir
(
"from"
)
self
.
_make_fs
(
fs1sub
)
utils
.
movedir
((
fs1
,
"from"
),
(
fs2
,
"copy"
))
self
.
assert_
(
not
fs1
.
exists
(
"from"
))
self
.
_check_fs
(
fs2
.
opendir
(
"copy"
))
fs1
=
TempFS
()
fs2
=
TempFS
()
fs1sub
=
fs1
.
makeopendir
(
"from"
)
self
.
_make_fs
(
fs1sub
)
utils
.
movedir
((
fs1
,
"from"
),
(
fs2
,
"copy"
))
self
.
assert_
(
not
fs1
.
exists
(
"from"
))
self
.
_check_fs
(
fs2
.
opendir
(
"copy"
))
def
test_movedir_root
(
self
):
"""Test movedir to root dir"""
fs1
=
MemoryFS
()
fs2
=
MemoryFS
()
fs1sub
=
fs1
.
makeopendir
(
"from"
)
self
.
_make_fs
(
fs1sub
)
utils
.
movedir
((
fs1
,
"from"
),
fs2
)
self
.
assert_
(
not
fs1
.
exists
(
"from"
))
self
.
_check_fs
(
fs2
)
fs1
=
TempFS
()
fs2
=
TempFS
()
fs1sub
=
fs1
.
makeopendir
(
"from"
)
self
.
_make_fs
(
fs1sub
)
utils
.
movedir
((
fs1
,
"from"
),
fs2
)
self
.
assert_
(
not
fs1
.
exists
(
"from"
))
self
.
_check_fs
(
fs2
)
if
__name__
==
"__main__"
:
def
_make_fs
(
fs
):
fs
.
setcontents
(
"f1"
,
"file 1"
)
fs
.
setcontents
(
"f2"
,
"file 2"
)
fs
.
setcontents
(
"f3"
,
"file 3"
)
fs
.
makedir
(
"foo/bar"
,
recursive
=
True
)
fs
.
setcontents
(
"foo/bar/fruit"
,
"apple"
)
fs1
=
TempFS
()
fs2
=
TempFS
()
fs1sub
=
fs1
.
makeopendir
(
"from"
)
_make_fs
(
fs1sub
)
utils
.
movedir
((
fs1
,
"from"
),
fs2
)
#self.assert_(not fs1.exists("from"))
#self._check_fs(fs2)
\ No newline at end of file
fs/utils.py
View file @
60da3d53
...
@@ -12,8 +12,7 @@ __all__ = ['copyfile',
...
@@ -12,8 +12,7 @@ __all__ = ['copyfile',
'isfile'
,
'isfile'
,
'isdir'
,
'isdir'
,
'find_duplicates'
,
'find_duplicates'
,
'print_fs'
,
'print_fs'
]
'wrap_file'
]
import
os
import
os
import
sys
import
sys
...
@@ -21,7 +20,7 @@ import stat
...
@@ -21,7 +20,7 @@ import stat
from
fs.mountfs
import
MountFS
from
fs.mountfs
import
MountFS
from
fs.path
import
pathjoin
from
fs.path
import
pathjoin
from
fs.errors
import
DestinationExistsError
from
fs.errors
import
DestinationExistsError
,
DeleteRootError
from
fs.base
import
FS
from
fs.base
import
FS
def
copyfile
(
src_fs
,
src_path
,
dst_fs
,
dst_path
,
overwrite
=
True
,
chunk_size
=
64
*
1024
):
def
copyfile
(
src_fs
,
src_path
,
dst_fs
,
dst_path
,
overwrite
=
True
,
chunk_size
=
64
*
1024
):
...
@@ -187,38 +186,51 @@ def movefile_non_atomic(src_fs, src_path, dst_fs, dst_path, overwrite=True, chun
...
@@ -187,38 +186,51 @@ def movefile_non_atomic(src_fs, src_path, dst_fs, dst_path, overwrite=True, chun
dst
.
close
()
dst
.
close
()
def
movedir
(
fs1
,
fs2
,
overwrite
=
Fals
e
,
ignore_errors
=
False
,
chunk_size
=
64
*
1024
):
def
movedir
(
fs1
,
fs2
,
create_destination
=
Tru
e
,
ignore_errors
=
False
,
chunk_size
=
64
*
1024
):
"""Moves contents of a directory from one filesystem to another.
"""Moves contents of a directory from one filesystem to another.
:param fs1:
Source filesystem, or a
tuple of (<filesystem>, <directory path>)
:param fs1:
A
tuple of (<filesystem>, <directory path>)
:param fs2: Destination filesystem, or a tuple of (<filesystem>, <directory path>)
:param fs2: Destination filesystem, or a tuple of (<filesystem>, <directory path>)
:param create_destination: If True, the destination will be created if it doesn't exist
:param ignore_errors: If True, exceptions from file moves are ignored
:param ignore_errors: If True, exceptions from file moves are ignored
:param chunk_size: Size of chunks to move if a simple copy is used
:param chunk_size: Size of chunks to move if a simple copy is used
"""
"""
if
isinstance
(
fs1
,
tuple
):
if
not
isinstance
(
fs1
,
tuple
):
raise
ValueError
(
"first argument must be a tuple of (<filesystem>, <path>)"
)
fs1
,
dir1
=
fs1
fs1
,
dir1
=
fs1
parent_fs1
=
fs1
parent_dir1
=
dir1
fs1
=
fs1
.
opendir
(
dir1
)
fs1
=
fs1
.
opendir
(
dir1
)
print
fs1
if
parent_dir1
in
(
''
,
'/'
):
raise
DeleteRootError
(
dir1
)
if
isinstance
(
fs2
,
tuple
):
if
isinstance
(
fs2
,
tuple
):
fs2
,
dir2
=
fs2
fs2
,
dir2
=
fs2
fs2
.
makedir
(
dir2
,
allow_recreate
=
True
)
if
create_destination
:
fs2
.
makedir
(
dir2
,
allow_recreate
=
True
,
recursive
=
True
)
fs2
=
fs2
.
opendir
(
dir2
)
fs2
=
fs2
.
opendir
(
dir2
)
mount_fs
=
MountFS
()
mount_fs
=
MountFS
(
auto_close
=
False
)
mount_fs
.
mount
(
'src'
,
fs1
)
mount_fs
.
mount
(
'src'
,
fs1
)
mount_fs
.
mount
(
'dst'
,
fs2
)
mount_fs
.
mount
(
'dst'
,
fs2
)
mount_fs
.
move
dir
(
'src'
,
'dst'
,
mount_fs
.
copy
dir
(
'src'
,
'dst'
,
overwrite
=
overwrit
e
,
overwrite
=
Tru
e
,
ignore_errors
=
ignore_errors
,
ignore_errors
=
ignore_errors
,
chunk_size
=
chunk_size
)
chunk_size
=
chunk_size
)
parent_fs1
.
removedir
(
parent_dir1
,
force
=
True
)
def
copydir
(
fs1
,
fs2
,
overwrite
=
Fals
e
,
ignore_errors
=
False
,
chunk_size
=
64
*
1024
):
def
copydir
(
fs1
,
fs2
,
create_destination
=
Tru
e
,
ignore_errors
=
False
,
chunk_size
=
64
*
1024
):
"""Copies contents of a directory from one filesystem to another.
"""Copies contents of a directory from one filesystem to another.
:param fs1: Source filesystem, or a tuple of (<filesystem>, <directory path>)
:param fs1: Source filesystem, or a tuple of (<filesystem>, <directory path>)
:param fs2: Destination filesystem, or a tuple of (<filesystem>, <directory path>)
:param fs2: Destination filesystem, or a tuple of (<filesystem>, <directory path>)
:param create_destination: If True, the destination will be created if it doesn't exist
:param ignore_errors: If True, exceptions from file moves are ignored
:param ignore_errors: If True, exceptions from file moves are ignored
:param chunk_size: Size of chunks to move if a simple copy is used
:param chunk_size: Size of chunks to move if a simple copy is used
...
@@ -228,14 +240,15 @@ def copydir(fs1, fs2, overwrite=False, ignore_errors=False, chunk_size=64*1024):
...
@@ -228,14 +240,15 @@ def copydir(fs1, fs2, overwrite=False, ignore_errors=False, chunk_size=64*1024):
fs1
=
fs1
.
opendir
(
dir1
)
fs1
=
fs1
.
opendir
(
dir1
)
if
isinstance
(
fs2
,
tuple
):
if
isinstance
(
fs2
,
tuple
):
fs2
,
dir2
=
fs2
fs2
,
dir2
=
fs2
fs2
.
makedir
(
dir2
,
allow_recreate
=
True
)
if
create_destination
:
fs2
.
makedir
(
dir2
,
allow_recreate
=
True
,
recursive
=
True
)
fs2
=
fs2
.
opendir
(
dir2
)
fs2
=
fs2
.
opendir
(
dir2
)
mount_fs
=
MountFS
()
mount_fs
=
MountFS
(
auto_close
=
False
)
mount_fs
.
mount
(
'src'
,
fs1
)
mount_fs
.
mount
(
'src'
,
fs1
)
mount_fs
.
mount
(
'dst'
,
fs2
)
mount_fs
.
mount
(
'dst'
,
fs2
)
mount_fs
.
copydir
(
'src'
,
'dst'
,
mount_fs
.
copydir
(
'src'
,
'dst'
,
overwrite
=
overwrit
e
,
overwrite
=
Tru
e
,
ignore_errors
=
ignore_errors
,
ignore_errors
=
ignore_errors
,
chunk_size
=
chunk_size
)
chunk_size
=
chunk_size
)
...
@@ -519,11 +532,20 @@ def print_fs(fs, path='/', max_levels=5, file_out=None, terminal_colors=None, hi
...
@@ -519,11 +532,20 @@ def print_fs(fs, path='/', max_levels=5, file_out=None, terminal_colors=None, hi
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
from
fs.memoryfs
import
MemoryFS
from
fs.tempfs
import
TempFS
m
=
MemoryFS
()
t1
=
TempFS
()
m
.
setcontents
(
"test"
,
"Hello, World!"
*
10000
)
t1
.
setcontents
(
"foo"
,
"test"
)
t1
.
makedir
(
"bar"
)
f
=
m
.
open
(
"test"
)
t1
.
setcontents
(
"bar/baz"
,
"another test"
)
print
f
tf
=
wrap_file
(
f
,
"r"
)
t1
.
tree
()
print
repr
(
tf
.
read
(
10
))
t2
=
TempFS
()
print
t2
.
listdir
()
movedir
(
t1
,
t2
)
print
t2
.
listdir
()
t1
.
tree
()
t2
.
tree
()
fs/wrapfs/__init__.py
View file @
60da3d53
...
@@ -18,6 +18,7 @@ standard unix shell functionality of hiding dot-files in directory listings.
...
@@ -18,6 +18,7 @@ standard unix shell functionality of hiding dot-files in directory listings.
import
re
import
re
import
sys
import
sys
import
fnmatch
import
fnmatch
import
threading
from
fs.base
import
FS
,
threading
,
synchronize
,
NoDefaultMeta
from
fs.base
import
FS
,
threading
,
synchronize
,
NoDefaultMeta
from
fs.errors
import
*
from
fs.errors
import
*
...
@@ -65,11 +66,11 @@ class WrapFS(FS):
...
@@ -65,11 +66,11 @@ class WrapFS(FS):
"""
"""
def
__init__
(
self
,
fs
):
def
__init__
(
self
,
fs
):
super
(
WrapFS
,
self
)
.
__init__
()
super
(
WrapFS
,
self
)
.
__init__
()
try
:
try
:
self
.
_lock
=
fs
.
_lock
self
.
_lock
=
fs
.
_lock
except
(
AttributeError
,
FSError
):
except
(
AttributeError
,
FSError
):
self
.
_lock
=
None
self
.
_lock
=
self
.
_lock
=
threading
.
RLock
()
self
.
wrapped_fs
=
fs
self
.
wrapped_fs
=
fs
def
_file_wrap
(
self
,
f
,
mode
):
def
_file_wrap
(
self
,
f
,
mode
):
...
...
fs/wrapfs/lazyfs.py
View file @
60da3d53
...
@@ -29,7 +29,7 @@ class LazyFS(WrapFS):
...
@@ -29,7 +29,7 @@ class LazyFS(WrapFS):
"""
"""
def
__init__
(
self
,
fs
):
def
__init__
(
self
,
fs
):
super
(
LazyFS
,
self
)
.
__init__
(
fs
)
super
(
LazyFS
,
self
)
.
__init__
(
fs
)
self
.
_lazy_creation_lock
=
Lock
()
self
.
_lazy_creation_lock
=
Lock
()
def
__unicode__
(
self
):
def
__unicode__
(
self
):
...
...
fs/wrapfs/subfs.py
View file @
60da3d53
...
@@ -60,27 +60,38 @@ class SubFS(WrapFS):
...
@@ -60,27 +60,38 @@ class SubFS(WrapFS):
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
# Careful not to recurse outside the subdir
# Careful not to recurse outside the subdir
path
=
normpath
(
path
)
path
=
normpath
(
path
)
if
path
in
(
""
,
"/"
):
if
path
in
(
''
,
'/'
):
if
not
force
:
raise
DeleteRootError
(
path
)
for
path2
in
self
.
listdir
(
path
):
raise
DirectoryNotEmptyError
(
path
)
else
:
for
path2
in
self
.
listdir
(
path
,
absolute
=
True
,
files_only
=
True
):
try
:
self
.
remove
(
path2
)
except
ResourceNotFoundError
:
pass
for
path2
in
self
.
listdir
(
path
,
absolute
=
True
,
dirs_only
=
True
):
try
:
self
.
removedir
(
path2
,
force
=
True
)
except
ResourceNotFoundError
:
pass
else
:
super
(
SubFS
,
self
)
.
removedir
(
path
,
force
=
force
)
super
(
SubFS
,
self
)
.
removedir
(
path
,
force
=
force
)
if
recursive
:
if
recursive
:
try
:
try
:
if
dirname
(
path
)
not
in
(
''
,
'/'
):
self
.
removedir
(
dirname
(
path
),
recursive
=
True
)
self
.
removedir
(
dirname
(
path
),
recursive
=
True
)
except
DirectoryNotEmptyError
:
except
DirectoryNotEmptyError
:
pass
pass
# if path in ("","/"):
# if not force:
# for path2 in self.listdir(path):
# raise DirectoryNotEmptyError(path)
# else:
# for path2 in self.listdir(path,absolute=True,files_only=True):
# try:
# self.remove(path2)
# except ResourceNotFoundError:
# pass
# for path2 in self.listdir(path,absolute=True,dirs_only=True):
# try:
# self.removedir(path2,force=True)
# except ResourceNotFoundError:
# pass
# else:
# super(SubFS,self).removedir(path,force=force)
# if recursive:
# try:
# if dirname(path):
# self.removedir(dirname(path),recursive=True)
# except DirectoryNotEmptyError:
# pass
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment