Is it possible for python to interpret operators within a variable?

I have a block of text that I am printing to console, and I want to style it a little bit. The block of text is held in a MongoDB, and has a few things included like colorama styles and newline characters. I store multiple blocks of text like this in the DB that get called in various ways, and to keep the database clean I'd like to be able to declare everything within 1 field of the document.

Example text block, as seen by python when retrieved using pymongo:

'This is the first line of text' + '\n' + Style.DIM + 'This is the second line of text' + '\n'

If I put this into print(), then it formats exactly as I want where the second line looks greyed out (due to Style.DIM):

This is the first line of text
This is the second line of text

However, if I retrieve it from the database using a pymongo call like db.text["TEXT"] I can't seem to find the solution for getting python to interpret the + operators, newlines or colorama styles. It just prints the string literally into the console with single-quotes and all like my first example above.

I've attempted a few things:

  • Force it to a string with str()
  • Try to format with print(f"{db.text['TEXT']}"). I entered the newlines and styles within {}, but python just printed them literally without parsing anything inside.
  • Splitting the text into a list, iterate the list, then print each line. Trying both str() and format mentioned previously.

Is there anything built-in that allows me to retrieve the field, then get python to interpret the operators/style/etc before it actually prints to console?


EDIT1: Adding code for more context

The MongoDB document looks like this when viewed through robo3t:

{
    "_id" : "61e2178b6b5b2246042eac8c",
    "NAME": "Room 1",
    "DESC": "'This is the first line of text' + '\\n' + Style.DIM + 'This is the second line of text' + '\\n'"
}

My python looks like this:

from colorama import Fore, Back, Style
import pymongo

# Setup database connections
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["dbname"]
rooms = db["rooms"]

# I have a lot of docs, so I need to locate the right one first
roomInfo = rooms.find_one( { "NAME": "Room 1" } )

# Now I print the name and description
print(roomInfo["NAME"])
print(roomInfo["DESC"])

The output looks like this:

Room 1
'This is the first line of text' + '\n' + Style.DIM + 'This is the second line of text' + '\n'

EDIT2: If I copy the output as it is above into print(), it's how I want it to look.

To clarify one more time what I mean, this code:

print('This is the first line of text' + '\n' + Style.DIM + 'This is the second line of text' + '\n')

Outputs like this:

This is the first line of text
This is the second line of text


EDIT3: Based on @Sid's comment, I tried this:

I updated the document, so it views like this in MongoDB:

# example 1
"DESC": "This is the first line of text\n{Style.DIM}This is the second line of text\n"

# example 2
"DESC": "f\"This is the first line of text\n{Style.DIM}This is the second line of text\n\""

I tried print() a couple ways:

# example 1
print(f"{roomInfo['DESC']}")

# example 2
print(roomInfo["DESC"])

I didn't realize the \n characters would get parsed, so that part is solved at least. It still prints the {} brackets literally and doesn't parse Style.DIM in either example. In the second example, it also prints the f" characters.


Solution 1:

Store a template string in the database, without any operators or string-escapes but with some sort of placeholders for the .format call - such that your database object looks like:

{
    "_id" : "61e2178b6b5b2246042eac8c",
    "NAME": "Room 1",
    "DESC": "This is the first line of text\n{DIM}This is the second line of text\n"
}

Ahead of time, construct a mapping from those placeholders to the value to insert:

styles = { 'DIM': Styles.DIM, } # etc.
# There are shortcuts for this, which may or may not be good enough for your purposes.

Now when you retrieve a string from the database, you can call .format directly (that's one of the reasons why it still exists along-side the f-strings that are syntactic sugar for the method):

roomInfo = rooms.find_one( { "NAME": "Room 1" } )
print(roomInfo['DESC'].format(**styles))
# or: print(roomInfo['DESC'].format_map(styles))

You could also do the formatting before you write to the database. That way, the database looks like:

{
    "_id" : "61e2178b6b5b2246042eac8c",
    "NAME": "Room 1",
    "DESC": "This is the first line of text\n\033[2mThis is the second line of text\n"
}

(Of course, in the code that you use to write to the database, you'd use an f-string to specify the DIM code.)

This is simpler, but less flexible. By formatting the codes later, you can choose how to format them. You can even easily set it up to ignore all the placeholders:

class Blank(dict):
    """A fake dictionary that reports an empty string for every key."""
    def __missing__(self, key):
        return ''
    # Optional, for cleanliness:
    def __setitem__(self, key):
        pass # intentionally don't add it

# Now every placeholder is just removed - replaced with nothing.
print(roomInfo['DESC'].format_map(Blank()))