Concatenate str

I have a main class that returns the result of a secondary class. The problem is defined in the following message in the terminal:

TypeError: can only concatenate str (not “CompletedProcess”) to str

This is due to the sub-process that I need to concatenate within the body of the html, below is an excerpt from the primary class and the secondary class:

Primary Class

def do_GET(self):
    self.do_HEAD()
    from index import Index
    o_html = Index().view()
    self.wfile.write(bytes(o_html, "utf8"))
    return

Secondary Class

#! /usr/local/bin/python3.9
import subprocess

# Class name : Index -> Structure html page :
class Index:

    # Class method : Constructor -> Object Build :
    def __init__(self):
        pass

    # Class method : build ->  : Render code html :
    def view(self):

        self.v_shell = subprocess.run("ls")
        # Variable : v_html5 -> Code Html
        self.v_html5 = """
            <!DOCTYPE html>
            <html lang="pt-BR">
            <head>
                <meta charset="UTF-8">
                <meta http-equiv="X-UA-Compatible" content="IE=edge">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>Webstrucs Action</title>
            </head>
            <body>
                <h1>Action</h1>
                Python Web Server For Asynchronous Requests<br>
                """ + self.v_shell + """
                <p>
                </p>
            </body>
            </html>
        """
        return self.v_html5

How can I get around this TypeError?

I have a main class that returns the result of a secondary class. The
problem is defined in the following message in the terminal:

TypeError: can only concatenate str (not “CompletedProcess”) to str

This says that you’re joining a string to a CompletedProcess.

This is due to the sub-process that I need to concatenate within the body of the html, below is an excerpt from the primary class and the secondary class:

Thanks for including the code. It also helps to include the stack trace
which came with the exception above.

But no matter, the issue’s with your secondary class:

#! /usr/local/bin/python3.9
import subprocess
class Index:

Class method : build → : Render code html :

def view(self):
self.v_shell = subprocess.run(“ls”)

Here you’re storing the result of subprocess.run() in v_shell. That
function is documented here:

https://docs.python.org/3/library/subprocess.html#subprocess.run

What does it return? A CompletedProcess instance:

https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess

which is where you get the CompletedProcess in the exception above,
which comes from lower down where you go:

           Python Web Server For Asynchronous Requests<br>
           """ + self.v_shell + """

where you’re adding your document text to v_shell.

What you actually want is the output of the “ls” command. That is
actually one of the attributes of the CompletedProcess.

See the documentation above, in particular the statements about what is
needed for the .stdout attribute to be a string - you must call .run()
in a particular way.

Cheers,
Cameron Simpson cs@cskk.id.au

Hi Joao,

does not return a string with the output of “ls”.

Try self.v_shell = subprocess.check_output(‘ls’, shell=True) instead.

Cheers, Dominik

You shouldn’t use shell=True unless you really know what you are doing.

Not only does it have security issues, but it’s also less efficient.

Might be true, but on some systems, it might not work without it (e.g. on my Windows system)…

The documentation says:

“”"
On Windows with shell=True, the COMSPEC environment variable specifies
the default shell. The only time you need to specify shell=True on
Windows is when the command you wish to execute is built into the shell
(e.g. dir or copy). You do not need shell=True to run a batch file or
console-based executable.
“”"

https://docs.python.org/3/library/subprocess.html#subprocess.Popen

As “dir” is Windows counterpart of Linux’s “ls”, this applies here, right?

“dir” might be a Windows shell builtin, but on UNIX “ls” is a standalone
executable.

…which does not change the fact, that you need the shell=True part, if you want to get the example working on Windows (apparently with “dir” instead of “ls” there) - it just explains it. Which is nice :slight_smile:

This is how it works :

subprocess.getoutput("ls")
1 Like

Hi João,

When posting error messages, it is helpful to post the full traceback,
not just the last line. The traceback contains lots of useful debugging
information, especially the line of code that causes the error.

I think that the problem you have is this:

self.v_shell = subprocess.run("ls")
self.v_html5 = """html""" + self.v_shell + """text"""

which contains a number of bugs. The first gives you a TypeError when
you try to concatenate a CompletedProcess object to a string.

To solve that, we can read the docs for subprocess.run:

https://docs.python.org/3/library/subprocess.html#subprocess.run

Unfortunately subprocess is a complex library, and the run function
has to do a lot of different things. You need to read the docs carefully
to decide what information you need back from the subprocess. I will
guess that you want to capture the output of the ls call.

self.v_html5 = """html""" + self.v_shell.stdout + """html"""

However, before you can fix that bug, you need to also fix another bug:
your run function doesn’t capture stdout.

# Doesn't capture output.
self.v_shell = subprocess.run("ls")

# Capture output as bytes
self.v_shell = subprocess.run("ls", capture_output=True)

# Capture output as a string
self.v_shell = subprocess.run("ls", capture_output=True, text=True)

Once you have fixed those two arguments, that leaves the most incidious
bug of all: you are injecting the raw output of the ls command
directly into your HTML. If a clever attact can get you to run this in a
directory they control, they can put any HTML code into your webpage
they want, including Javascript.

Unless this is only going to be run by somebody you totally trust, on
systems that you alone have access to, you should sanitise the output of
ls before injecting it into the HTML code.

I’m not an expert on HTML security vulnerabilities, but at the very
least you should probably run the output through html.escape:

output = html.escape(self.v_shell.stdout)
self.v_html5 = """html""" + output + """html"""