The official solution (Python 3 Docs) for strings in format mappings is to subclass the dict class and to define the magic-method __missing__(). This method is called whenever a key is missing, and what it returns is used for the string formatting instead:

class format_dict(dict):
    def __missing__(self, key):
        return "..."

d = format_dict({"foo": "name"})

print("My %(foo)s is %(bar)s" % d) # "My name is ..."

print("My {foo} is {bar}".format(**d)) # "My name is ..."

Edit: the second print() works in Python 3.5.3, but it does not in e.g. 3.7.2: KeyError: 'bar' is raised and I couldn't find a way to catch it.

After some experiments, I found a difference in Python's behavior. In v3.5.3, the calls are __getitem__(self, "foo") which succeeds and __getitem__(self, "bar") which can not find the key "bar", therefore it calls __missing__(self, "bar") to handle the missing key without throwing a KeyError. In v3.7.2, __getattribute__(self, "keys") is called internally. The built-in keys() method is used to return an iterator over the keys, which yields "foo", __getitem__("foo") succeeds, then the iterator is exhausted. For {bar} from the format string there is no key "bar". __getitem__() and hence __missing_() are not called to handle the situation. Instead, the KeyError is thrown. I don't know how one could catch it, if at all.

In Python 3.2+ you should use format_map() instead (also see Python Bug Tracker - Issue 6081):

from collections import defaultdict
    
d = defaultdict(lambda: "...")
d.update({"foo": "name"})

print("My {foo} is {bar}".format_map(d)) # "My name is ..."

If you want to keep the placeholders, you can do:

class Default(dict):
    def __missing__(self, key): 
        return key.join("{}")
    
d = Default({"foo": "name"})

print("My {foo} is {bar}".format_map(d)) # "My name is {bar}"

As you can see, format_map() does call __missing__().

The following appears to be the most compatible solution as it also works in older Python versions including 2.x (I tested v2.7.15):

class Default(dict):
    def __missing__(self, key):
        return key.join("{}")

d = Default({"foo": "name"})

import string
print(string.Formatter().vformat("My {foo} is {bar}", (), d)) # "My name is {bar}"

To keep placeholders as-is including the format spec (e.g. {bar:<15}) the Formatter needs to be subclassed:

import string

class Unformatted:
    def __init__(self, key):
        self.key = key
    def __format__(self, format_spec):
        return "{{{}{}}}".format(self.key, ":" + format_spec if format_spec else "")

class Formatter(string.Formatter):
    def get_value(self, key, args, kwargs):
        if isinstance(key, int):
            try:
                return args[key]
            except IndexError:
                return Unformatted(key)
        else:
            try:
                return kwargs[key]
            except KeyError:
                return Unformatted(key)


f = Formatter()
s1 = f.vformat("My {0} {1} {foo:<10} is {bar:<15}!", ["real"], {"foo": "name"})
s2 = f.vformat(s1, [None, "actual"], {"bar":"Geraldine"})
print(s1) # "My real {1} name       is {bar:<15}!"
print(s2) # "My real actual name       is Geraldine      !"

Note that the placeholder indices are not changed ({1} remains in the string without a {0}), and in order to substitute {1} you need to pass an array with any odd first element and what you want to substitute the remaining placeholder with as second element (e.g. [None, "actual"]).

You can also call the format() method with positional and named arguments:

s1 = f.format("My {0} {1} {foo:<10} is {bar:<15}!", "real", foo="name")
s2 = f.format(s1, None, "actual", bar="Geraldine")
Answer from CodeManX on Stack Overflow
Top answer
1 of 4
24

The official solution (Python 3 Docs) for strings in format mappings is to subclass the dict class and to define the magic-method __missing__(). This method is called whenever a key is missing, and what it returns is used for the string formatting instead:

class format_dict(dict):
    def __missing__(self, key):
        return "..."

d = format_dict({"foo": "name"})

print("My %(foo)s is %(bar)s" % d) # "My name is ..."

print("My {foo} is {bar}".format(**d)) # "My name is ..."

Edit: the second print() works in Python 3.5.3, but it does not in e.g. 3.7.2: KeyError: 'bar' is raised and I couldn't find a way to catch it.

After some experiments, I found a difference in Python's behavior. In v3.5.3, the calls are __getitem__(self, "foo") which succeeds and __getitem__(self, "bar") which can not find the key "bar", therefore it calls __missing__(self, "bar") to handle the missing key without throwing a KeyError. In v3.7.2, __getattribute__(self, "keys") is called internally. The built-in keys() method is used to return an iterator over the keys, which yields "foo", __getitem__("foo") succeeds, then the iterator is exhausted. For {bar} from the format string there is no key "bar". __getitem__() and hence __missing_() are not called to handle the situation. Instead, the KeyError is thrown. I don't know how one could catch it, if at all.

