3838 _SEEK_END = 2
3939
4040
41+ """Default chunk size, in bytes."""
42+ DEFAULT_CHUNK_SIZE = 256 * 1024
43+
44+
4145def _create_property (field_name , docstring ,
4246 read_only = False , closed_only = False ):
4347 """Helper for creating properties to read/write to files.
4448 """
4549 def getter (self ):
46- if closed_only and not self .__closed :
50+ if closed_only and not self ._closed :
4751 raise AttributeError ("can only get %r on a closed file" %
4852 field_name )
49- return self .__file .get (field_name , None )
53+ return self ._file .get (field_name , None )
5054 def setter (self , value ):
51- if self .__closed :
55+ if self ._closed :
5256 raise AttributeError ("cannot set %r on a closed file" %
5357 field_name )
54- self .__file [field_name ] = value
58+ self ._file [field_name ] = value
5559
5660 if read_only :
5761 docstring = docstring + "\n \n This attribute is read-only." ""
@@ -107,32 +111,40 @@ def __init__(self, root_collection, **kwargs):
107111 if not isinstance (root_collection , Collection ):
108112 raise TypeError ("root_collection must be an instance of Collection" )
109113
110- # Convert from kwargs to a file document
114+ # Handle alternative naming
111115 if "content_type" in kwargs :
112116 kwargs ["contentType" ] = kwargs .pop ("content_type" )
113117 if "chunk_size" in kwargs :
114118 kwargs ["chunkSize" ] = kwargs .pop ("chunk_size" )
119+
120+ # Move bonus kwargs into metadata
121+ to_move = []
115122 for key in kwargs :
116123 if key not in ["_id" , "filename" , "contentType" ,
117124 "chunkSize" , "aliases" , "metadata" ]:
118- kwargs ["metadata" ] = kwargs .get ("metadata" , {})
125+ to_move .append (key )
126+ if to_move :
127+ kwargs ["metadata" ] = kwargs .get ("metadata" , {})
128+ for key in to_move :
119129 kwargs ["metadata" ][key ] = kwargs .pop (key )
120- if "_id" not in kwargs :
121- kwargs ["_id" ] = ObjectId ()
130+
131+ # Defaults
132+ kwargs ["_id" ] = kwargs .get ("_id" , ObjectId ())
133+ kwargs ["chunkSize" ] = kwargs .get ("chunkSize" , DEFAULT_CHUNK_SIZE )
122134
123135 self .__coll = root_collection
124136 self .__chunks = root_collection .chunks
125- self .__file = kwargs
137+ self ._file = kwargs
126138 self .__buffer = StringIO ()
127139 self .__position = 0
128140 self .__chunk_number = 0
129- self .__closed = False
141+ self ._closed = False
130142
131143 @property
132144 def closed (self ):
133145 """Is this file closed?
134146 """
135- return self .__closed
147+ return self ._closed
136148
137149 _id = _create_property ("_id" , "The ``'_id'`` value for this file." ,
138150 read_only = True )
@@ -158,7 +170,7 @@ def __flush_data(self, data):
158170 return
159171 assert (len (data ) <= self .chunk_size )
160172
161- chunk = {"files_id" : self .__file ["_id" ],
173+ chunk = {"files_id" : self ._file ["_id" ],
162174 "n" : self .__chunk_number ,
163175 "data" : Binary (data )}
164176
@@ -181,20 +193,20 @@ def __flush(self):
181193 md5 = self .__coll .database .command ("filemd5" , self ._id ,
182194 root = self .__coll .name )["md5" ]
183195
184- self .__file ["md5" ] = md5
185- self .__file ["length" ] = self .__position
186- self .__file ["uploadDate" ] = datetime .datetime .utcnow ()
187- return self .__coll .files .insert (self .__file )
196+ self ._file ["md5" ] = md5
197+ self ._file ["length" ] = self .__position
198+ self ._file ["uploadDate" ] = datetime .datetime .utcnow ()
199+ return self .__coll .files .insert (self ._file )
188200
189201 def close (self ):
190202 """Flush the file and close it.
191203
192204 A closed file cannot be written any more. Calling
193205 :meth:`close` more than once is allowed.
194206 """
195- if not self .__closed :
207+ if not self ._closed :
196208 self .__flush ()
197- self .__closed = True
209+ self ._closed = True
198210
199211 # TODO should support writing unicode to a file. this means that files will
200212 # need to have an encoding attribute.
@@ -210,7 +222,7 @@ def write(self, data):
210222 :Parameters:
211223 - `data`: string of bytes to be written to the file
212224 """
213- if self .__closed :
225+ if self ._closed :
214226 raise ValueError ("cannot write to a closed file" )
215227
216228 if not isinstance (data , str ):
@@ -270,9 +282,9 @@ def __init__(self, root_collection, file_id):
270282 raise TypeError ("root_collection must be an instance of Collection" )
271283
272284 self .__chunks = root_collection .chunks
273- self .__file = root_collection .files .find_one ({"_id" : file_id })
285+ self ._file = root_collection .files .find_one ({"_id" : file_id })
274286
275- if not self .__file :
287+ if not self ._file :
276288 raise NoFile ("no file in gridfs collection %r with _id %r" %
277289 (root_collection , file_id ))
278290
@@ -315,7 +327,7 @@ def read(self, size=-1):
315327 size = remainder
316328
317329 data = self .__buffer
318- chunk_number = (len (bytes ) + self .__position ) / self .chunk_size
330+ chunk_number = (len (data ) + self .__position ) / self .chunk_size
319331
320332 while len (data ) < size :
321333 chunk = self .__chunks .find_one ({"files_id" : self ._id ,
0 commit comments