ajknzhol
ajknzhol

Reputation: 6450

TypeError: can't concat bytes to int

I am trying to hash the filename and then save into DB. I am using Flask and Python 3.4

This is the code for upload:

@app.route('/', methods=['GET', 'POST'])
def upload_pic():
    if request.method == 'POST':
        file = request.files['file']
        try:
            extension = file.filename.rsplit('.', 1)[1].lower()
        except IndexError as e:
            abort(404)
        if file and check_extension(extension):
            # Salt and hash the file contents
            filename = md5(file.read() + str(round(time.time() * 1000))).hexdigest() + '.' + extension
            file.seek(0)  # Move cursor back to beginning so we can write to disk
            file.save(os.path.join(app.config['UPLOAD_DIR'], filename))
            add_pic(filename)
            gen_thumbnail(filename)
            return redirect(url_for('show_pic', filename=filename))
        else:  # Bad file extension
            abort(404)
    else:
        return render_template('upload.html')

When i post the form, i get this error traceback.

Traceback (most recent call last):
  File "C:\Python34\lib\site-packages\flask\app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\Python34\lib\site-packages\flask\app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "C:\Python34\lib\site-packages\flask\app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Python34\lib\site-packages\flask\_compat.py", line 33, in reraise
    raise value
  File "C:\Python34\lib\site-packages\flask\app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Python34\lib\site-packages\flask\app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Python34\lib\site-packages\flask\app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Python34\lib\site-packages\flask\_compat.py", line 33, in reraise
    raise value
  File "C:\Python34\lib\site-packages\flask\app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Python34\lib\site-packages\flask\app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "C:\Users\Ajay\PycharmProjects\codehackr-upload\flaskgur.py", line 70, in upload_pic
    filename = md5(file.read() + (round(time.time() * 1000))).hexdigest() + '.' + extension
TypeError: can't concat bytes to int

I dont know whats wrong is happening, please enlighten me.

Thanks.

Upvotes: 3

Views: 23543

Answers (2)

Yirkha
Yirkha

Reputation: 13838

Yes, as julienc wrote, the problem was trying to concatenate the result of file.read(), of type bytes, with the result of round(time.time() * 1000)), which was an int.

BUT DON'T DO WHAT'S SHOWN IN THE OTHER ANSWER! Keep calm and carry on reading...

How to create bytes in Python 3

1. bytes(n) – Create bytes of length n that is empty (full of zeroes)

bytes(12) == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

This is rarely what you want. Beware!

In the context of this question md5(file.read() + bytes(round(time.time() * 1000))) hashes the file contents and then around 1.5 trillion empty bytes. Technically it still does what's needed, but ugh, for what a computing cost :-)

2. bytes([...]) – Create bytes containing the specified value(s)

bytes([12])         == b'\x0c'
bytes([444])        -> ValueError("bytes must be in range(0, 256)")
bytes([0x01, 0xBC]) == b'\x01\xbc'

Each source value must be just between 0 and 255 to fit into a byte.

Of course, could be also written with a tuple, but it's a bit uglier for the case of length 1: bytes((12,))

3. int.to_bytes(...) – Create bytes as a native/binary representation of an integer

( 12).to_bytes(8, 'big') == b'\x00\x00\x00\x00\x00\x00\x00\x0c'
(444).to_bytes(8, 'big') == b'\x00\x00\x00\x00\x00\x00\x01\xbc'

This is the answer to the original question, how to convert an integer to a stream etc.

But now you need to think about some low-level things, like number of bytes of the output and the endianness (byte order). See int.to_bytes() docs for details.

Of course, the extra parentheses are needed only with a literal value, like 12 in my example. They can be omitted when using a variable or other expression, e.g. self._size.to_bytes(8).

4. str.encode(...) – Create bytes from a string

str(12).encode() == b'12'

As an alternative to the above, sometimes you don't need or want to think about the low-level considerations and then the same goal can be accomplished by just hashing (or whatever) the simple human textual representation of the value.

encode() without an explicit encoding argument uses UTF-8, which is a good idea everywhere unless having a good reason to pick something else.

Upvotes: 2

julienc
julienc

Reputation: 20325

You are trying to concatenate the result of file.read() with the result of round(time.time() * 1000)), which is an integer. That's why you get the error:

TypeError: can't concat bytes to int

Try to cast the integer:

file.read() + bytes(round(time.time() * 1000)))

But as @Lev Levitsky noticed, it looks like your code already has the correction: are you sure to run the last version of your code?

Upvotes: 5

Related Questions