0

I have a bunch of files with many tags inside of the form {my_var}, {some_var}, etc. I am looking to open them, and replace them with my_var and some_var that I've read into Python.

To do these sorts of things I've been using inspect.cleandoc():

import inspect, markdown
my_var='this'
some_var='that'
something=inspect.cleandoc(f'''
    All my vars are {some_var} and {my_var}. This is all.
''')
print(something)
#All my vars are that and this. This is all.

But I'd like to do this by reading files file1.md and file2.md

### file1.md
There are some strings such as {my_var} and {some_var}.
Done.

### file2.md
Here there are also some vars: {some_var}, {my_var}. Also done.

Here's the Python code:

import inspect, markdown
my_var='this'
some_var='that'

def filein(file):
    with open(file, 'r') as file:
        data = file.read()
    return data

for filei in ['file1.md','file2.md']:
    fin=filein(file)
    pre=inspect.cleandoc(f'''{fin}''')

However, the above does not evaluate the strings inside filei and replace them with this (my_var) and that (some_var), and instead keeps them as strings {my_var} and {some_var}.

What am I doing wrong?

5
  • What is inspect.cleandoc expected to do? Commented Feb 3, 2020 at 11:12
  • Does this answer your question? Replace string within file contents Commented Feb 3, 2020 at 11:13
  • 1
    @bereal appologies, someone accepted an edit that excluded my preamble. I've edited my input. Commented Feb 3, 2020 at 11:16
  • @ZarakiKenpachi not really, as I'd like to avoid having to define a replace for every single variable substitution: in this work case I am suggesting 2 variables, so it is easy. But in my real case, I am importing many variables into python, which would imply that I explicitly specify each variable substitution. Commented Feb 3, 2020 at 11:17
  • @usr2564301 Sorry, I was trying to fix the function, as it would have produced an "undefined data variable" error due to its indentation. I'll try to be more careful next time. Commented Feb 3, 2020 at 11:25

2 Answers 2

2

You can use the .format method.

You can use ** to pass it a dictionary containing the variable.

Therefore you can use the locals() or globals(), which are dictionary of all the locals and globals variables.

e.g.

text = text.format(**globals())

Complete code:

my_var="this"
some_var="that"

for file in ["file1.md", "file2.md"]:
    with open(file, "r") as f:
        text = f.read()
    text = text.format(**globals())
    print(text)
Sign up to request clarification or add additional context in comments.

2 Comments

Awsome! Didn't think about passing **globals(), but this solves my problem.
In general .format(**locals()) can "emulate" the f-strings. I mostly use it on my scripts since it's both python 2 and 3 compatible so I don't have to worry about the python version.
2
  • f-strings are a static replacement mechanism, they're an intrinsic part of the bytecode, not a general-purpose templating mechanism
  • I've no idea what you think inspect.cleandoc does, but it does not do that.
  • Python generally avoids magic, meaning it really doesn't give a rat's ass about your local variables unless you specifically make it, which is not the case here. Python generally works with explicitely provided dicts (mappings of some term to its replacement).

I guess what you want here is the format/format_map methods, which do apply to format strings using {} e.g.

filein(file).format(my_var=my_var, some_var=some_var)

This can be risky if the files you're reading are under the control of a third party though: str.format allows attribute access and thus ultimately provides tools for arbitrary code execution. In that case, tools like string.Template, old-style string substitution (%) or a proper template engine might be a better idea.

2 Comments

Dear Masklinn, thanks for your comments. I have edited my question to explain how I've been using inspect.cleandoc(), as it had been removed from my previous edit. I am also reading variables from another file and I'm wondering if there is a way to use them directly instead of having to specify all of them under .format()? I appreciate your comments
The cleandoc call still makes no sense (it's the f-string which does the work). You can use format_map and give it a map (a mapping), or use "parameter unpacking" with str.format for the same effect (str.format(**params)), both require that you can get your substitutions as a Python dict somehow.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.