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
f001445d
Commit
f001445d
authored
Mar 30, 2011
by
rfkelly0
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
make LimitSizeFS more robust
parent
92e3024b
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
143 additions
and
79 deletions
+143
-79
fs/base.py
+3
-0
fs/tests/__init__.py
+1
-1
fs/wrapfs/limitsizefs.py
+139
-78
No files found.
fs/base.py
View file @
f001445d
...
@@ -971,6 +971,9 @@ class FS(object):
...
@@ -971,6 +971,9 @@ class FS(object):
try
:
try
:
src_file
=
self
.
open
(
src
,
"rb"
)
src_file
=
self
.
open
(
src
,
"rb"
)
self
.
setcontents
(
dst
,
src_file
,
chunk_size
=
chunk_size
)
self
.
setcontents
(
dst
,
src_file
,
chunk_size
=
chunk_size
)
except
ResourceNotFoundError
:
if
self
.
exists
(
src
)
and
not
self
.
exists
(
dirname
(
dst
)):
raise
ParentDirectoryMissingError
(
dst
)
finally
:
finally
:
if
src_file
is
not
None
:
if
src_file
is
not
None
:
src_file
.
close
()
src_file
.
close
()
...
...
fs/tests/__init__.py
View file @
f001445d
...
@@ -788,7 +788,7 @@ class FSTestCases(object):
...
@@ -788,7 +788,7 @@ class FSTestCases(object):
def
test_big_file
(
self
):
def
test_big_file
(
self
):
"""Test
big files
(1MB)"""
"""Test
handling of a big file
(1MB)"""
chunk_size
=
1024
*
256
chunk_size
=
1024
*
256
num_chunks
=
4
num_chunks
=
4
def
chunk_stream
():
def
chunk_stream
():
...
...
fs/wrapfs/limitsizefs.py
View file @
f001445d
...
@@ -8,12 +8,14 @@ This module provides the class LimitSizeFS, an FS wrapper that can limit the
...
@@ -8,12 +8,14 @@ This module provides the class LimitSizeFS, an FS wrapper that can limit the
total size of files stored in the wrapped FS.
total size of files stored in the wrapped FS.
"""
"""
# for Python2.5 compatibility
from
__future__
import
with_statement
from
__future__
import
with_statement
from
fs.errors
import
*
from
fs.errors
import
*
from
fs.path
import
*
from
fs.path
import
*
from
fs.base
import
FS
,
threading
,
synchronize
from
fs.base
import
FS
,
threading
,
synchronize
from
fs.wrapfs
import
WrapFS
from
fs.wrapfs
import
WrapFS
from
fs.filelike
import
FileWrapper
class
LimitSizeFS
(
WrapFS
):
class
LimitSizeFS
(
WrapFS
):
...
@@ -21,17 +23,21 @@ class LimitSizeFS(WrapFS):
...
@@ -21,17 +23,21 @@ class LimitSizeFS(WrapFS):
def
__init__
(
self
,
fs
,
max_size
):
def
__init__
(
self
,
fs
,
max_size
):
super
(
LimitSizeFS
,
self
)
.
__init__
(
fs
)
super
(
LimitSizeFS
,
self
)
.
__init__
(
fs
)
if
max_size
<
0
:
try
:
max_size
=
fs
.
getmeta
(
"total_space"
)
+
max_size
except
NotMetaError
:
msg
=
"FS doesn't report total_size; "
\
"can't use negative max_size"
raise
ValueError
(
msg
)
self
.
max_size
=
max_size
self
.
max_size
=
max_size
self
.
cur_size
=
sum
(
self
.
getsize
(
f
)
for
f
in
self
.
walkfiles
())
self
.
_size_lock
=
threading
.
Lock
()
self
.
_size_lock
=
threading
.
Lock
()
self
.
_file_sizes
=
{}
self
.
_file_sizes
=
PathMap
()
self
.
cur_size
=
self
.
_get_cur_size
()
def
_decr_size
(
self
,
decr
):
with
self
.
_size_lock
:
self
.
cur_size
-=
decr
def
__getstate__
(
self
):
def
__getstate__
(
self
):
state
=
super
(
LimitSizeFS
,
self
)
.
__getstate__
()
state
=
super
(
LimitSizeFS
,
self
)
.
__getstate__
()
del
state
[
"cur_size"
]
del
state
[
"_size_lock"
]
del
state
[
"_size_lock"
]
del
state
[
"_file_sizes"
]
del
state
[
"_file_sizes"
]
return
state
return
state
...
@@ -39,8 +45,15 @@ class LimitSizeFS(WrapFS):
...
@@ -39,8 +45,15 @@ class LimitSizeFS(WrapFS):
def
__setstate__
(
self
,
state
):
def
__setstate__
(
self
,
state
):
super
(
LimitSizeFS
,
self
)
.
__setstate__
(
state
)
super
(
LimitSizeFS
,
self
)
.
__setstate__
(
state
)
self
.
_size_lock
=
threading
.
Lock
()
self
.
_size_lock
=
threading
.
Lock
()
self
.
_file_sizes
=
PathMap
()
self
.
cur_size
=
self
.
_get_cur_size
()
def
_get_cur_size
(
self
):
return
sum
(
self
.
getsize
(
f
)
for
f
in
self
.
walkfiles
())
def
getsyspath
(
self
,
path
,
allow_none
=
False
):
def
getsyspath
(
self
,
path
,
allow_none
=
False
):
# If people could grab syspaths, they could route around our
# size protection; no dice!
if
not
allow_none
:
if
not
allow_none
:
raise
NoSysPathError
(
path
)
raise
NoSysPathError
(
path
)
return
None
return
None
...
@@ -53,14 +66,33 @@ class LimitSizeFS(WrapFS):
...
@@ -53,14 +66,33 @@ class LimitSizeFS(WrapFS):
except
ResourceNotFoundError
:
except
ResourceNotFoundError
:
size
=
0
size
=
0
f
=
super
(
LimitSizeFS
,
self
)
.
open
(
path
,
mode
)
f
=
super
(
LimitSizeFS
,
self
)
.
open
(
path
,
mode
)
if
path
not
in
self
.
_file_sizes
:
if
"w"
not
in
mode
:
self
.
_
file_sizes
[
path
]
=
size
self
.
_
set_file_size
(
path
,
None
,
1
)
if
"w"
in
mod
e
:
els
e
:
self
.
cur_size
-=
size
self
.
cur_size
-=
size
print
"OPEN, SIZE NOW"
,
self
.
cur_size
size
=
0
size
=
0
self
.
_file_sizes
[
path
]
=
0
self
.
_set_file_size
(
path
,
0
,
1
)
return
LimitSizeFile
(
self
,
path
,
f
,
mode
,
size
)
return
LimitSizeFile
(
f
,
mode
,
size
,
self
,
path
)
def
_set_file_size
(
self
,
path
,
size
,
incrcount
=
None
):
try
:
(
cursize
,
count
)
=
self
.
_file_sizes
[
path
]
except
KeyError
:
count
=
0
try
:
cursize
=
self
.
getsize
(
path
)
except
ResourceNotFoundError
:
cursize
=
0
if
size
is
None
:
size
=
cursize
if
count
is
not
None
:
count
+=
1
if
count
==
0
:
del
self
.
_file_sizes
[
path
]
else
:
self
.
_file_sizes
[
path
]
=
(
size
,
count
)
def
setcontents
(
self
,
path
,
data
,
chunk_size
=
64
*
1024
):
def
setcontents
(
self
,
path
,
data
,
chunk_size
=
64
*
1024
):
f
=
None
f
=
None
try
:
try
:
...
@@ -76,22 +108,42 @@ class LimitSizeFS(WrapFS):
...
@@ -76,22 +108,42 @@ class LimitSizeFS(WrapFS):
if
f
is
not
None
:
if
f
is
not
None
:
f
.
close
()
f
.
close
()
def
_file_closed
(
self
,
path
):
self
.
_set_file_size
(
path
,
None
,
-
1
)
def
_ensure_file_size
(
self
,
path
,
size
,
shrink
=
False
):
def
_ensure_file_size
(
self
,
path
,
size
,
shrink
=
False
):
path
=
relpath
(
normpath
(
path
))
with
self
.
_size_lock
:
with
self
.
_size_lock
:
if
path
not
in
self
.
_file_sizes
:
try
:
self
.
_file_sizes
[
path
]
=
self
.
getsize
(
path
)
(
cur_size
,
_
)
=
self
.
_file_sizes
[
path
]
cur_size
=
self
.
_file_sizes
[
path
]
print
"...LOADED"
,
cur_size
except
KeyError
:
print
"...NOT LOADED"
try
:
cur_size
=
self
.
getsize
(
path
)
except
ResourceNotFoundError
:
cur_size
=
0
self
.
_set_file_size
(
path
,
cur_size
,
1
)
print
"WRITING"
,
path
,
size
,
cur_size
diff
=
size
-
cur_size
diff
=
size
-
cur_size
if
diff
>
0
:
if
diff
>
0
:
if
self
.
cur_size
+
diff
>
self
.
max_size
:
if
self
.
cur_size
+
diff
>
self
.
max_size
:
raise
StorageSpaceError
(
"write"
)
raise
StorageSpaceError
(
"write"
)
self
.
cur_size
+=
diff
self
.
cur_size
+=
diff
self
.
_file_sizes
[
path
]
=
size
print
"WRITE, CUR SIZE NOW"
,
self
.
cur_size
self
.
_set_file_size
(
path
,
size
)
print
self
.
_file_sizes
[
path
]
return
size
elif
diff
<
0
and
shrink
:
elif
diff
<
0
and
shrink
:
self
.
cur_size
+=
diff
self
.
cur_size
+=
diff
self
.
_file_sizes
[
path
]
=
size
print
"WRITE, CUR SIZE NOW"
,
self
.
cur_size
self
.
_set_file_size
(
path
,
size
)
return
size
else
:
return
cur_size
# We force use of several base FS methods,
# since they will fall back to writing out each file
# and thus will route through our size checking logic.
def
copy
(
self
,
src
,
dst
,
**
kwds
):
def
copy
(
self
,
src
,
dst
,
**
kwds
):
FS
.
copy
(
self
,
src
,
dst
,
**
kwds
)
FS
.
copy
(
self
,
src
,
dst
,
**
kwds
)
...
@@ -99,86 +151,95 @@ class LimitSizeFS(WrapFS):
...
@@ -99,86 +151,95 @@ class LimitSizeFS(WrapFS):
FS
.
copydir
(
self
,
src
,
dst
,
**
kwds
)
FS
.
copydir
(
self
,
src
,
dst
,
**
kwds
)
def
move
(
self
,
src
,
dst
,
**
kwds
):
def
move
(
self
,
src
,
dst
,
**
kwds
):
FS
.
move
(
self
,
src
,
dst
,
**
kwds
)
FS
.
move
(
self
,
src
,
dst
,
**
kwds
)
path
=
relpath
(
normpath
(
src
))
with
self
.
_size_lock
:
self
.
_file_sizes
.
pop
(
path
,
None
)
def
movedir
(
self
,
src
,
dst
,
**
kwds
):
def
movedir
(
self
,
src
,
dst
,
**
kwds
):
FS
.
movedir
(
self
,
src
,
dst
,
**
kwds
)
FS
.
movedir
(
self
,
src
,
dst
,
**
kwds
)
def
remove
(
self
,
path
):
def
remove
(
self
,
path
):
size
=
self
.
getsize
(
path
)
super
(
LimitSizeFS
,
self
)
.
remove
(
path
)
self
.
_decr_size
(
size
)
path
=
relpath
(
normpath
(
path
))
with
self
.
_size_lock
:
with
self
.
_size_lock
:
try
:
(
size
,
_
)
=
self
.
_file_sizes
[
path
]
except
KeyError
:
size
=
self
.
getsize
(
path
)
super
(
LimitSizeFS
,
self
)
.
remove
(
path
)
self
.
cur_size
-=
size
print
"REMOVE, SIZE NOW"
,
self
.
cur_size
self
.
_file_sizes
.
pop
(
path
,
None
)
self
.
_file_sizes
.
pop
(
path
,
None
)
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
def
removedir
(
self
,
path
,
recursive
=
False
,
force
=
False
):
size
=
sum
(
self
.
getsize
(
f
)
for
f
in
self
.
walkfiles
(
path
))
# Walk and remove directories by hand, so they we
super
(
LimitSizeFS
,
self
)
.
removedir
(
path
,
recursive
=
recursive
,
force
=
force
)
# keep the size accounting precisely up to date.
self
.
_decr_size
(
size
)
for
nm
in
self
.
listdir
(
path
):
if
not
force
:
raise
DirectoryNotEmptyError
(
path
)
cpath
=
pathjoin
(
path
,
nm
)
try
:
if
self
.
isdir
(
cpath
):
self
.
removedir
(
cpath
,
force
=
True
)
else
:
self
.
remove
(
cpath
)
except
ResourceNotFoundError
:
pass
super
(
LimitSizeFS
,
self
)
.
removedir
(
path
,
recursive
=
recursive
)
def
rename
(
self
,
src
,
dst
):
def
rename
(
self
,
src
,
dst
):
if
self
.
getmeta
(
"atomic.rename"
,
False
):
super
(
LimitSizeFS
,
self
)
.
rename
(
src
,
dst
)
with
self
.
_size_lock
:
self
.
_file_sizes
.
pop
(
src
,
None
)
else
:
if
self
.
isdir
(
src
):
self
.
movedir
(
src
,
dst
)
else
:
self
.
move
(
src
,
dst
)
def
getinfo
(
self
,
path
):
info
=
super
(
LimitSizeFS
,
self
)
.
getinfo
(
path
)
try
:
try
:
size
=
self
.
getsize
(
dst
)
info
[
"size"
]
=
max
(
self
.
_file_sizes
[
path
][
0
],
info
[
"size"
])
except
ResourceNotFoundError
:
except
KeyError
:
size
=
0
pass
super
(
LimitSizeFS
,
self
)
.
rename
(
src
,
dst
)
return
info
self
.
_decr_size
(
size
)
path
=
relpath
(
normpath
(
src
))
def
getsize
(
self
,
path
):
with
self
.
_size_lock
:
size
=
super
(
LimitSizeFS
,
self
)
.
getsize
(
path
)
self
.
_file_sizes
.
pop
(
path
,
None
)
try
:
size
=
max
(
self
.
_file_sizes
[
path
][
0
],
size
)
except
KeyError
:
pass
return
size
class
LimitSizeFile
(
object
):
class
LimitSizeFile
(
FileWrapper
):
"""Filelike wrapper class for use by LimitSizeFS."""
"""Filelike wrapper class for use by LimitSizeFS."""
def
__init__
(
self
,
fs
,
path
,
file
,
mode
,
size
):
def
__init__
(
self
,
file
,
mode
,
size
,
fs
,
path
):
self
.
_lock
=
fs
.
_lock
super
(
LimitSizeFile
,
self
)
.
__init__
(
file
,
mode
)
self
.
size
=
size
self
.
fs
=
fs
self
.
fs
=
fs
self
.
path
=
path
self
.
path
=
path
self
.
file
=
file
self
.
_lock
=
fs
.
_lock
self
.
mode
=
mode
self
.
size
=
size
self
.
closed
=
False
@synchronize
@synchronize
def
write
(
self
,
data
):
def
_write
(
self
,
data
,
flushing
=
False
):
pos
=
self
.
file
.
tell
()
pos
=
self
.
wrapped_file
.
tell
()
self
.
size
=
self
.
fs
.
_ensure_file_size
(
self
.
path
,
pos
+
len
(
data
))
new_size
=
self
.
fs
.
_ensure_file_size
(
self
.
path
,
pos
+
len
(
data
))
self
.
file
.
write
(
data
)
res
=
super
(
LimitSizeFile
,
self
)
.
_write
(
data
,
flushing
)
self
.
size
=
new_size
def
writelines
(
self
,
lines
):
return
res
for
line
in
lines
:
self
.
write
(
line
)
@synchronize
@synchronize
def
truncate
(
self
,
size
=
None
):
def
_truncate
(
self
,
size
):
pos
=
self
.
file
.
tell
()
new_size
=
self
.
fs
.
_ensure_file_size
(
self
.
path
,
size
,
shrink
=
True
)
if
size
is
None
:
res
=
super
(
LimitSizeFile
,
self
)
.
_truncate
(
size
)
size
=
pos
self
.
size
=
new_size
self
.
fs
.
_ensure_file_size
(
self
.
path
,
size
,
shrink
=
True
)
return
res
self
.
file
.
truncate
(
size
)
self
.
size
=
size
# This is lifted straight from the stdlib's tempfile.py
def
__getattr__
(
self
,
name
):
file
=
self
.
__dict__
[
'file'
]
a
=
getattr
(
file
,
name
)
if
not
issubclass
(
type
(
a
),
type
(
0
)):
setattr
(
self
,
name
,
a
)
return
a
def
__enter__
(
self
):
@synchronize
self
.
file
.
__enter__
()
def
close
(
self
):
return
self
super
(
LimitSizeFile
,
self
)
.
close
()
self
.
fs
.
_file_closed
(
self
.
path
)
def
__exit__
(
self
,
exc
,
value
,
tb
):
self
.
close
()
return
False
def
__iter__
(
self
):
return
iter
(
self
.
file
)
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