In Python 3.2+ you should use format_map() instead (also see Python Bug Tracker - Issue 6081):

from collections import defaultdict
    
d = defaultdict(lambda: "...")
d.update({"foo": "name"})

print("My {foo} is {bar}".format_map(d)) # "My name is ..."

If you want to keep the placeholders, you can do:

class Default(dict):
    def __missing__(self, key): 
        return key.join("{}")
    
d = Default({"foo": "name"})

print("My {foo} is {bar}".format_map(d)) # "My name is {bar}"

As you can see, format_map() does call __missing__().

The following appears to be the most compatible solution as it also works in older Python versions including 2.x (I tested v2.7.15):

class Default(dict):
    def __missing__(self, key):
        return key.join("{}")

d = Default({"foo": "name"})

import string
print(string.Formatter().vformat("My {foo} is {bar}", (), d)) # "My name is {bar}"

To keep placeholders as-is including the format spec (e.g. {bar:<15}) the Formatter needs to be subclassed:

import string

class Unformatted:
    def __init__(self, key):
        self.key = key
    def __format__(self, format_spec):
        return "{{{}{}}}".format(self.key, ":" + format_spec if format_spec else "")

class Formatter(string.Formatter):
    def get_value(self, key, args, kwargs):
        if isinstance(key, int):
            try:
                return args[key]
            except IndexError:
                return Unformatted(key)
        else:
            try:
                return kwargs[key]
            except KeyError:
                return Unformatted(key)


f = Formatter()
s1 = f.vformat("My {0} {1} {foo:<10} is {bar:<15}!", ["real"], {"foo": "name"})
s2 = f.vformat(s1, [None, "actual"], {"bar":"Geraldine"})
print(s1) # "My real {1} name       is {bar:<15}!"
print(s2) # "My real actual name       is Geraldine      !"

Note that the placeholder indices are not changed ({1} remains in the string without a {0}), and in order to substitute {1} you need to pass an array with any odd first element and what you want to substitute the remaining placeholder with as second element (e.g. [None, "actual"]).

You can also call the format() method with positional and named arguments:

s1 = f.format("My {0} {1} {foo:<10} is {bar:<15}!", "real", foo="name")
s2 = f.format(s1, None, "actual", bar="Geraldine")
2 of 4
20

str.format() doesn't expect a mapping object. Try this:

from collections import defaultdict

d = defaultdict(str)
d['error2'] = "success"
s = "i am an {0[error]} example string {0[error2]}"
print s.format(d)

You make a defaultdict with a str() factory that returns "". Then you make one key for the defaultdict. In the format string, you access keys of the first object passed. This has the advantage of allowing you to pass other keys and values, as long as your defaultdict is the first argument to format().

Also, see http://bugs.python.org/issue6081

Discussions

KeyError in string format when curlies { } present
I'm running into the same problem as #767 and used a similar fix, but one that still tries to do the formatting. So my message is Retrying timed. .wrapped_fn in 0.9077886023569136 ... More on github.com
🌐 github.com
14
October 18, 2023
Python format throws KeyError - Stack Overflow
The following code snippet: template = "\ function routes(app, model){\ ... More on stackoverflow.com
🌐 stackoverflow.com
Format function: Fill missing keys with empty string
Python has default dict, where it returns a default value on non-existing keys: >>> from collections import defaultdict >>> dd = defaultdict(list) >>> dd["nosuchkey"] [] More on reddit.com
🌐 r/learnpython
4
2
February 5, 2020
python - Ignore KeyError and continue program - Stack Overflow
In Python 3 I have a program coded as below. It basically takes an input from a user and checks it against a dictionary (EXCHANGE_DATA) and outputs a list of information. from shares import More on stackoverflow.com
🌐 stackoverflow.com
🌐
AskPython
askpython.com › home › using python string format_map()
Using Python String format_map() - AskPython
August 6, 2022 - Well, format() does not handle this for us, and it simply raises a KeyError exception. This is because it copies the mapping to a new dictionary object. Because the mapping is on a new dictionary object (not using our subclass), it does not ...
🌐
Python
docs.python.org › 3.0 › library › string.html
string — Common string operations — Python v3.0.1 documentation
December 18, 2020 - Like substitute(), except that if placeholders are missing from mapping and kws, instead of raising a KeyError exception, the original placeholder will appear in the resulting string intact.
🌐
GitHub
github.com › Delgan › loguru › issues › 1008
KeyError in string format when curlies { } present · Issue #1008 · Delgan/loguru
October 18, 2023 - class SafeDict(dict): def __missing__(self, key): return '{' + key + '}' ... try: log_record["message"] = message.format(*args, **kwargs) except (KeyError, IndexError): # KeyError from { missing_key } in message, IndexError from missing positional ...
Author   Delgan
Find elsewhere
🌐
Reddit
reddit.com › r/learnpython › format function: fill missing keys with empty string
r/learnpython on Reddit: Format function: Fill missing keys with empty string
February 5, 2020 -

