2

I'm trying to do an upload to podio but it fails. Following extract :

c = api.OAuthClient(
    podio_pw.client_id,
    podio_pw.client_secret,
    podio_pw.username,
    podio_pw.password,  
source = "dit is een test"
    attributes = {
            'filename' : 'test.txt',
            'source' : source
            }
    filep = 

c.transport.POST(url='/file/v2/',body=attributes,type='multipart/form-data')

This results always in the following error.

Traceback (most recent call last):
  File "C:\Python34\libs\podio-py-master\attach_invoices.py", line 43, in <module>
    filep = c.transport.POST(url='/file/v2/',body=attributes,type='multipart/form-data')
  File "C:\Python34\libs\podio-py-master\pypodio2\transport.py", line 135, in __call__
    body = "".join(body)
  File "C:\Python34\libs\podio-py-master\pypodio2\encode.py", line 376, in __next__
    return next(self)
  File "C:\Python34\libs\podio-py-master\pypodio2\encode.py", line 352, in __next__
    block = next(self.param_iter)
  File "C:\Python34\libs\podio-py-master\pypodio2\encode.py", line 245, in iter_encode
    block = self.encode(boundary)
  File "C:\Python34\libs\podio-py-master\pypodio2\encode.py", line 233, in encode
    if re.search("^--%s$" % re.escape(boundary), value, re.M):
  File "C:\Python34\lib\re.py", line 166, in search
    return _compile(pattern, flags).search(string)
TypeError: can't use a string pattern on a bytes-like object

I know it has to do something with byte-encoding etc but I have no idea how to handle it. Even if I try to make that source a file, raw file or whatever, the POST fails.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
mdecroos
  • 21
  • 1
  • same result with source = open("test.txt", "rb") Can somebody explain what "source" in this attributes variable should be ? The file , the filename, the fileobject , the binary /raw file or ...??? – mdecroos Feb 02 '15 at 17:16

3 Answers3

1

This worked for me:

c = api.OAuthClient(
    client_id,
    client_secret,
    username,
    password,    
)

filename = 'screenie.png'
filedata = open(filename, 'r')

"""Create a file from raw data"""
attributes = {'filename': filename,
              'source': filedata}

file_upload = c.transport.POST(url='/file/v2/', body=attributes, type='multipart/form-data')
print(file_upload)

I lifted the code from here: https://github.com/podio/podio-py/blob/master/pypodio2/areas.py

Silas
  • 89
  • 1
  • 7
1

To execute the file upload process in Python 3.*, You have to update two files in pypodio.

Step 1

Replace the file encode.py with the below script.

import urllib.request
import http.client
import mimetypes
import codecs
import uuid
import binascii
import io
import os
import sys

def multipart_encode(fields, files):
    content_type, body = MultipartFormdataEncoder().encode(fields, files)
    return body, content_type


class MultipartFormdataEncoder(object):
    def __init__(self):
        self.boundary = uuid.uuid4().hex
        self.content_type = 'multipart/form-data; boundary={}'.format(self.boundary)

    @classmethod
    def u(cls, s):
        if sys.hexversion < 0x03000000 and isinstance(s, str):
            s = s.decode('utf-8')
        if sys.hexversion >= 0x03000000 and isinstance(s, bytes):
            s = s.decode('utf-8')
        return s

    def iter(self, fields, files):
        """
        fields is a sequence of (name, value) elements for regular form fields.
        files is a sequence of (name, filename, file-type) elements for data to be uploaded as files
        Yield body's chunk as bytes
        """
        encoder = codecs.getencoder('utf-8')
        for (key, value) in fields:
            key = self.u(key)
            yield encoder('--{}\r\n'.format(self.boundary))
            yield encoder(self.u('Content-Disposition: form-data; name="{}"\r\n').format(key))
            yield encoder('\r\n')
            if isinstance(value, int) or isinstance(value, float):
                value = str(value)
            yield encoder(self.u(value))
            yield encoder('\r\n')
        for (key, filename, fpath) in files:
            key = self.u(key)
            filename = self.u(filename)
            yield encoder('--{}\r\n'.format(self.boundary))
            yield encoder(self.u('Content-Disposition: form-data; name="{}"; filename="{}"\r\n').format(key, filename))
            yield encoder(
                'Content-Type: {}\r\n'.format(mimetypes.guess_type(filename)[0] or 'application/octet-stream'))
            yield encoder('\r\n')
            with open(fpath, 'rb') as fd:
                buff = fd.read()
                yield (buff, len(buff))
            yield encoder('\r\n')
        yield encoder('--{}--\r\n'.format(self.boundary))

    def encode(self, fields, files):
        body = io.BytesIO()
        for chunk, chunk_len in self.iter(fields, files):
            body.write(chunk)
        return self.content_type, body.getvalue()

Code snippet from here

Step 2

Update transport.py, line no.186,

        if kwargs['type'] == 'multipart/form-data':
            fields = [('filename', kwargs['body']['filename'])]
            files = [('source', kwargs['body']['filename'],kwargs['body']['source'])]
            body, content_type = multipart_encode(fields,files)
            headers.update({'Content-Type': content_type, })
        else:
Mûhámmàd Yäsår K
  • 1,492
  • 11
  • 24
0

Returns "can only join an iterable error"

attributes={'filename': 'mx.txt', 'source': 'hello uyur92wyhfr    ruptgpwyoer8t9u'}
    try:
        item = c.transport.POST(url=url,
                                body=attributes,
                                type='multipart/form-data')
    except Exception as e:
        print(e)