Search code examples
pythoncherrypy

CherryPy get uploaded file's temporary location


File Uppload in CherryPy:

    def upload(self, myFile):
        out = """File name: %s, Content-Type: %"""
        return out % (myFile.filename, myFile.content_type)
    upload.exposed = True

From docs:

When a client uploads a file to a CherryPy application, it’s placed on disk immediately. CherryPy will pass it to your exposed method as an argument (see “myFile” below); that arg will have a “file” attribute, which is a handle to the temporary uploaded file. If you wish to permanently save the file, you need to read() from myFile.file and write() somewhere else.

How can I get uploaded file's temporary location?


Solution

  • You can't get the name of the temporary file by using the default entity processor. But you can set you own custom one to ensue that a temporary file is always created (usually is not created for files <1000 bytes).

    To have a name in the temporary file you need a NamedTemporaryFile which is created with the CustomPart class:

    import tempfile
    import cherrypy as cp
    
    class App:
    
        @cp.expose
        def index(self):
            return """
            <html><body>
                <h2>Upload a file</h2>
                <form action="upload" method="post" enctype="multipart/form-data">
                filename: <input type="file" name="my_file" /><br />
                <input type="submit" />
                </form>
            </body></html>
            """
    
        @cp.expose
        def upload(self, my_file):
            return "The path is %s" % my_file.file.name
    
    
    class CustomPart(cp._cpreqbody.Part):
        """
        Custom entity part that it will alway create a named
        temporary file for the entities.
        """
        maxrambytes = 0 # to ensure that it doesn't store it in memory
    
        def make_file(self):
            return tempfile.NamedTemporaryFile()
    
    
    if __name__ == '__main__':
        cp.quickstart(App(), config={
            '/': {
                'request.body.part_class': CustomPart
            }
        })
    

    You would not be able to see the file when the request is done because by default the NamedTemporaryFile class deletes the file as soon as it closed. In this case as soon as the request finish. You can add some sleep calls like this and validate what I have just said:

       @cp.expose
       def upload(self, my_file):
            import time
            cp.log.error("You have 30 seconds to open the temporary file %s" % my_file.file.name)
            time.sleep(30)
            return "The path is %s" % my_file.file.name
    

    If you really want to keep the temporary file then you just have to set the delete parameter to False on the NamedTemporaryFile and end up with something like this:

     class CustomPart(cp._cpreqbody.Part):
            """
            Custom entity part that it will alway create a named
            temporary file for the entities.
            """
            maxrambytes = 0 # to ensure that it doesn't store it in memory
    
            def make_file(self):
                return tempfile.NamedTemporaryFile(delete=False)
    

    You'll have to make sure that you delete those temporary files on your own.