Hey guys,

I'm working in a very specific enviroment and I have a scheme file where I replace keys with the format function. The file might look like this:

1: {code1}
2: {code2}
3: {code3}

I want that other persons can change the format file and add {code} tags. My program uses this file and replaces the values, but the amount of {code} blocks varies.

So at the moment I generate a dict with the code tags, and replace them in that string (which got loaded from the file)

code_tags = {"code1": "ABC", "code2": "DEF"}
file_content.format(**code_tags)

A problem occurs when there are more keys in the scheme file than keys generated from my program (KeyError). How can I put in an empty string for tags which got not specified in code_tags?

I thought about crawling the file and find every tag, compare, and add missing to the dict with and emptry string. But that's kinda hask-ish and maybe not the cleanest style.

How would you solve the problem?

🌐
Aquiles
notes.aquiles.me › tech_notes › python_partial_string_formatting
Formatting strings in two steps with Python | Aquiles Carattino
July 8, 2020 - The thing is that I want to format the string using only val1 and leaving the part concerning val2 intact, because that will be passed down to some other code. Basically, I want this: ... But if we try, we get a KeyError because val2 is missing. This means that Python is using a dictionary to handle the formatting, and if we could somehow get in between, we can actually skip the error and return the unformatted part of the string.
🌐
GitHub
github.com › pypa › cibuildwheel › issues › 840
Do not use Python's str.format() for expanding placeholders in commands · Issue #840 · pypa/cibuildwheel
September 22, 2021 - Placeholders in command environment ... using Python's str.format(): https://github.com/pypa/cibuildwheel/blob/main/cibuildwheel/util.py#L41 · This makes it (nearly) impossible to use curly braces in a command, because a pair of single braces will throw a KeyError exception ...
Author   pypa
Top answer
1 of 4
9

You can use Template and safe_substitute for that:

from string import Template

practise_dict = {"Additional_Details":"blah blah blah blah", "Title": "Mr", "Surname": "Smith", "URL": "/test/tester"}

msg = """From: John Smith <[email protected]>
To: $Title $Surname <[email protected]>
MIME-Version: 1.0
Content-type: text/html
Subject: New Website Enquiry
This is an e-mail message to be sent in HTML format
$Additional_Details
$Date
<b>This is HTML message.</b>
<h1>This is headline.</h1>
`"""

s = Template(msg).safe_substitute(**practise_dict)
print(s)

OUTPUT

From: John Smith <[email protected]>
To: Mr Smith <[email protected]>
MIME-Version: 1.0
Content-type: text/html
Subject: New Website Enquiry
This is an e-mail message to be sent in HTML format
blah blah blah blah
$Date
<b>This is HTML message.</b>
<h1>This is headline.</h1>
2 of 4
2

I don't think there's a way to tell format that some substitutions are optional. However, here are two workarounds.

If there's only one missing field, try something like:

msg = """...""".format(Date=practise_dict.pop("Date", ""), # handle optional field
                       **practise_dict) # pass the rest as before

However, note that this modifies practise_dict, and will be awkward if there are several values to deal with.

If there may be multiple fields missing, or you don't want to modify the dictionary, the following would probably be preferable:

defaults = {"Date": "", "Additional Details": ""} # define optional fields
defaults.update(practise_dict) # override user data where available
msg = """...""".format(**defaults)

Both approaches will still fail for keys you haven't explicitly provided an alternative for, which allows you to make some fields mandatory.

🌐
Python.org
discuss.python.org › python help
Please help: Key Error: ' ' - Python Help - Discussions on Python.org
June 8, 2021 - Hello I am new to learning the Python language and I am currently teaching myself by going through a ten-week bootcamp book for beginners. I have encounter this error: Key Error: ’ ’ The book utilises Python 3.7 and…
🌐
Reddit
reddit.com › r/learnpython › keyerror: '\n type'
r/learnpython on Reddit: KeyError: '\n type'
November 10, 2022 -

Hey I've been working on a project and I came across a error of: KeyError: '\n type'

I've been looking online for solutions but I've only found KeyError: '\n' (without the 'type' and none of the solutions work). What I'm trying to do is take a list and get a chart back from quickchart.io. Its worked fine without using variable data, but now that im trying to it isn't working.

