Python error TypeError: argument should be bytes, buffer or ASCII string, not 'NoneType'

user4573 picture user4573 · Oct 25, 2017 · Viewed 8.1k times · Source

I'm trying to create a tool to transfer binary files in python 3 and running into an odd issue on the server side. In the server code you will see I have one line commented out which prints the data received from the client to the screen.

With this line commented out I receive the error TypeError: argument should be bytes, buffer or ASCII string, not 'NoneType' and the binary file is obviously damaged.

If I uncomment the print statement from the server code the file is transferred as expected and the binary file is received undamaged. I've tried checking for None on self.data, however, a None type is never detected.

I'm completely bewildered as to why the line "print(self.data)" is allowing the code to execute without an error. Any ideas are appreciated.

Server to receive file:

import socketserver, argparse, sys, binascii
class tcpReceiver(socketserver.BaseRequestHandler):
    def handle(self):
        self.data = self.request.recv(4096).strip()
        if self.data.startswith(b"snd:"):
            self.file = self.data.split(b":")[1]
            print ("Receiving File: " + str(self.file, "utf-8"))
            with open(self.file, 'wb') as f:
                while self.data:
                    self.data = self.request.recv(4096).strip()
                    #print (self.data)
                    if len(self.data) % 2 == 0:
                        f.write(binascii.unhexlify(self.data))
                    else:
                        f.write(binascii.unhexlify(bytearray(self.data).append(0)))
        print ("File Received.")
        return

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("port", action="store", help="port", type=int)      
    args = parser.parse_args() # Declare argumnets object to args
    host, port = "", args.port
    server = socketserver.TCPServer((host, port), tcpReceiver)
    server.serve_forever()

Client to send file:

import socket
import sys, os, argparse, binascii

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("host", action="store", help="remote host", type=str)
    parser.add_argument("port", action="store", help="remote port", type=int)
    parser.add_argument("file", action="store", help="file to send", type=str)
    args = parser.parse_args() # Declare argumnets object to args
    HOST, PORT = args.host, args.port
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((HOST, PORT))
    path, file = os.path.split(args.file)
    sock.sendall(b"snd:" + bytes(file, "utf-8"))
    with open(args.file, 'rb') as f:
        dat = f.read(4096)
        while (dat):
            if dat:
                sock.sendall(binascii.hexlify(dat))
            dat = f.read(4096)
    sock.close()

Answer

hyper-neutrino picture hyper-neutrino · Oct 25, 2017

append is not in-place

bytearray(self.data).append(0): You are making the mistake in assuming that this returns a value. In reality, it just appends 0 to the array and returns nothing (I really despise this too, especially for code golf). Instead, do this for the else clause:

array = bytearray(self.data)
array.append(0)
f.write(binascii.unhexlify(array))

You might also be able to just do f.write(binascii.unhexlify(bytearray(self.data) + [0])) I'm not sure.