Output Multi-line strings with Python Flask or other framework

Question:

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.

Asked By: lumberjacked

||

Answers:

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"""
Answered By: Sean Vieira

Sean’s answer is the correct way to go, but if you just want to test something you could use the xmp tag:

@app.route("/"):
def hello():
    return """<xmp>
              Hello,
              Multiline!
              </xmp>"""

decorator version

You could also create your own decorator for this:

from functools import wraps

def multiline(fn):
    @wraps(fn)
    def _fn(*args, **kwargs):
        return "<xmp>" + fn(*args, **kwargs) + "</xmp>"
    return _fn

Then you can do:

    @app.route("/"):
    @multiline
    def hello():
    return """Hello,
              Multiline!"""
Answered By: enrico.bacis
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.