My code:

import quickchart from QuickChart
coins = ['1','2','3','4','5']
bags = ['1','2','3','4','5']
cash = ['1','2','3','4','5']
qc = QuickChart()
qc.width = 1000
qc.height = 600
qc.version = "2"
qc.config = '''{
        type: 'line',
        data: {
          labels: ['24hrs', '18hrs', '12hrs', '6hrs', 'now'],
          datasets: [
            {
              label: 'coins',
              borderColor: 'rgb(255, 99, 132)',
              backgroundColor: 'rgba(255, 99, 132, .5)',
              data: {},
            },
            {
              label: 'bags',
              borderColor: 'rgb(54, 162, 235)',
              backgroundColor: 'rgba(54, 162, 235, .5)',
              data: {},
            },
            {
              label: 'cash',
              borderColor: 'rgb(75, 192, 192)',
              backgroundColor: 'rgba(75, 192, 192, .5)',
              data: {},
            },
          ],
        },
        options: {
          responsive: true,
          title: {
            display: true,
            text: 'Stock Market',
          },
          tooltips: {
            mode: 'index',
          },
          hover: {
            mode: 'index',
          },
          scales: {
            xAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Time Since',
                },
              },
            ],
            yAxes: [
              {
                stacked: true,
                scaleLabel: {
                  display: true,
                  labelString: 'Value',
                },
              },
            ],
          },
        },
      }'''.format(coins, bags, cash) #This is the line causing the error according to my console

the indents in the stringed-dict may be stuffed up from copy and paste, but hopefully that doesn't cause an issue for you.

I've also tried doing :

...
data: ['{}','{}','{}','{}','{}']
...
}'''.format(coins[0], coins[1]) #and so on

which has the same error

In case you need it, is the documentation for quickchart (https://quickchart.io/documentation/)

let me know if you need other information, I'd be happy to give it to you.

🌐
GitHub
github.com › hwchase17 › langchain › issues › 7079
KeyError when formatting FewShotPromptTemplate · Issue #7079 · langchain-ai/langchain
July 3, 2023 - KeyError Traceback (most recent call last) Cell In[1], line 56 53 new_doc = "Kate McConnell is 56 and is soon retired according to the current laws of the state of Alaska in which she resides." 54 new_entities_to_extract = ['name', 'organization'] ---> 56 prompt = few_shot_prompt_template.format( 57 input_doc=new_doc, 58 entities_to_extract=new_entities_to_extract, 59 answer={} 60 ) File [~/Desktop/automarkup/.venv/lib/python3.9/site-packages/langchain/prompts/few_shot.py:123](https://file+.vscode-resource.vscode-cdn.net/Users/username/Desktop/automarkup/src/~/Desktop/automarkup/.venv/lib/python3.9/site-packages/langchain/prompts/few_shot.py:123), in FewShotPromptTemplate.format(self, **kwargs) 120 template = self.example_separator.join([piece for piece in pieces if piece]) 122 # Format the template with the input variables.
Author   langchain-ai
🌐
Reddit
reddit.com › r/learnpython › how to get .format() to ignore a specific {} that is in a string?
r/learnpython on Reddit: How to get .format() to ignore a specific {} that is in a string?
July 14, 2018 -

I have a text file that gets read in to the program, and it also contains a JSON file.

An example of what I'm talking about is this:

Hello, {}. Welcome to /r/{}. This is a JSON file.

---

{ 
    "key": "value"
}

That is stored in a text file that we will call example.txt. I read the file in as such:

def read_text_file(file_name):
    with open(file_name, "r") as file:
        return file.read()

my_string = read_text_file("example.txt")
formatted_string = my_string.format(username, subreddit)

However, because the dictionary also has a {} in it, .format() seems to expect a third argument with .format(). Is there a way to make it ignore the third one so that I don't get a KeyError exception?

🌐
STechies
stechies.com › python-keyerror
Python KeyError Exceptions - How to Resolve it with Example
Try and except block will help you to avoid the keyError. The try and except is the keyword. Try block statements will execute first then except. Everything executed well then except block will ignore.
🌐
Stack Overflow
stackoverflow.com › questions › 66264405 › how-to-ignore-keyerror-in-my-case-python
list - How to ignore KeyError in my case? (Python) - Stack Overflow
employees = 0 if str(json_data['context']['dispatcher']['stores']['QuoteSummaryStore']['assetProfile']['fullTimeEmployees']) != KeyError: employees = str(json_data['context']['dispatcher']['stores']['QuoteSummaryStore']['assetProfile']['ful...