0

I am creating a string of a dictionary (to add to a .txt file later) in Python 3.6.6.

When I hard code the string of the dictionary, I don't get any problems:

my_string = '{"source": "s3://some_s3_bucket/random_filename.csv"} \n'
print(my_string)

outputs

{"source": "s3://some_s3_bucket/random_filename.csv"}

However, when I try to substitute the hard-coded filepath for variables, it appears that Python starts assuming that "source" is a variable I want to substitute:

bucket = "some_s3_bucket"
filename = "random_filename.csv"
my_new_string = '{"source": "s3://{0}/{1}"} \n'.format(bucket, filename)
print(my_new_string)

outputs

KeyError Traceback (most recent call last) in module
--> 1 my_new_string = '{"source": "s3://{0}/{1}"} \n'.format(bucket, filename)
      2 print(my_new_string)

KeyError: '"source"'

How should I be formatting this string for Python to properly read my bucket and filename variables?

TrentWoodbury
  • 871
  • 2
  • 13
  • 22
  • 1
    you can simply use the old way of formatting: ```my_new_string = '{"source": "s3://%s/%s"} \n' % (bucket, filename)``` – Maciek Feb 07 '20 at 11:17

5 Answers5

5

format triggers replacements on curly braces. You have a curly brace at the start of the string. Incidentally, after a field name, you can append format modifiers, separated by a colon. Consequently, everything between a curly brace and a colon is taken as a field name, and you don't have a field named "source" (together with the quotes).

To output a curly brace, double it:

my_new_string = '{{"source": "s3://{0}/{1}"}} \n'.format(bucket, filename)

but Talon's comment is right, using json module would be better than making JSON by hand, since the variables' values might need escaping, in the general case. Since you will then have no braces you'd need to output, your format problem disappears:

import json
my_new_string = json.dumps({"source": "s3://{0}/{1}".format(bucket, filename) })
Amadan
  • 191,408
  • 23
  • 240
  • 301
  • I appreciate you explaining why I should be using json.dumps() instead of just appending to the string. I changed my code to do that. And thank you for the fix! – TrentWoodbury Feb 07 '20 at 11:11
1

You are using string format so you have to use double {{ data }}

In [1]: bucket = "some_s3_bucket" 
   ...: filename = "random_filename.csv" 
   ...: my_new_string = '{{"source": "s3://{0}/{1}"}} \n'.format(bucket, filename) 
   ...: print(my_new_string)                                                                                                                          
{"source": "s3://some_s3_bucket/random_filename.csv"\}

Check this for more information How can I print literal curly-brace characters in python string and also use .format on it?

Alif Jahan
  • 793
  • 1
  • 7
  • 20
1

str.format() uses {} characters as placeholders for parameters to be formatted. You used { at the beginning of your format string, and that causes the problem. What you want to do is to use double braces {{ & }} where they need to be taken as literal braces rather than substituted:

my_new_string = '{{"source": "s3://{0}/{1}"}} \n'.format(bucket, filename)

Besides, this is a poor way to generate JSON data (see the comment by Talon).

Błotosmętek
  • 12,717
  • 19
  • 29
0

The problem is those { and } characters you have there that don't specify a key for formatting.

bucket = "some_s3_bucket"
filename = "random_filename.csv"
my_new_string = '{{"source": "s3://{0}/{1}"}} \n'.format(bucket, filename)
print(my_new_string)
Aditya
  • 19
  • 5
0

the problem is with the curly braces using:

my_new_string = '{{"source": "s3://{}/{}"}}'.format(bucket, filename)

outputed this

{"source": "s3://some_s3_bucket/random_filename.csv"}

Simone
  • 813
  • 8
  • 21