title: How to prettify HTML so tag attributes will remain in one single line?
body: <p>I got this little piece of code:</p>
  
  <pre><code>text = """&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;
      &lt;h1 style="
      text-align: center;
  "&gt;Main site&lt;/h1&gt;
      &lt;div&gt;
          &lt;p style="
      color: blue;
      text-align: center;
  "&gt;text1
          &lt;/p&gt;
          &lt;p style="
      color: blueviolet;
      text-align: center;
  "&gt;text2
          &lt;/p&gt;
      &lt;/div&gt;
      &lt;div&gt;
          &lt;p style="text-align:center"&gt;
              &lt;img src="./foo/test.jpg" alt="Testing static images" style="
  "&gt;
          &lt;/p&gt;
      &lt;/div&gt;
  &lt;/body&gt;&lt;/html&gt;
  """
  
  import sys
  import re
  import bs4
  
  
  def prettify(soup, indent_width=4):
      r = re.compile(r'^(\s*)', re.MULTILINE)
      return r.sub(r'\1' * indent_width, soup.prettify())
  
  soup = bs4.BeautifulSoup(text, "html.parser")
  print(prettify(soup))
  </code></pre>
  
  <p>The output of the above snippet right now is:</p>
  
  <pre><code>&lt;html&gt;
      &lt;head&gt;
      &lt;/head&gt;
      &lt;body&gt;
          &lt;h1 style="
                  text-align: center;
  "&gt;
              Main site
          &lt;/h1&gt;
          &lt;div&gt;
              &lt;p style="
                  color: blue;
                  text-align: center;
  "&gt;
                  text1
              &lt;/p&gt;
              &lt;p style="
                  color: blueviolet;
                  text-align: center;
  "&gt;
                  text2
              &lt;/p&gt;
          &lt;/div&gt;
          &lt;div&gt;
              &lt;p style="text-align:center"&gt;
                  &lt;img alt="Testing static images" src="./foo/test.jpg" style="
  "/&gt;
              &lt;/p&gt;
          &lt;/div&gt;
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>I'd like to figure out how to format the output so it becomes this instead:</p>
  
  <pre><code>&lt;html&gt;
      &lt;head&gt;
      &lt;/head&gt;
      &lt;body&gt;
          &lt;h1 style="text-align: center;"&gt;
              Main site
          &lt;/h1&gt;
          &lt;div&gt;
              &lt;p style="color: blue;text-align: center;"&gt;
                  text1
              &lt;/p&gt;
              &lt;p style="color: blueviolet;text-align: center;"&gt;
                  text2
              &lt;/p&gt;
          &lt;/div&gt;
          &lt;div&gt;
              &lt;p style="text-align:center"&gt;
                  &lt;img alt="Testing static images" src="./foo/test.jpg" style=""/&gt;
              &lt;/p&gt;
          &lt;/div&gt;
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>Said otherwise, I'd like to keep html statements such as <code>&lt;tag attrib1=value1 attrib2=value2 ... attribn=valuen&gt;</code> in one single line if possible. When I say "if possible" I mean without screwing up the value of the attributes themselves (value1, value2, ..., valuen).</p>
  
  <p>Is this possible to achieve with beautifulsoup4? As far I've read in the docs it seems you can use a custom <a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/#output-formatters" rel="noreferrer">formatter</a> but I don't know how I could have a custom formatter so it can accomplish the described requirements.</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>@alecxe solution is quite simple, unfortunately fails in some more complex cases like the below one, ie:</p>
  
  <pre><code>test1 = """
  &lt;div id="dialer-capmaign-console" class="fill-vertically" style="flex: 1 1 auto;"&gt;
      &lt;div id="sessionsGrid" data-columns="[
          { field: 'dialerSession.startTime', format:'{0:G}', title:'Start time', width:122 },
          { field: 'dialerSession.endTime', format:'{0:G}', title:'End time', width:122, attributes: {class:'tooltip-column'}},
          { field: 'conversationStartTime', template: cty.ui.gct.duration_dialerSession_conversationStartTime_endTime, title:'Duration', width:80},
          { field: 'dialerSession.caller.lastName',template: cty.ui.gct.person_dialerSession_caller_link, title:'Caller', width:160 },
          { field: 'noteType',template:cty.ui.gct.nameDescription_noteType, title:'Note type', width:150, attributes: {class:'tooltip-column'}},
          { field: 'note', title:'Note'}
          ]"&gt;
  &lt;/div&gt;
  &lt;/div&gt;
  """
  
  from bs4 import BeautifulSoup
  import re
  
  
  def prettify(soup, indent_width=4, single_lines=True):
      if single_lines:
          for tag in soup():
              for attr in tag.attrs:
                  print(tag.attrs[attr], tag.attrs[attr].__class__)
                  tag.attrs[attr] = " ".join(
                      tag.attrs[attr].replace("\n", " ").split())
  
      r = re.compile(r'^(\s*)', re.MULTILINE)
      return r.sub(r'\1' * indent_width, soup.prettify())
  
  
  def html_beautify(text):
      soup = BeautifulSoup(text, "html.parser")
      return prettify(soup)
  
  print(html_beautify(test1))
  </code></pre>
  
  <p><strong>TRACEBACK:</strong></p>
  
  <pre><code>dialer-capmaign-console &lt;class 'str'&gt;
  ['fill-vertically'] &lt;class 'list'&gt;
  Traceback (most recent call last):
    File "d:\mcve\x.py", line 35, in &lt;module&gt;
      print(html_beautify(test1))
    File "d:\mcve\x.py", line 33, in html_beautify
      return prettify(soup)
    File "d:\mcve\x.py", line 25, in prettify
      tag.attrs[attr].replace("\n", " ").split())
  AttributeError: 'list' object has no attribute 'replace'
  </code></pre>