Search code examples
pythonjsonurllib2pyramid

Pyramid rendered JSON Response returned as a string


I'm using the pyramid web framework and writing some functions that receive and respond with JSON.

Here is some code I've written that returns the files and directories from a given directory

@view_config(route_name='file', renderer='json')
def file(request):
    values = request.json_body
    path = os.path.dirname(__file__) + '/files' + values['path']
    if os.path.isdir(path):
        files = [ f for f in os.listdir(path) if os.path.isfile(os.path.join(path,f)) ]
        dirs = [ f for f in os.listdir(path) if os.path.isdir(os.path.join(path,f)) ]
        if files is None:
            files = []
        if dirs is None:
            dirs = []
        response = dict()
        response['version']='1.0'
        response['files']=files
        response['directories']=dirs
        return response
    else:
        response = dict()
        response['version']='1.0'
        response['files']=[]
        response['directories']=[]
        return response

@view_config(route_name='files', renderer='templates/filesTest.jinja2')
def files(request):
    if 'form.submitted' in request.params:
        json_payload = json.dumps({'path':request.params['path']})
        headers = {'Content-Type':'application/json; charset=utf-8'}
        req = urllib2.Request(request.route_url('file'), json_payload, headers)
        resp = urllib2.urlopen(req)
        data = resp.read()
        return dict(dirs=[], files=[], saveURL = request.route_url('files'), pathDefault=request.params['path'])
    return dict(dirs=[], files=[], saveURL = request.route_url('files'), pathDefault='/')

I'm mainly having trouble with the files function. type(data) is returning <type 'str'>. Sending the string to my template displays {"files": ["file1.jpg", "file2.png"], "version": "1.0", "directories": ["Directory1"]}

Does anyone know why I'm getting a string result?


Solution

  • When you make a request the server sends you some bytes back. How you interpret those bytes is up to you. If you request XML instead of JSON, you also do not receive an XML object, but bytes that can be interpreted as XML.

    It is superfluous to make an explicit request. This makes sense when:

    • Crossing languages
    • Crossing components and you want really little coupling

    In this case all code is in the same component, and the same language. A better solution is a helper function:

    def fetch_files_and_directories(path):
        path = os.path.dirname(__file__) + '/files' + path
        if os.path.isdir(path):
            files = [ f for f in os.listdir(path) if os.path.isfile(os.path.join(path,f)) ]
            dirs = [ f for f in os.listdir(path) if os.path.isdir(os.path.join(path,f)) ]
            # Note that the is None check is nonsense.
            # The result of an empty list comprehension is an empty list, not None
        else:
            files = []
            directories = []
        return dict(directories=dirs, files=files)
    
    @view_config(route_name='file', renderer='json')
    def file(request):
        response = fetch_files_and_directories(request.json_body['path'])
        # you might want to move this into the fetch_* function.
        response['version']='1.0'
        return response
    
    @view_config(route_name='files', renderer='templates/filesTest.jinja2')
    def files(request):
        if 'form.submitted' in request.params:
            path = request.params['path']
            data = fetch_files_and_directories(path)
            # You did not use data below here, so neither did I.
            return dict(dirs=[], files=[], saveURL = request.route_url('files'), pathDefault=path)
        return dict(dirs=[], files=[], saveURL = request.route_url('files'), pathDefault='/')
    

    Keep in mind that file(request) now maybe has become obsolete.