BigBoy1337
BigBoy1337

Reputation: 4963

Python/Pyramid: Will this function let users upload files and then parse them?

Right now I have this form:

<form action="/store_stl_data" method="post" accept-charset="utf-8"
      enctype="multipart/form-data">

    <label for="stl">STL</label>
    <input id="stl" name="stl" type="file" value="" />

    <input type="submit" value="submit" />
</form>

then in my views.py I have

@view_config(route_name='store_stl_data', renderer='templates/edit')

def store_stl_data(request):
    input_file=request.POST['stl'].file
    i1, i2 = itertools.tee(input_file)
    vertices = [map(float, line.split()[1:4])
                for line in i1
                if line.lstrip().startswith('vertex')]

    normals = [map(float, line.split()[2:5])
                for line in i2
                if line.lstrip().startswith('facet')]

        ...(parsing data)...
    return data

The three lines under def store_stl_data(request): are the ones I am most unsure about. I got them from this tutorial.

I want it so that when people upload the file, the entire store_stl_data function runs and processes the input file.

Right now it gives me an error:

KeyError: "No key 'stl': Not a form request"

Also here is my route, in __init__.py:

from pyramid.config import Configurator
from sqlalchemy import engine_from_config

from .models import (
    DBSession,
    Base,
    )


def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('view_wiki', '/')
    config.add_route('view_page', '/{pagename}')
    config.add_route('add_page', '/add_page/{pagename}')
    config.add_route('edit_page', '/{pagename}/edit_page')
    config.scan()
    return config.make_wsgi_app()

Upvotes: 0

Views: 1084

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121734

The .file object you get from the request is already an open file(like) object.

If you look closely at the example in the documentation you linked to, it creates a new file using the filename of the upload, and uses the uploaded file to write data to that new file. input_file is never opened in that code, only output_file is (note the different variable name there).

You do not need to close the file object either, so no with is needed. Your code can be simplified to:

def store_stl_data(request):
    input_file=request.POST['stl'].file
    i1, i2 = itertools.tee(input_file)
    vertices = [map(float, line.split()[1:4])
                for line in i1
                if line.lstrip().startswith('vertex')]

    normals = [map(float, line.split()[2:5])
                for line in i2
                if line.lstrip().startswith('facet')]

I personally would not use itertools.tee for this though, you are reading the whole file into the tee buffer while building vertices.

Instead, I'd use a single loop:

def store_stl_data(request):
    input_file=request.POST['stl'].file
    vertices, normals = [], []
    for line in input_file
        parts = line.split()
        if parts[0] == 'vertex':
            vertices.append(map(float, parts[1:4]))
        elif parts[0] == 'facet':
            normals.append(map(float, parts[2:5]))

Now only one line at a time is kept in memory (plus the vertices and normals structure).

Note: If you get a KeyError: No key '...': Not a form request error message, then the view did not receive a POST HTTP request. Do double check your form method is set to "POST" (case does not matter).

Upvotes: 1

Related Questions