Output Multi-line strings with Python Flask or other framework

lumberjacked picture lumberjacked · Jun 25, 2013 · Viewed 11.2k times · Source

I am trying to take Redhat kickstart files and modify them in python before using them in a server setup. My app uses python to curl the original kickstart file from my Redhat Satellite server then I'm doing a string replace on certain values in the kickstart file. When I curl the file in python it comes back as a multi-line string, which is what I need in order for redhat kickstart to interpret the file correctly. But when I return the string variable through one of these frameworks (web2py, bottle, flask) something is happening and it is not returning it as a multi-line string, I need it to preserve the exact format of the original file besides the areas I change. I don't want to put my kickstart files in templates because I manage them through satellite, if I curl the file from satellite then it picks up any modifications without needing to go into the template ever time. Then in a template or something I either return the string without a template or in a template file I only pass 1 variable to the template as the entire kickstart file.

@route('/kickstart/<name>')
def kickstart(name):

    ks = vula.kickstarter.kickstart.Kickstarter()
    ks_file = ks.getKickstartFile()

    return pystache.render('{{kickstart}}', {'kickstart': ks_file})

Here is the method in my vula package. It returns the file exactly the way I need it. But again something is happening between this and returning this value through the framework.

def getKickstartFile(self):

    response = urllib2.urlopen('https://my-satellite-server/core-kickstarter')
    ks_file = response.read()

    return ks_file

I started off using Bottle as a framework but I found a statement that says they are not capable of returning multi-line strings, so scratch that. I moved over to Flask but currently Flask is doing the same thing. I am still learning python and possibly I'm doing something wrong, but I need any help possible to get this working correctly. I would like to output a multi-line string. I understand that you use either

""" or '''

for multi-line strings, but even after you do that and send it through a framework it will still print to the screen as one continuous line. What am I doing wrong? As a vary last resort I will be forced to put the kickstart files into templates if I cannot output multi-line strings.

Answer

Sean Vieira picture Sean Vieira · Jun 26, 2013

Both Bottle and Flask can handle multi-line strings just fine. Your issue is that your data is being interpreted as text/html by default and in HTML any combination of whitespace is collapsed into a single space when displayed. In order to ensure that your data comes back exactly as you sent it you'll want to set the Content-Type header to text/plain.

In Flask:

# If you want *all* your responses to be text/plain
# then this is what you want
@app.after_request
def treat_as_plain_text(response):
    response.headers["content-type"] = "text/plain"
    return response

# If you want only *this* route to respond
# with Content-Type=text/plain
@app.route("/plain-text")
def a_plain_text_route():
    response = make_response(getKickstartFile())
    response.headers["content-type"] = "text/plain"
    return response

In Bottle:

@route("/plain-text")
def plain_text():
    response.content_type = "text/plain"
    return """This
              multi-line string
              will show up
              just fine"""