Home > database >  Store f-string with function calls in a file
Store f-string with function calls in a file

Time:01-08

I'm storing f-strings with function calls in a separate file (with lots of variables).

I am writing a script that has hundreds of variables which are then loaded into an HTML table. Some of the contents in the HTML table require function calls.

This works:

def add_one(a):
    return a   1

a = 1
s = f"A is {a} and next comes {add_one(a)}"
print(s)

When I store s in a file, I can use **locals() to format it and it works when I store variables in s.txt.

Contents of s.txt:

A is {a}

Contents of script that works:

a = 1
print(open('s.txt').read().format(**locals()))

However, when I try to call functions, it does not work:

Contents of s.txt:

A is {a} and next comes {add_one(a)}

Contents of script that does not work:

def add_one(a):
    return a   1

a = 1
print(open('s.txt').read().format(**locals()))

What can I do to make it work (given my actual case is hundreds of function calls and not this simple 2 variable example)?

In this example it should result in A is 1 and next comes 2.

CodePudding user response:

You might want to consider using a templating language rather than f-strings if you have a complex HTML table with hundreds of variables. e.g. Jinja2.

For simplicity I've stored the a value in a dictionary as this then simplifies passing it to the Jinja2 render and also converting it to JSON for storing it in a file.

Here is your example using Jinja2 templates and storing the data to a json file:

import json
from pathlib import Path

import jinja2

json_file = Path('/tmp/test_store.json')

jinja_env = jinja2.Environment()

# Set variable values
values = {'a': 3}

# Save to json file
json_file.write_text(json.dumps(values))

# Read from json file to dictionary with new variable name
read_values = json.loads(json_file.read_text())


def add_one(a):
    return a   1


# Add custom filter to jinja environment
jinja_env.filters['add_one'] = add_one
# Define template
template = jinja_env.from_string("A is {{a}} and next comes {{a | add_one}}")
# Print rendered template
print(template.render(read_values))

This gave the output of:

A is 3 and next comes 4

The JSON file is the following:

{"a": 3}

CodePudding user response:

As mentioned in the discussion e.g. here, what you want does not really work in any simple way. There is one obvious workaround: storing an f-string (e.g. f"A is {a} and next comes {add_one(a)}") in your text file and then eval'ing it:

with open('s.txt', 'r') as f:
    print(eval(f.read()))  # A is 1 and next comes 2

Of course, all the usual warnings about shooting yourself in the foot apply here, but your problem definition sounds exactly like this use case. You can try sandboxing your functions and whatnot, but it generally does not work well. I would say it is still a viable use case for homebrew automation, but it has a massive potential for backfiring, and the only reason I am suggesting it is because alternative solutions are likely to be about as dangerous.

CodePudding user response:

Use serialization and deserialization to store data

import json

data = {
    "a" : 1,
    "b" : 2,
    "name" : "Jack",
    "bunch_of_numbers" : [1, 2, 3, 5, 6]
}
file_name = "s.txt"
with open(file_name, 'w') as file:
    file.write(json.dumps(data)) #serialization

with open(file_name, 'rb') as file:
    data = json.load(file) # de-serialization
    print(data)

Output:

{'a': 1, 'b': 2, 'name': 'Jack', 'bunch_of_numbers': [1, 2, 3, 5, 6]}
  • Related