Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
141
Merge Requests
141
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
nexedi
erp5
Commits
82c36966
Commit
82c36966
authored
Feb 15, 2024
by
Jérome Perrin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
big_file: py3
parent
395566b6
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
141 additions
and
135 deletions
+141
-135
bt5/erp5_big_file/DocumentTemplateItem/portal_components/document.erp5.BigFile.py
...ntTemplateItem/portal_components/document.erp5.BigFile.py
+25
-20
bt5/erp5_big_file/ModuleComponentTemplateItem/portal_components/module.erp5.BTreeData.py
...ntTemplateItem/portal_components/module.erp5.BTreeData.py
+11
-9
bt5/erp5_big_file/TestTemplateItem/portal_components/test.erp5.testBigFile.py
...stTemplateItem/portal_components/test.erp5.testBigFile.py
+105
-106
No files found.
bt5/erp5_big_file/DocumentTemplateItem/portal_components/document.erp5.BigFile.py
View file @
82c36966
...
@@ -23,14 +23,17 @@ from erp5.component.module.BTreeData import BTreeData
...
@@ -23,14 +23,17 @@ from erp5.component.module.BTreeData import BTreeData
from
ZPublisher.HTTPRequest
import
FileUpload
from
ZPublisher.HTTPRequest
import
FileUpload
from
ZPublisher
import
HTTPRangeSupport
from
ZPublisher
import
HTTPRangeSupport
from
zope.datetime
import
rfc1123_date
from
zope.datetime
import
rfc1123_date
from
mimetools
import
choose_boundary
from
Products.CMFCore.utils
import
_setCacheHeaders
,
_ViewEmulator
from
Products.CMFCore.utils
import
_setCacheHeaders
,
_ViewEmulator
from
DateTime
import
DateTime
from
DateTime
import
DateTime
import
re
import
re
import
io
import
six
import
six
if
six
.
PY3
:
if
six
.
PY3
:
long
=
int
# pylint:disable=redefined-builtin
long
=
int
# pylint:disable=redefined-builtin
from
email.generator
import
_make_boundary
as
choose_boundary
else
:
from
mimetools
import
choose_boundary
class
BigFile
(
File
):
class
BigFile
(
File
):
"""
"""
...
@@ -43,10 +46,10 @@ class BigFile(File):
...
@@ -43,10 +46,10 @@ class BigFile(File):
data property is either
data property is either
- BTreeData instance, or
- BTreeData instance, or
-
str
(*), or
-
bytes
(*), or
- None.
- None.
(*)
str has to be supported because
'' is a default value for `data` field
(*)
bytes has to be supported because b
'' is a default value for `data` field
from Data property sheet.
from Data property sheet.
Even more - for
Even more - for
...
@@ -55,7 +58,7 @@ class BigFile(File):
...
@@ -55,7 +58,7 @@ class BigFile(File):
b) desire to support automatic migration of File-based documents
b) desire to support automatic migration of File-based documents
from document_module to BigFiles
from document_module to BigFiles
non-empty
str
for data also have to be supported.
non-empty
bytes
for data also have to be supported.
XXX(kirr) I'm not sure supporting non-empty str is a good idea (it
XXX(kirr) I'm not sure supporting non-empty str is a good idea (it
would be simpler if .data could be either BTreeData or "empty"),
would be simpler if .data could be either BTreeData or "empty"),
...
@@ -64,6 +67,8 @@ class BigFile(File):
...
@@ -64,6 +67,8 @@ class BigFile(File):
We discussed with Romain and settled on "None or str or BTreeData"
We discussed with Romain and settled on "None or str or BTreeData"
invariant for now.
invariant for now.
notes: for python3 port "str" becomes "bytes", but kirr message was not modified.
"""
"""
meta_type
=
'ERP5 Big File'
meta_type
=
'ERP5 Big File'
...
@@ -115,9 +120,9 @@ class BigFile(File):
...
@@ -115,9 +120,9 @@ class BigFile(File):
# of memory.
# of memory.
n
=
1
<<
16
n
=
1
<<
16
if
isinstance
(
file
,
str
):
if
isinstance
(
file
,
bytes
):
# Big string: cut it into smaller chunks
# Big string: cut it into smaller chunks
file
=
String
IO
(
file
)
file
=
io
.
Bytes
IO
(
file
)
if
isinstance
(
file
,
FileUpload
)
and
not
file
:
if
isinstance
(
file
,
FileUpload
)
and
not
file
:
raise
ValueError
(
'File not specified'
)
raise
ValueError
(
'File not specified'
)
...
@@ -130,9 +135,9 @@ class BigFile(File):
...
@@ -130,9 +135,9 @@ class BigFile(File):
if
data
is
None
:
if
data
is
None
:
btree
=
BTreeData
()
btree
=
BTreeData
()
elif
isinstance
(
data
,
str
):
elif
isinstance
(
data
,
bytes
):
# we'll want to append content to this file -
# we'll want to append content to this file -
# - automatically convert
str
(empty or not) to BTreeData
# - automatically convert
bytes
(empty or not) to BTreeData
btree
=
BTreeData
()
btree
=
BTreeData
()
btree
.
write
(
data
,
0
)
btree
.
write
(
data
,
0
)
else
:
else
:
...
@@ -236,7 +241,7 @@ class BigFile(File):
...
@@ -236,7 +241,7 @@ class BigFile(File):
RESPONSE
.
setStatus
(
206
)
# Partial content
RESPONSE
.
setStatus
(
206
)
# Partial content
# NOTE data cannot be None here (if it is - ranges are not satisfiable)
# NOTE data cannot be None here (if it is - ranges are not satisfiable)
if
isinstance
(
data
,
str
):
if
isinstance
(
data
,
bytes
):
RESPONSE
.
write
(
data
[
start
:
end
])
RESPONSE
.
write
(
data
[
start
:
end
])
return
True
return
True
for
chunk
in
data
.
iterate
(
start
,
end
-
start
):
for
chunk
in
data
.
iterate
(
start
,
end
-
start
):
...
@@ -271,22 +276,22 @@ class BigFile(File):
...
@@ -271,22 +276,22 @@ class BigFile(File):
RESPONSE
.
setStatus
(
206
)
# Partial content
RESPONSE
.
setStatus
(
206
)
# Partial content
for
start
,
end
in
ranges
:
for
start
,
end
in
ranges
:
RESPONSE
.
write
(
'
\
r
\
n
--%s
\
r
\
n
'
%
boundary
)
RESPONSE
.
write
(
(
'
\
r
\
n
--%s
\
r
\
n
'
%
boundary
).
encode
()
)
RESPONSE
.
write
(
'Content-Type: %s
\
r
\
n
'
%
RESPONSE
.
write
(
(
'Content-Type: %s
\
r
\
n
'
%
self
.
content_type
)
self
.
content_type
)
.
encode
())
RESPONSE
.
write
(
RESPONSE
.
write
(
'Content-Range: bytes %d-%d/%d
\
r
\
n
\
r
\
n
'
%
(
(
'Content-Range: bytes %d-%d/%d
\
r
\
n
\
r
\
n
'
%
(
start
,
end
-
1
,
self
.
getSize
()))
start
,
end
-
1
,
self
.
getSize
()))
.
encode
())
# NOTE data cannot be None here (if it is - ranges are not satisfiable)
# NOTE data cannot be None here (if it is - ranges are not satisfiable)
if
isinstance
(
data
,
str
):
if
isinstance
(
data
,
bytes
):
RESPONSE
.
write
(
data
[
start
:
end
])
RESPONSE
.
write
(
data
[
start
:
end
])
else
:
else
:
for
chunk
in
data
.
iterate
(
start
,
end
-
start
):
for
chunk
in
data
.
iterate
(
start
,
end
-
start
):
RESPONSE
.
write
(
chunk
)
RESPONSE
.
write
(
chunk
)
RESPONSE
.
write
(
'
\
r
\
n
--%s--
\
r
\
n
'
%
boundary
)
RESPONSE
.
write
(
(
'
\
r
\
n
--%s--
\
r
\
n
'
%
boundary
).
encode
()
)
return
True
return
True
security
.
declareProtected
(
Permissions
.
View
,
'index_html'
)
security
.
declareProtected
(
Permissions
.
View
,
'index_html'
)
...
@@ -296,7 +301,7 @@ class BigFile(File):
...
@@ -296,7 +301,7 @@ class BigFile(File):
"""
"""
if
self
.
_range_request_handler
(
REQUEST
,
RESPONSE
):
if
self
.
_range_request_handler
(
REQUEST
,
RESPONSE
):
# we served a chunk of content in response to a range request.
# we served a chunk of content in response to a range request.
return
''
return
b
''
web_cache_kw
=
kw
.
copy
()
web_cache_kw
=
kw
.
copy
()
if
format
is
not
_MARKER
:
if
format
is
not
_MARKER
:
...
@@ -327,13 +332,13 @@ class BigFile(File):
...
@@ -327,13 +332,13 @@ class BigFile(File):
if
data
is
None
:
if
data
is
None
:
return
''
return
b
''
if
isinstance
(
data
,
str
):
if
isinstance
(
data
,
bytes
):
RESPONSE
.
setBase
(
None
)
RESPONSE
.
setBase
(
None
)
return
data
return
data
for
chunk
in
data
.
iterate
():
for
chunk
in
data
.
iterate
():
RESPONSE
.
write
(
chunk
)
RESPONSE
.
write
(
chunk
)
return
''
return
b
''
security
.
declareProtected
(
Permissions
.
ModifyPortalContent
,
'PUT'
)
security
.
declareProtected
(
Permissions
.
ModifyPortalContent
,
'PUT'
)
def
PUT
(
self
,
REQUEST
,
RESPONSE
):
def
PUT
(
self
,
REQUEST
,
RESPONSE
):
...
...
bt5/erp5_big_file/ModuleComponentTemplateItem/portal_components/module.erp5.BTreeData.py
View file @
82c36966
...
@@ -3,6 +3,7 @@ from BTrees.LOBTree import LOBTree
...
@@ -3,6 +3,7 @@ from BTrees.LOBTree import LOBTree
from
persistent
import
Persistent
from
persistent
import
Persistent
import
itertools
import
itertools
from
six.moves
import
range
from
six.moves
import
range
import
six
# Maximum memory to allocate for sparse-induced padding.
# Maximum memory to allocate for sparse-induced padding.
MAX_PADDING_CHUNK
=
2
**
20
MAX_PADDING_CHUNK
=
2
**
20
...
@@ -11,11 +12,13 @@ class PersistentString(Persistent):
...
@@ -11,11 +12,13 @@ class PersistentString(Persistent):
def
__init__
(
self
,
value
):
def
__init__
(
self
,
value
):
self
.
value
=
value
self
.
value
=
value
def
__
str
__
(
self
):
def
__
bytes
__
(
self
):
return
self
.
value
return
self
.
value
if
six
.
PY2
:
__str__
=
__bytes__
# Save place when storing this data in zodb
# Save place when storing this data in zodb
__getstate__
=
__
str
__
__getstate__
=
__
bytes
__
__setstate__
=
__init__
__setstate__
=
__init__
negative_offset_error
=
ValueError
(
'Negative offset'
)
negative_offset_error
=
ValueError
(
'Negative offset'
)
...
@@ -110,7 +113,7 @@ class BTreeData(Persistent):
...
@@ -110,7 +113,7 @@ class BTreeData(Persistent):
chunk
=
tree
[
lower_key
]
chunk
=
tree
[
lower_key
]
chunk_end
=
lower_key
+
len
(
chunk
.
value
)
chunk_end
=
lower_key
+
len
(
chunk
.
value
)
if
chunk_end
>
offset
or
(
if
chunk_end
>
offset
or
(
len
(
chunk
.
value
)
<
self
.
_chunk_size
and
len
(
chunk
.
value
)
<
(
self
.
_chunk_size
or
0
)
and
chunk_end
==
offset
chunk_end
==
offset
):
):
key
=
lower_key
key
=
lower_key
...
@@ -137,7 +140,7 @@ class BTreeData(Persistent):
...
@@ -137,7 +140,7 @@ class BTreeData(Persistent):
try
:
try
:
chunk
=
tree
[
key
]
chunk
=
tree
[
key
]
except
KeyError
:
except
KeyError
:
tree
[
key
]
=
chunk
=
PersistentString
(
''
)
tree
[
key
]
=
chunk
=
PersistentString
(
b
''
)
entry_size
=
len
(
chunk
.
value
)
entry_size
=
len
(
chunk
.
value
)
if
entry_size
<
to_write_len
:
if
entry_size
<
to_write_len
:
to_write_len
=
min
(
to_write_len
,
max_to_write_len
)
to_write_len
=
min
(
to_write_len
,
max_to_write_len
)
...
@@ -158,9 +161,9 @@ class BTreeData(Persistent):
...
@@ -158,9 +161,9 @@ class BTreeData(Persistent):
size (int)
size (int)
Number of bytes to read.
Number of bytes to read.
Returns
string
of read data.
Returns
bytes
of read data.
"""
"""
return
''
.
join
(
self
.
iterate
(
offset
,
size
))
return
b
''
.
join
(
self
.
iterate
(
offset
,
size
))
def
iterate
(
self
,
offset
=
0
,
size
=
None
):
def
iterate
(
self
,
offset
=
0
,
size
=
None
):
"""
"""
...
@@ -243,7 +246,7 @@ class BTreeData(Persistent):
...
@@ -243,7 +246,7 @@ class BTreeData(Persistent):
except
ValueError
:
except
ValueError
:
break
break
del
tree
[
key
]
del
tree
[
key
]
self
.
write
(
''
,
offset
)
self
.
write
(
b
''
,
offset
)
# XXX: Various batch_size values need to be benchmarked, and a saner
# XXX: Various batch_size values need to be benchmarked, and a saner
# default is likely to be applied.
# default is likely to be applied.
...
@@ -314,12 +317,11 @@ class BTreeData(Persistent):
...
@@ -314,12 +317,11 @@ class BTreeData(Persistent):
tree
[
key
]
=
next_chunk
tree
[
key
]
=
next_chunk
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
def
check
(
tree
,
length
,
read_offset
,
read_length
,
data_
,
keys
=
None
):
def
check
(
tree
,
length
,
read_offset
,
read_length
,
data_
,
keys
=
None
):
print
(
list
(
tree
.
_tree
.
items
()))
print
(
list
(
tree
.
_tree
.
items
()))
tree_length
=
len
(
tree
)
tree_length
=
len
(
tree
)
tree_data
=
tree
.
read
(
read_offset
,
read_length
)
tree_data
=
tree
.
read
(
read_offset
,
read_length
)
tree_iterator_data
=
''
.
join
(
tree
.
iterate
(
read_offset
,
read_length
))
tree_iterator_data
=
b
''
.
join
(
tree
.
iterate
(
read_offset
,
read_length
))
assert
tree_length
==
length
,
tree_length
assert
tree_length
==
length
,
tree_length
assert
tree_data
==
data_
,
repr
(
tree_data
)
assert
tree_data
==
data_
,
repr
(
tree_data
)
assert
tree_iterator_data
==
data_
,
repr
(
tree_iterator_data
)
assert
tree_iterator_data
==
data_
,
repr
(
tree_iterator_data
)
...
...
bt5/erp5_big_file/TestTemplateItem/portal_components/test.erp5.testBigFile.py
View file @
82c36966
...
@@ -24,8 +24,7 @@
...
@@ -24,8 +24,7 @@
# along with this program; if not, write to the Free Software
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from
six.moves
import
cStringIO
as
StringIO
import
io
from
ZPublisher.HTTPRequest
import
HTTPRequest
from
ZPublisher.HTTPRequest
import
HTTPRequest
from
ZPublisher.HTTPResponse
import
HTTPResponse
from
ZPublisher.HTTPResponse
import
HTTPResponse
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
...
@@ -35,15 +34,15 @@ from erp5.component.module.BTreeData import BTreeData
...
@@ -35,15 +34,15 @@ from erp5.component.module.BTreeData import BTreeData
# like Testing.makerequest, but
# like Testing.makerequest, but
#
#
# 1. always redirects stdout to
stringio
,
# 1. always redirects stdout to
BytesIO
,
# 2. stdin content can be specified and is processed,
# 2. stdin content can be specified and is processed,
# 3. returns actual request object (not wrapped portal).
# 3. returns actual request object (not wrapped portal).
#
#
# see also: Products.CMFCore.tests.test_CookieCrumbler.makerequest()
# see also: Products.CMFCore.tests.test_CookieCrumbler.makerequest()
# TODO makerequest() is generic enough and deserves moving to testing utils
# TODO makerequest() is generic enough and deserves moving to testing utils
def
makerequest
(
environ
=
None
,
stdin
=
''
):
def
makerequest
(
environ
=
None
,
stdin
=
b
''
):
stdout
=
String
IO
()
stdout
=
io
.
Bytes
IO
()
stdin
=
String
IO
(
stdin
)
stdin
=
io
.
Bytes
IO
(
stdin
)
if
environ
is
None
:
if
environ
is
None
:
environ
=
{}
environ
=
{}
...
@@ -65,7 +64,7 @@ def makerequest(environ=None, stdin=''):
...
@@ -65,7 +64,7 @@ def makerequest(environ=None, stdin=''):
# generate makerequest-like function for http method
# generate makerequest-like function for http method
def
request_function
(
method_name
):
def
request_function
(
method_name
):
method_name
=
method_name
.
upper
()
method_name
=
method_name
.
upper
()
def
method_func
(
environ
=
None
,
stdin
=
''
):
def
method_func
(
environ
=
None
,
stdin
=
b
''
):
if
environ
is
None
:
if
environ
is
None
:
environ
=
{}
environ
=
{}
environ
.
setdefault
(
'REQUEST_METHOD'
,
method_name
)
environ
.
setdefault
(
'REQUEST_METHOD'
,
method_name
)
...
@@ -112,7 +111,7 @@ class TestBigFile(ERP5TypeTestCase):
...
@@ -112,7 +111,7 @@ class TestBigFile(ERP5TypeTestCase):
ret
=
method
(
request
,
request
.
RESPONSE
,
**
kw
)
ret
=
method
(
request
,
request
.
RESPONSE
,
**
kw
)
# like in ZPublisher - returned RESPONSE means empty
# like in ZPublisher - returned RESPONSE means empty
if
ret
is
request
.
RESPONSE
:
if
ret
is
request
.
RESPONSE
:
ret
=
''
ret
=
b
''
self
.
assertEqual
(
ret
,
result
)
self
.
assertEqual
(
ret
,
result
)
self
.
assertEqual
(
status
,
request
.
RESPONSE
.
getStatus
())
self
.
assertEqual
(
status
,
request
.
RESPONSE
.
getStatus
())
for
h
,
v
in
header_dict
.
items
():
for
h
,
v
in
header_dict
.
items
():
...
@@ -120,9 +119,9 @@ class TestBigFile(ERP5TypeTestCase):
...
@@ -120,9 +119,9 @@ class TestBigFile(ERP5TypeTestCase):
self
.
assertEqual
(
v
,
rv
,
'%s: %r != %r'
%
(
h
,
v
,
rv
))
self
.
assertEqual
(
v
,
rv
,
'%s: %r != %r'
%
(
h
,
v
,
rv
))
# force response flush to its stdout
# force response flush to its stdout
request
.
RESPONSE
.
write
(
''
)
request
.
RESPONSE
.
write
(
b
''
)
# body and headers are delimited by empty line (RFC 2616, 4.1)
# body and headers are delimited by empty line (RFC 2616, 4.1)
response_body
=
request
.
RESPONSE
.
stdout
.
getvalue
().
split
(
'
\
r
\
n
\
r
\
n
'
,
1
)[
1
]
response_body
=
request
.
RESPONSE
.
stdout
.
getvalue
().
split
(
b
'
\
r
\
n
\
r
\
n
'
,
1
)[
1
]
self
.
assertEqual
(
body
,
response_body
)
self
.
assertEqual
(
body
,
response_body
)
...
@@ -135,90 +134,90 @@ class TestBigFile(ERP5TypeTestCase):
...
@@ -135,90 +134,90 @@ class TestBigFile(ERP5TypeTestCase):
# after creation file is empty and get(0-0) returns 416
# after creation file is empty and get(0-0) returns 416
self
.
assertEqual
(
f
.
getSize
(),
0
)
self
.
assertEqual
(
f
.
getSize
(),
0
)
self
.
assertEqual
(
f
.
getData
(),
''
)
self
.
assertEqual
(
f
.
getData
(),
b
''
)
# result body status headers
# result body status headers
check
(
get
(),
{
'format'
:
'raw'
},
''
,
''
,
200
,
{
'Content-Length'
:
'0'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
''
,
200
,
{
'Content-Length'
:
'0'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0--1'
})
# XXX 0--1 ok?
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0--1'
})
# XXX 0--1 ok?
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
''
,
''
,
416
,
{
'Content-Length'
:
'0'
,
'Content-Range'
:
'bytes */0'
})
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
b''
,
b
''
,
416
,
{
'Content-Length'
:
'0'
,
'Content-Range'
:
'bytes */0'
})
# append empty chunk - the same
# append empty chunk - the same
f
.
_appendData
(
''
)
f
.
_appendData
(
b
''
)
self
.
assertEqual
(
f
.
getSize
(),
0
)
self
.
assertEqual
(
f
.
getSize
(),
0
)
self
.
assertEqual
(
f
.
getData
(),
''
)
self
.
assertEqual
(
f
.
getData
(),
b
''
)
check
(
get
(),
{
'format'
:
'raw'
},
''
,
''
,
200
,
{
'Content-Length'
:
'0'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
''
,
200
,
{
'Content-Length'
:
'0'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0--1'
})
# XXX 0--1 ok?
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0--1'
})
# XXX 0--1 ok?
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
''
,
''
,
416
,
{
'Content-Range'
:
'bytes */0'
})
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
b''
,
b
''
,
416
,
{
'Content-Range'
:
'bytes */0'
})
# append 1 byte - file should grow up and get(0-0) returns 206
# append 1 byte - file should grow up and get(0-0) returns 206
f
.
_appendData
(
'x'
)
f
.
_appendData
(
b
'x'
)
self
.
assertEqual
(
f
.
getSize
(),
1
)
self
.
assertEqual
(
f
.
getSize
(),
1
)
self
.
assertEqual
(
f
.
getData
(),
'x'
)
self
.
assertEqual
(
f
.
getData
(),
b
'x'
)
check
(
get
(),
{
'format'
:
'raw'
},
''
,
'x'
,
200
,
{
'Content-Length'
:
'1'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
'x'
,
200
,
{
'Content-Length'
:
'1'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0-0'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0-0'
})
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
''
,
'x'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 0-0/1'
})
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
b''
,
b
'x'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 0-0/1'
})
# append another 2 bytes and try to get whole file and partial contents
# append another 2 bytes and try to get whole file and partial contents
f
.
_appendData
(
'yz'
)
f
.
_appendData
(
b
'yz'
)
self
.
assertEqual
(
f
.
getSize
(),
3
)
self
.
assertEqual
(
f
.
getSize
(),
3
)
self
.
assertEqual
(
f
.
getData
(),
'xyz'
)
self
.
assertEqual
(
f
.
getData
(),
b
'xyz'
)
check
(
get
(),
{
'format'
:
'raw'
},
''
,
'xyz'
,
200
,
{
'Content-Length'
:
'3'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
'xyz'
,
200
,
{
'Content-Length'
:
'3'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0-2'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0-2'
})
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
''
,
'x'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 0-0/3'
})
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
b''
,
b
'x'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 0-0/3'
})
check
(
get
({
'Range'
:
'bytes=1-1'
}),{},
''
,
'y'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 1-1/3'
})
check
(
get
({
'Range'
:
'bytes=1-1'
}),{},
b''
,
b
'y'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 1-1/3'
})
check
(
get
({
'Range'
:
'bytes=2-2'
}),{},
''
,
'z'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 2-2/3'
})
check
(
get
({
'Range'
:
'bytes=2-2'
}),{},
b''
,
b
'z'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 2-2/3'
})
check
(
get
({
'Range'
:
'bytes=0-1'
}),{},
''
,
'xy'
,
206
,
{
'Content-Length'
:
'2'
,
'Content-Range'
:
'bytes 0-1/3'
})
check
(
get
({
'Range'
:
'bytes=0-1'
}),{},
b''
,
b
'xy'
,
206
,
{
'Content-Length'
:
'2'
,
'Content-Range'
:
'bytes 0-1/3'
})
check
(
get
({
'Range'
:
'bytes=1-2'
}),{},
''
,
'yz'
,
206
,
{
'Content-Length'
:
'2'
,
'Content-Range'
:
'bytes 1-2/3'
})
check
(
get
({
'Range'
:
'bytes=1-2'
}),{},
b''
,
b
'yz'
,
206
,
{
'Content-Length'
:
'2'
,
'Content-Range'
:
'bytes 1-2/3'
})
check
(
get
({
'Range'
:
'bytes=0-2'
}),{},
''
,
'xyz'
,
206
,
{
'Content-Length'
:
'3'
,
'Content-Range'
:
'bytes 0-2/3'
})
check
(
get
({
'Range'
:
'bytes=0-2'
}),{},
b''
,
b
'xyz'
,
206
,
{
'Content-Length'
:
'3'
,
'Content-Range'
:
'bytes 0-2/3'
})
# append via PUT with range
# append via PUT with range
check
(
put
({
'Content-Range'
:
'bytes 3-4/5'
,
'Content-Length'
:
'2'
},
'01'
),{},
''
,
''
,
204
,
{})
check
(
put
({
'Content-Range'
:
'bytes 3-4/5'
,
'Content-Length'
:
'2'
},
b'01'
),{},
b''
,
b
''
,
204
,
{})
self
.
assertEqual
(
f
.
getSize
(),
5
)
self
.
assertEqual
(
f
.
getSize
(),
5
)
self
.
assertEqual
(
f
.
getData
(),
'xyz01'
)
self
.
assertEqual
(
f
.
getData
(),
b
'xyz01'
)
check
(
get
(),
{
'format'
:
'raw'
},
''
,
'xyz01'
,
200
,
{
'Content-Length'
:
'5'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
'xyz01'
,
200
,
{
'Content-Length'
:
'5'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0-4'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0-4'
})
check
(
get
({
'Range'
:
'bytes=0-4'
}),{},
''
,
'xyz01'
,
206
,
{
'Content-Length'
:
'5'
,
'Content-Range'
:
'bytes 0-4/5'
})
check
(
get
({
'Range'
:
'bytes=0-4'
}),{},
b''
,
b
'xyz01'
,
206
,
{
'Content-Length'
:
'5'
,
'Content-Range'
:
'bytes 0-4/5'
})
check
(
get
({
'Range'
:
'bytes=1-3'
}),{},
''
,
'yz0'
,
206
,
{
'Content-Length'
:
'3'
,
'Content-Range'
:
'bytes 1-3/5'
})
check
(
get
({
'Range'
:
'bytes=1-3'
}),{},
b''
,
b
'yz0'
,
206
,
{
'Content-Length'
:
'3'
,
'Content-Range'
:
'bytes 1-3/5'
})
check
(
get
({
'Range'
:
'bytes=1-2'
}),{},
''
,
'yz'
,
206
,
{
'Content-Length'
:
'2'
,
'Content-Range'
:
'bytes 1-2/5'
})
check
(
get
({
'Range'
:
'bytes=1-2'
}),{},
b''
,
b
'yz'
,
206
,
{
'Content-Length'
:
'2'
,
'Content-Range'
:
'bytes 1-2/5'
})
check
(
get
({
'Range'
:
'bytes=2-2'
}),{},
''
,
'z'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 2-2/5'
})
check
(
get
({
'Range'
:
'bytes=2-2'
}),{},
b''
,
b
'z'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 2-2/5'
})
# replace whole content via PUT without range
# replace whole content via PUT without range
# (and we won't exercise GET with range routinely further)
# (and we won't exercise GET with range routinely further)
check
(
put
({
'Content-Length'
:
'3'
},
'abc'
),{},
''
,
''
,
204
,
{})
check
(
put
({
'Content-Length'
:
'3'
},
b'abc'
),{},
b''
,
b
''
,
204
,
{})
self
.
assertEqual
(
f
.
getSize
(),
3
)
self
.
assertEqual
(
f
.
getSize
(),
3
)
self
.
assertEqual
(
f
.
getData
(),
'abc'
)
self
.
assertEqual
(
f
.
getData
(),
b
'abc'
)
check
(
get
(),
{
'format'
:
'raw'
},
''
,
'abc'
,
200
,
{
'Content-Length'
:
'3'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
'abc'
,
200
,
{
'Content-Length'
:
'3'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0-2'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0-2'
})
# append via PUT with range (again)
# append via PUT with range (again)
check
(
put
({
'Content-Range'
:
'bytes 3-7/8'
,
'Content-Length'
:
'5'
},
'defgh'
),{},
''
,
''
,
204
,
{})
check
(
put
({
'Content-Range'
:
'bytes 3-7/8'
,
'Content-Length'
:
'5'
},
b'defgh'
),{},
b''
,
b
''
,
204
,
{})
self
.
assertEqual
(
f
.
getSize
(),
8
)
self
.
assertEqual
(
f
.
getSize
(),
8
)
self
.
assertEqual
(
f
.
getData
(),
'abcdefgh'
)
self
.
assertEqual
(
f
.
getData
(),
b
'abcdefgh'
)
check
(
get
(),
{
'format'
:
'raw'
},
''
,
'abcdefgh'
,
200
,
{
'Content-Length'
:
'8'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
'abcdefgh'
,
200
,
{
'Content-Length'
:
'8'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0-7'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0-7'
})
# append via ._appendData() (again)
# append via ._appendData() (again)
f
.
_appendData
(
'ij'
)
f
.
_appendData
(
b
'ij'
)
self
.
assertEqual
(
f
.
getSize
(),
10
)
self
.
assertEqual
(
f
.
getSize
(),
10
)
self
.
assertEqual
(
f
.
getData
(),
'abcdefghij'
)
self
.
assertEqual
(
f
.
getData
(),
b
'abcdefghij'
)
check
(
get
(),
{
'format'
:
'raw'
},
''
,
'abcdefghij'
,
200
,
{
'Content-Length'
:
'10'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
'abcdefghij'
,
200
,
{
'Content-Length'
:
'10'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0-9'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0-9'
})
# make sure PUT with incorrect/non-append range is rejected
# make sure PUT with incorrect/non-append range is rejected
check
(
put
({
'Content-Range'
:
'bytes 10-10/10'
,
'Content-Length'
:
'1'
},
'k'
),{},
''
,
''
,
400
,
{
'X-Explanation'
:
'Total size unexpected'
})
check
(
put
({
'Content-Range'
:
'bytes 10-10/10'
,
'Content-Length'
:
'1'
},
b'k'
),{},
b''
,
b
''
,
400
,
{
'X-Explanation'
:
'Total size unexpected'
})
self
.
assertEqual
(
f
.
getData
(),
'abcdefghij'
)
self
.
assertEqual
(
f
.
getData
(),
b
'abcdefghij'
)
check
(
put
({
'Content-Range'
:
'bytes 10-10/11'
,
'Content-Length'
:
'2'
},
'k'
),{},
''
,
''
,
400
,
{
'X-Explanation'
:
'Content length unexpected'
})
check
(
put
({
'Content-Range'
:
'bytes 10-10/11'
,
'Content-Length'
:
'2'
},
b'k'
),{},
b''
,
b
''
,
400
,
{
'X-Explanation'
:
'Content length unexpected'
})
self
.
assertEqual
(
f
.
getData
(),
'abcdefghij'
)
self
.
assertEqual
(
f
.
getData
(),
b
'abcdefghij'
)
check
(
put
({
'Content-Range'
:
'bytes 8-8/10'
,
'Content-Length'
:
'1'
},
'?'
),{},
''
,
''
,
400
,
{
'X-Explanation'
:
'Can only append data'
})
check
(
put
({
'Content-Range'
:
'bytes 8-8/10'
,
'Content-Length'
:
'1'
},
b'?'
),{},
b''
,
b
''
,
400
,
{
'X-Explanation'
:
'Can only append data'
})
check
(
put
({
'Content-Range'
:
'bytes 9-9/10'
,
'Content-Length'
:
'1'
},
'?'
),{},
''
,
''
,
400
,
{
'X-Explanation'
:
'Can only append data'
})
check
(
put
({
'Content-Range'
:
'bytes 9-9/10'
,
'Content-Length'
:
'1'
},
b'?'
),{},
b''
,
b
''
,
400
,
{
'X-Explanation'
:
'Can only append data'
})
check
(
put
({
'Content-Range'
:
'bytes 9-10/11'
,
'Content-Length'
:
'2'
},
'??'
),{},
''
,
''
,
400
,
{
'X-Explanation'
:
'Can only append data'
})
check
(
put
({
'Content-Range'
:
'bytes 9-10/11'
,
'Content-Length'
:
'2'
},
b'??'
),{},
b''
,
b
''
,
400
,
{
'X-Explanation'
:
'Can only append data'
})
check
(
put
({
'Content-Range'
:
'bytes 11-11/12'
,
'Content-Length'
:
'1'
},
'?'
),{},
''
,
''
,
400
,
{
'X-Explanation'
:
'Can only append data'
})
check
(
put
({
'Content-Range'
:
'bytes 11-11/12'
,
'Content-Length'
:
'1'
},
b'?'
),{},
b''
,
b
''
,
400
,
{
'X-Explanation'
:
'Can only append data'
})
# TODO test 'If-Range' with GET
# TODO test 'If-Range' with GET
# TODO test multiple ranges in 'Range' with GET
# TODO test multiple ranges in 'Range' with GET
...
@@ -229,11 +228,11 @@ class TestBigFile(ERP5TypeTestCase):
...
@@ -229,11 +228,11 @@ class TestBigFile(ERP5TypeTestCase):
# (called from under testBigFile_02_DataVarious driver)
# (called from under testBigFile_02_DataVarious driver)
def
_testBigFile_02_DataVarious
(
self
):
def
_testBigFile_02_DataVarious
(
self
):
# BigFile's .data can be:
# BigFile's .data can be:
#
str - because data comes from Data property sheet and default value is
''
#
bytes - because data comes from Data property sheet and default value is b
''
# None - because it can be changed
# None - because it can be changed
# BTreeData - because it is scalable way to work with large content
# BTreeData - because it is scalable way to work with large content
#
#
#
str
can be possibly non-empty because we could want to transparently
#
bytes
can be possibly non-empty because we could want to transparently
# migrate plain File documents to BigFiles.
# migrate plain File documents to BigFiles.
#
#
# make sure BigFile correctly works in all those situations.
# make sure BigFile correctly works in all those situations.
...
@@ -242,47 +241,47 @@ class TestBigFile(ERP5TypeTestCase):
...
@@ -242,47 +241,47 @@ class TestBigFile(ERP5TypeTestCase):
f
=
big_file_module
.
newContent
(
portal_type
=
'Big File'
)
f
=
big_file_module
.
newContent
(
portal_type
=
'Big File'
)
check
=
lambda
*
args
:
self
.
checkRequest
(
f
,
*
args
)
check
=
lambda
*
args
:
self
.
checkRequest
(
f
,
*
args
)
# after creation .data is '' (as per default from Data property sheet)
# after creation .data is
b
'' (as per default from Data property sheet)
_
=
f
.
_baseGetData
()
_
=
f
.
_baseGetData
()
self
.
assertIsInstance
(
_
,
str
)
self
.
assertIsInstance
(
_
,
bytes
)
self
.
assertEqual
(
_
,
''
)
self
.
assertEqual
(
_
,
b
''
)
# make sure we can get empty content through all ways
# make sure we can get empty content through all ways
# (already covered in testBigFile_01_Basic, but still)
# (already covered in testBigFile_01_Basic, but still)
self
.
assertEqual
(
f
.
getSize
(),
0
)
self
.
assertEqual
(
f
.
getSize
(),
0
)
self
.
assertEqual
(
f
.
getData
(),
''
)
self
.
assertEqual
(
f
.
getData
(),
b
''
)
check
(
get
(),
{
'format'
:
'raw'
},
''
,
''
,
200
,
{
'Content-Length'
:
'0'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
''
,
200
,
{
'Content-Length'
:
'0'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0--1'
})
# XXX 0--1 ok?
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0--1'
})
# XXX 0--1 ok?
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
''
,
''
,
416
,
{
'Content-Length'
:
'0'
,
'Content-Range'
:
'bytes */0'
})
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
b''
,
b
''
,
416
,
{
'Content-Length'
:
'0'
,
'Content-Range'
:
'bytes */0'
})
# set .data to non-empty str and make sure we can get content through all ways
# set .data to non-empty str and make sure we can get content through all ways
f
.
_baseSetData
(
'abc'
)
f
.
_baseSetData
(
b
'abc'
)
_
=
f
.
_baseGetData
()
_
=
f
.
_baseGetData
()
self
.
assertIsInstance
(
_
,
str
)
self
.
assertIsInstance
(
_
,
bytes
)
self
.
assertEqual
(
_
,
'abc'
)
self
.
assertEqual
(
_
,
b
'abc'
)
self
.
assertEqual
(
f
.
getSize
(),
3
)
self
.
assertEqual
(
f
.
getSize
(),
3
)
self
.
assertEqual
(
f
.
getData
(),
'abc'
)
self
.
assertEqual
(
f
.
getData
(),
b
'abc'
)
check
(
get
(),
{
'format'
:
'raw'
},
'abc'
,
''
,
200
,
{
'Content-Length'
:
'3'
})
check
(
get
(),
{
'format'
:
'raw'
},
b'abc'
,
b
''
,
200
,
{
'Content-Length'
:
'3'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0-2'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0-2'
})
check
(
get
({
'Range'
:
'bytes=0-2'
}),{},
''
,
'abc'
,
206
,
{
'Content-Length'
:
'3'
,
'Content-Range'
:
'bytes 0-2/3'
})
check
(
get
({
'Range'
:
'bytes=0-2'
}),{},
b''
,
b
'abc'
,
206
,
{
'Content-Length'
:
'3'
,
'Content-Range'
:
'bytes 0-2/3'
})
# and .data should remain str after access (though later this could be
# and .data should remain str after access (though later this could be
# changed to transparently migrate to BTreeData)
# changed to transparently migrate to BTreeData)
_
=
f
.
_baseGetData
()
_
=
f
.
_baseGetData
()
self
.
assertIsInstance
(
_
,
str
)
self
.
assertIsInstance
(
_
,
bytes
)
self
.
assertEqual
(
_
,
'abc'
)
self
.
assertEqual
(
_
,
b
'abc'
)
# on append .data should migrate to BTreeData
# on append .data should migrate to BTreeData
f
.
_appendData
(
'd'
)
f
.
_appendData
(
b
'd'
)
_
=
f
.
_baseGetData
()
_
=
f
.
_baseGetData
()
self
.
assertIsInstance
(
_
,
BTreeData
)
self
.
assertIsInstance
(
_
,
BTreeData
)
self
.
assertEqual
(
f
.
getSize
(),
4
)
self
.
assertEqual
(
f
.
getSize
(),
4
)
self
.
assertEqual
(
f
.
getData
(),
'abcd'
)
self
.
assertEqual
(
f
.
getData
(),
b
'abcd'
)
check
(
get
(),
{
'format'
:
'raw'
},
''
,
'abcd'
,
200
,
{
'Content-Length'
:
'4'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
'abcd'
,
200
,
{
'Content-Length'
:
'4'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0-3'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0-3'
})
check
(
get
({
'Range'
:
'bytes=0-3'
}),{},
''
,
'abcd'
,
206
,
{
'Content-Length'
:
'4'
,
'Content-Range'
:
'bytes 0-3/4'
})
check
(
get
({
'Range'
:
'bytes=0-3'
}),{},
b''
,
b
'abcd'
,
206
,
{
'Content-Length'
:
'4'
,
'Content-Range'
:
'bytes 0-3/4'
})
...
@@ -292,39 +291,39 @@ class TestBigFile(ERP5TypeTestCase):
...
@@ -292,39 +291,39 @@ class TestBigFile(ERP5TypeTestCase):
#
#
# see ERP5.Document.File._setSize() for details.
# see ERP5.Document.File._setSize() for details.
f
.
_setData
(
None
)
f
.
_setData
(
None
)
# NOTE still '' because it is default value specified in Data property
# NOTE still
b
'' because it is default value specified in Data property
# sheet for .data field
# sheet for .data field
_
=
f
.
_baseGetData
()
_
=
f
.
_baseGetData
()
self
.
assertIsInstance
(
_
,
str
)
self
.
assertIsInstance
(
_
,
bytes
)
self
.
assertEqual
(
_
,
''
)
self
.
assertEqual
(
_
,
b
''
)
# but we can change property sheet default on the fly
# but we can change property sheet default on the fly
# XXX ( only for this particular getter _baseGetData -
# XXX ( only for this particular getter _baseGetData -
# - because property type information is not stored in one place,
# - because property type information is not stored in one place,
# but is copied on getter/setter initialization - see Getter/Setter
# but is copied on getter/setter initialization - see Getter/Setter
# in ERP5Type.Accessor.Base )
# in ERP5Type.Accessor.Base )
# NOTE this change is automatically reverted back in calling helper
# NOTE this change is automatically reverted back in calling helper
self
.
assertIsInstance
(
f
.
_baseGetData
.
_default
,
str
)
self
.
assertIsInstance
(
f
.
_baseGetData
.
_default
,
bytes
)
self
.
assertEqual
(
f
.
_baseGetData
.
_default
,
''
)
self
.
assertEqual
(
f
.
_baseGetData
.
_default
,
b
''
)
f
.
_baseGetData
.
__func__
.
_default
=
None
# NOTE not possible to do on just f._baseGetData
f
.
_baseGetData
.
__func__
.
_default
=
None
# NOTE not possible to do on just f._baseGetData
self
.
assertIs
(
f
.
_baseGetData
.
_default
,
None
)
self
.
assertIs
(
f
.
_baseGetData
.
_default
,
None
)
self
.
assertIs
(
f
.
_baseGetData
(),
None
)
# <- oops
self
.
assertIs
(
f
.
_baseGetData
(),
None
)
# <- oops
self
.
assertEqual
(
f
.
getSize
(),
0
)
self
.
assertEqual
(
f
.
getSize
(),
0
)
self
.
assertIs
(
f
.
getData
(),
None
)
self
.
assertIs
(
f
.
getData
(),
None
)
check
(
get
(),
{
'format'
:
'raw'
},
''
,
''
,
200
,
{
'Content-Length'
:
'0'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
''
,
200
,
{
'Content-Length'
:
'0'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0--1'
})
# XXX 0--1 ok?
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0--1'
})
# XXX 0--1 ok?
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
''
,
''
,
416
,
{
'Content-Length'
:
'0'
,
'Content-Range'
:
'bytes */0'
})
check
(
get
({
'Range'
:
'bytes=0-0'
}),{},
b''
,
b
''
,
416
,
{
'Content-Length'
:
'0'
,
'Content-Range'
:
'bytes */0'
})
# on append .data should become BTreeData
# on append .data should become BTreeData
f
.
_appendData
(
'x'
)
f
.
_appendData
(
b
'x'
)
_
=
f
.
_baseGetData
()
_
=
f
.
_baseGetData
()
self
.
assertIsInstance
(
_
,
BTreeData
)
self
.
assertIsInstance
(
_
,
BTreeData
)
self
.
assertEqual
(
f
.
getSize
(),
1
)
self
.
assertEqual
(
f
.
getSize
(),
1
)
self
.
assertEqual
(
f
.
getData
(),
'x'
)
self
.
assertEqual
(
f
.
getData
(),
b
'x'
)
check
(
get
(),
{
'format'
:
'raw'
},
''
,
'x'
,
200
,
{
'Content-Length'
:
'1'
})
check
(
get
(),
{
'format'
:
'raw'
},
b''
,
b
'x'
,
200
,
{
'Content-Length'
:
'1'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
''
,
''
,
R308
,
{
'Range'
:
'bytes 0-0'
})
check
(
put
({
'Content-Range'
:
'bytes */*'
}),{},
b''
,
b
''
,
R308
,
{
'Range'
:
'bytes 0-0'
})
check
(
get
({
'Range'
:
'bytes=0-3'
}),{},
''
,
'x'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 0-0/1'
})
check
(
get
({
'Range'
:
'bytes=0-3'
}),{},
b''
,
b
'x'
,
206
,
{
'Content-Length'
:
'1'
,
'Content-Range'
:
'bytes 0-0/1'
})
...
@@ -333,26 +332,26 @@ class TestBigFile(ERP5TypeTestCase):
...
@@ -333,26 +332,26 @@ class TestBigFile(ERP5TypeTestCase):
big_file_module
=
self
.
getPortal
().
big_file_module
big_file_module
=
self
.
getPortal
().
big_file_module
f
=
big_file_module
.
newContent
(
portal_type
=
'Big File'
)
f
=
big_file_module
.
newContent
(
portal_type
=
'Big File'
)
# Data property sheet specifies .data default to ''
# Data property sheet specifies .data default to
b
''
_
=
f
.
_baseGetData
()
_
=
f
.
_baseGetData
()
self
.
assertIsInstance
(
_
,
str
)
self
.
assertIsInstance
(
_
,
bytes
)
self
.
assertEqual
(
_
,
''
)
self
.
assertEqual
(
_
,
b
''
)
# NOTE obtaining getter is not possible via BigFile._baseGetData
# NOTE obtaining getter is not possible via BigFile._baseGetData
g
=
f
.
_baseGetData
.
__func__
g
=
f
.
_baseGetData
.
__func__
self
.
assertIsInstance
(
g
.
_default
,
str
)
self
.
assertIsInstance
(
g
.
_default
,
bytes
)
self
.
assertEqual
(
g
.
_default
,
''
)
self
.
assertEqual
(
g
.
_default
,
b
''
)
try
:
try
:
self
.
_testBigFile_02_DataVarious
()
self
.
_testBigFile_02_DataVarious
()
# restore ._baseGetData._default and make sure restoration really worked
# restore ._baseGetData._default and make sure restoration really worked
finally
:
finally
:
g
.
_default
=
''
g
.
_default
=
b
''
f
.
_baseSetData
(
None
)
# so that we are sure getter returns class defaults
f
.
_baseSetData
(
None
)
# so that we are sure getter returns class defaults
_
=
f
.
_baseGetData
()
_
=
f
.
_baseGetData
()
self
.
assertIsInstance
(
_
,
str
)
self
.
assertIsInstance
(
_
,
bytes
)
self
.
assertEqual
(
_
,
''
)
self
.
assertEqual
(
_
,
b
''
)
...
...
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