Tim Perevezentsev avatar Tim Perevezentsev committed 4ba9ab0

files support added to `BaseRequest.blank`

Comments (0)

Files changed (2)

tests/test_request.py

         self.assertEqual(exc_info[0], RuntimeError)
 
     #get_response
-    #blank
+    def test_blank__method_subtitution(self):
+        request = BaseRequest.blank('/', environ={'REQUEST_METHOD': 'PUT'})
+        self.assertEqual(request.method, 'PUT')
+
+        request = BaseRequest.blank('/', environ={'REQUEST_METHOD': 'PUT'}, POST={})
+        self.assertEqual(request.method, 'PUT')
+
+        request = BaseRequest.blank('/', environ={'REQUEST_METHOD': 'HEAD'}, POST={})
+        self.assertEqual(request.method, 'POST')
+
+    def test_blank__ctype_in_env(self):
+        request = BaseRequest.blank('/', environ={'CONTENT_TYPE': 'application/json'})
+        self.assertEqual(request.content_type, 'application/json')
+        self.assertEqual(request.method, 'GET')
+
+        request = BaseRequest.blank('/', environ={'CONTENT_TYPE': 'application/json'},
+                                         POST='')
+        self.assertEqual(request.content_type, 'application/json')
+        self.assertEqual(request.method, 'POST')
+
+    def test_blank__ctype_in_headers(self):
+        request = BaseRequest.blank('/', headers={'Content-type': 'application/json'})
+        self.assertEqual(request.content_type, 'application/json')
+        self.assertEqual(request.method, 'GET')
+
+        request = BaseRequest.blank('/', headers={'Content-Type': 'application/json'},
+                                         POST='')
+        self.assertEqual(request.content_type, 'application/json')
+        self.assertEqual(request.method, 'POST')
+
+    def test_blank__ctype_as_kw(self):
+        request = BaseRequest.blank('/', content_type='application/json')
+        self.assertEqual(request.content_type, 'application/json')
+        self.assertEqual(request.method, 'GET')
+
+        request = BaseRequest.blank('/', content_type='application/json',
+                                         POST='')
+        self.assertEqual(request.content_type, 'application/json')
+        self.assertEqual(request.method, 'POST')
+
+    def test_blank__str_post_data_for_unsupported_ctype(self):
+        self.assertRaises(ValueError, BaseRequest.blank, '/', content_type='application/json',
+                                                              POST={})
+
+    def test_blank__post_urlencoded(self):
+        request = Request.blank('/', POST={'first':1, 'second':2})
+        self.assertEqual(request.method, 'POST')
+        self.assertEqual(request.content_type, 'application/x-www-form-urlencoded')
+        self.assertEqual(request.body, 'second=2&first=1')
+        self.assertEqual(request.content_length, 16)
+
+    def test_blank__post_multipart(self):
+        request = Request.blank('/', POST={'first':'1', 'second':'2'}, 
+                                     content_type='multipart/form-data; boundary=boundary')
+        self.assertEqual(request.method, 'POST')
+        self.assertEqual(request.content_type, 'multipart/form-data')
+        self.assertEqual(request.body, '--boundary\r\n'
+                                       'Content-Disposition: form-data; name="second"\r\n\r\n'
+                                       '2\r\n'
+                                       '--boundary\r\n'
+                                       'Content-Disposition: form-data; name="first"\r\n\r\n'
+                                       '1\r\n'
+                                       '--boundary--')
+        self.assertEqual(request.content_length, 139)
+
+    def test_blank__post_files(self):
+        import cgi
+        from StringIO import StringIO
+        request = Request.blank('/', POST={'first':('filename1', StringIO('1')), 
+                                           'second':('filename2', '2'),
+                                           'third': '3'})
+        self.assertEqual(request.method, 'POST')
+        self.assertEqual(request.content_type, 'multipart/form-data')
+        self.assertEqual(request.body, '--boundary\r\n'
+                                       'Content-Disposition: form-data; name="second"; filename="filename2"\r\n\r\n'
+                                       '2\r\n'
+                                       '--boundary\r\n'
+                                       'Content-Disposition: form-data; name="third"\r\n\r\n'
+                                       '3\r\n'
+                                       '--boundary\r\n'
+                                       'Content-Disposition: form-data; name="first"; filename="filename1"\r\n\r\n'
+                                       '1\r\n'
+                                       '--boundary--')
+        self.assertEqual(request.content_length, 246)
+        self.assertTrue(isinstance(request.POST['first'], cgi.FieldStorage))
+        self.assertTrue(isinstance(request.POST['second'], cgi.FieldStorage))
+        self.assertEqual(request.POST['first'].value, '1')
+        self.assertEqual(request.POST['second'].value, '2')
+        self.assertEqual(request.POST['third'], '3')
+
+    def test_blank__post_file_w_wrong_ctype(self):
+        self.assertRaises(ValueError, Request.blank, '/', POST={'first':('filename1', '1')},
+                                                          content_type='application/x-www-form-urlencoded')
 
     #from_string
     def test_from_string_extra_data(self):
         ``decode_param_names``).
         """
         env = environ_from_url(path)
-        environ_add_POST(env, POST)
         if base_url:
             scheme, netloc, path, query, fragment = urlparse.urlsplit(base_url)
             if query or fragment:
                 env['SCRIPT_NAME'] = urllib.unquote(path)
         if environ:
             env.update(environ)
+        content_type = kw.get('content_type', env.get('CONTENT_TYPE'))
+        if headers and 'Content-Type' in headers:
+            content_type = headers['Content-Type']
+        if content_type is not None:
+            kw['content_type'] = content_type
+        environ_add_POST(env, POST, content_type)
         obj = cls(env, **kw)
         if headers is not None:
             obj.headers.update(headers)
     }
     return env
 
-def environ_add_POST(env, data):
+
+def environ_add_POST(env, data, content_type=None):
     if data is None:
         return
-    env['REQUEST_METHOD'] = 'POST'
+    if env['REQUEST_METHOD'] not in ('POST', 'PUT'):
+        env['REQUEST_METHOD'] = 'POST'
+    has_files = False
     if hasattr(data, 'items'):
         data = data.items()
-    if not isinstance(data, str):
-        data = urllib.urlencode(data)
+        has_files = filter(lambda _: isinstance(_[1], (tuple, list)), data)
+    if content_type is None:
+        content_type = has_files and 'multipart/form-data; boundary=boundary' or 'application/x-www-form-urlencoded'
+    if content_type.lower().startswith('multipart/form-data'):
+        if not isinstance(data, str):
+            data = _encode_multipart(data, content_type)
+    elif content_type.lower().startswith('application/x-www-form-urlencoded'):
+        if has_files:
+            raise ValueError('Submiting files is not allowed for'
+                             ' content type `%s`' % content_type)
+        if not isinstance(data, str):
+            data = urllib.urlencode(data)
+    else:
+        if not isinstance(data, str):
+            raise ValueError('Please provide `POST` data as string'
+                             ' for content type `%s`' % content_type)
     env['wsgi.input'] = StringIO(data)
     env['webob.is_body_seekable'] = True
     env['CONTENT_LENGTH'] = str(len(data))
-    env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
+    env['CONTENT_TYPE'] = content_type
 
 
 class AdhocAttrMixin(object):
             if self.content_type.lower().startswith('application/x-www-form-urlencoded'):
                 self._body = urllib.urlencode(self.vars.items())
             elif self.content_type.lower().startswith('multipart/form-data'):
-                self._body = _encode_multipart(self.vars, self.content_type)
+                self._body = _encode_multipart(self.vars.iteritems(), self.content_type)
             else:
                 assert 0, ('Bad content type: %r' % self.content_type)
         return self._body
                             % content_type)
     boundary = boundary_match.group(1).strip('"')
     lines = []
-    for name, value in vars.iteritems():
+    for name, value in vars:
         lines.append('--%s' % boundary)
         ## FIXME: encode the name like this?
         assert name is not None, 'Value associated with no name: %r' % value
         disp = 'Content-Disposition: form-data; name="%s"' % name
+        filename = None
         if getattr(value, 'filename', None):
-            disp += '; filename="%s"' % value.filename
+            filename = value.filename
+        elif isinstance(value, (list, tuple)):
+            filename, value = value
+            if hasattr(value, 'read'):
+                value = value.read()
+        if filename is not None:
+            disp += '; filename="%s"' % filename
         lines.append(disp)
         ## FIXME: should handle value.disposition_options
         if getattr(value, 'type', None):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.