Skip to main content

Basically textwrap.dedent with t-string support.

Project description

better dedent

PyPI - Version PyPI - Python Version


It's like textwrap.dedent, but with added t-string support.

The problem: interpolating before dedenting

Have you ever used textwrap.dedent with an f-string that has newline characters in a replacement field?

For example, given this code string (which has newlines in it):

code = r"""
def strip_each(lines):
    new_lines = []
    for line in lines:
        new_lines.append(line.rstrip("\n"))
    return new_lines
""".strip("\n")

Using textwrap.dedent with an f-string that uses code in a replacement field results in very strange indentation:

>>> print(dedent(f"""\
...     Example function:
...         {code}
...
...     That function was NOT indented properly!"""))
Example function:
    def strip_each(lines):
new_lines = []
for line in lines:
    new_lines.append(line.rstrip("\n"))
return new_lines

The problem is that f-strings immediately interpolate their replacement fields.

That code string is injected into the new string before dedent has a chance to even look at the string. By the time textwrap.dedent does its dedenting, the weirdness has already happened.

The solution: interpolating after dedenting

Passing a t-string to the better_dedent.dedent function allows the replacement fields to maintain their original indentation level.

Using the same code string as before:

code = r"""
def strip_each(lines):
    new_lines = []
    for line in lines:
        new_lines.append(line.rstrip("\n"))
    return new_lines
""".strip("\n")

The better_dedent.dedent function will dedent the t-string and then inject the replacement field, resulting in much more sensible indentation:

>>> print(dedent(t"""\
...     Example function:
...         {code}
...
...     That function was indented properly!""")
...
Example function:
    def strip_each(lines):
        new_lines = []
        for line in lines:
            new_lines.append(line.rstrip("\n"))
        return new_lines

That function was indented properly!

Using a t-string allows for dedenting the whole string before the replacement fields are inserted and then inserting the replacement fields.

Note that if an f-string is passed to better_dedent.dedent, it will simply delegate to textwrap.dedent.

undent

This package also includes an undent function, which will strip a leading newline (note the lack of \ after t"""):

>>> print(undent(t"""
...     Example function:
...         {code}
...     That function was indented properly!"""))
Example function:
    def strip_each(lines):
        new_lines = []
        for line in lines:
            new_lines.append(line.rstrip("\n"))
        return new_lines
That function was indented properly!

The undent function will also strips a trailing newline by default:

>>> print(undent(t"""
...     Example function:
...         {code}
...     That function was indented properly!
... """))
Example function:
    def strip_each(lines):
        new_lines = []
        for line in lines:
            new_lines.append(line.rstrip("\n"))
        return new_lines
That function was indented properly!
>>> print("Note that there's no blank line above this prompt")
Note that there's no blank line above this prompt

Passing strip_trailing=False to undent will suppress trailing newline removal.

Installation

pip install better-dedent

Or if you have uv installed and you'd like to play with it right now:

uvx --with better-dedent python

You can then import dedent and undent like this:

from better_dedent import dedent, undent

And try them out:

code = r"""
def strip_each(lines):
    new_lines = []
    for line in lines:
        new_lines.append(line.rstrip("\n"))
    return new_lines
""".strip("\n")

text = undent(t"""
    Here is some example code:

        {code}

    That indentation worked out nicely!
""")
print(text)

License

better-dedent is distributed under the terms of the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

better_dedent-0.0.3.tar.gz (6.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

better_dedent-0.0.3-py3-none-any.whl (4.6 kB view details)

Uploaded Python 3

File details

Details for the file better_dedent-0.0.3.tar.gz.

File metadata

  • Download URL: better_dedent-0.0.3.tar.gz
  • Upload date:
  • Size: 6.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.28.1

File hashes

Hashes for better_dedent-0.0.3.tar.gz
Algorithm Hash digest
SHA256 eebcc59241687ad04435140b49af3d70a7245e0403fe9fb70bb76ec4eb20c3d1
MD5 47e62cfbf1f8fc30d9502072379caca5
BLAKE2b-256 c755d08e7981b74c0b2d457479140c198d61b4f05edc5c3b3436528a22dd1d4b

See more details on using hashes here.

File details

Details for the file better_dedent-0.0.3-py3-none-any.whl.

File metadata

File hashes

Hashes for better_dedent-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 ff6d34bcf91c98c9b32ef2f26da7eca1c579d8d234c41e4277e6d041042189c5
MD5 02d7374be56ae83925cafc69f5bef9d1
BLAKE2b-256 0a5e4506ed4770e0d005bc9c3829c39f05fee425facce2ff16095a77f7412205

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page