So I am trying to modify some json file and I want to be consistent with its own style. I managed to handle order of keys, separators, etc, but I can't print empty list across few lines (see diff image above).
Here's the code snippet I have for this task.
info = json.load(f, object_pairs_hook=OrderedDict)
# make some changes in info
f.seek(0)
f.write(json.dumps(info, separators=(',', ': '), indent=4))
f.truncate()
I thought about a workaround using .replace("[],", "[\n\n\t],"), but it's kinda dirty (and incorrect for nested stuff). Any better way to do this? (or I am missing something in the json module?)
You can update the data by adding a special string to every empty list. Then you might end up with a file containing this:
"configs": [
"MAGIC_VALUE_NOBODY_USES"
],
Then just remove the lines that contain "MAGIC_VALUE_NOBODY_USES".
You can modify the json module on your own, simply change json/encoder.py.
The function _make_iterencode is the key for the output, modify the local function _iterencode_list,
def _iterencode_list(lst, _current_indent_level):
if not lst:
if _indent is not None:
yield '[' + '\n' + (' ' * (_indent * _current_indent_level)) + ']'
else:
yield '[]'
return
# ...
Related
I have a sql query string
query_for_update =
f'''
update {db_name}.{schema_name}.{self.table_name}
set {self.updated_field} = {self.updated_field}
where {self.key_field} in ({ids});
'''
But when I try to write this query to file f.write(query_for_update) I get following result:
update store_1.dbo.[my_table]
set [Trusted Plan] = [Trusted Plan]
where [Entry No_] in (1472371,
1472375,
1472377,
1472379,
1472373,
);
Code that creates string:
ids_string = ',\n'.join(["'" + str(item) + "'" for item in result.id])
query_for_update = mssql_table.get_update_query('dbo', mssql_db_name, ids_string).strip()
with open(mssql_server_name + '.sql', 'a') as f:
f.write(query_for_update)
How can i remove indents for strings in this case?
You can use textwrap.dedent (standard library):
import textwrap
query = textwrap.dedent(f"""\
update {db_name}.{schema_name}.{self.table_name}
set {self.updated_field} = {self.updated_field}
where {self.key_field} in ({ids});
""")
print(query)
This will remove all leading spaces that are common between every line. Useful for tipple quoted strings.
You can use the str.strip() function with a for loop to fix it.
for x in list:
if x.strip():
list2.append(x)
then you can use list2 as your new usable list
you can use the str.stip method https://www.w3schools.com/python/ref_string_strip.asp
For indentations and breaks you need to consider that you might need to use \n. There is also a dedent method in the textwrap library that could be interesting for you. https://docs.python.org/3/library/textwrap.html
I hope this helps :)
I have a function to create and write some info to a .txt file. I have to write it like this:
11:13, Andrej Hlavac, Zdenka Sedlak
But instead, I get:
11:13, Andrej Hlavac, Zdenka Sedlak,
The function that writes this output is:
def write_assignments_file(assignments, header, file_name):
header[1]=str(dateTime.date(header[3],header[1],5))
header='\n'.join(header)
timetable=open(file_name,'w')
timetable.write(str(header)+'\n')
timetable.write('Timetable:'+'\n')
for i in range(len(assignments)):
for re in assignments[i]:
timetable.write(str(re)+', ')
timetable.write('\n')
timetable.close()
You're current code adds a ', ' after every element so of course there will be one at the end. The str.join(sep, it) method only puts the sep string in between each element of it.
So replace
for re in assignments[i]:
timetable.write(str(re)+', ')
with
timetable.write(', '.join(map(str, assignments[i])))
For the record, never do
for i in range(len(assignments)):
do_something(assignments[i])
instead do
for assignment in assignments:
timetable.write(', '.join(map(str, assignment)))
If you need the indices of assignments, use enumerate.
Id like to know what it takes to remove a comma from the last line within a for loop in python. When I run the script it gives me the below output(after code section). I want to remove the comma at the end of fourth line "{"{#MACRO}":"queue4"}," Please can someone help?
By the way if there is a better way to construct the block please share the ideas. I'm a beginner and like to learn. :)
Code:
import json
import urllib
import string
Url= "http://guest:guest#localhost:55672/api/queues"
Response = urllib.urlopen(Url)
Data = Response.read()
def Qlist(Name):
Text = ''' {{"{{#MACRO}}":"{Name}"}},'''.format(Name=Name)
print Text
X_json = json.loads(Data)
print '''{
"data":['''
for i in X_json:
VV = i['name']
Qlist(VV)
print ''']
}'''
Below is the Output:
{
"data":[
{"{#MACRO}":"queue1"},
{"{#MACRO}":"queue2"},
{"{#MACRO}":"queue3"},
{"{#MACRO}":"queue4"},
]
}
Thanks so much
You can modify your loop as follows.
# Create and initialize a dictionary (Associative Array)
# data['data'] is an empty list.
# Variable name (data in this case) can be anything you want.
# 'data' is a key. notice the quotations around. it's not a variable.
# I used 'data' as the key, becasue you wanted your final output to include that part.
data = {"data": []}
for i in X_json:
# We are not calling the data dictionary here.
# We are accessing the empty list we have created inside the `data` dict (above) using data['data'] syntax.
# We can use the append function to add an item to a list.
# We create a new dictionary for every `name` item found in your json array and
# append that new dictionary to the data['data'] list.
data['data'].append({"{#MACRO}": i['name']})
print(json.dumps(data))
# or print json.dumps(data, indent=True)
Read more about json.dumps() here. You can read more about python's list and dictionary here
Don't print inside Qlist - instead return a value; then you can join all returned values using comma as separator:
def Qlist(Name):
Text = ''' {{"{{#MACRO}}":"{Name}"}}'''.format(Name=Name)
return Text
print '''{
"data":[''' +
',\n'.join([ Qlist(i['name']) for i in X_json ]) +
''']
}'''
And anyway, using json.dumps is likely a better idea.
I have tried to make a Template for example.py by using string Template where I substitute each for loop elements in $i ["CA:"+$i+':'+" "]. Partially it works but substituting only the last element.
But, I want to append all the values in single line with certain format .
For example:
What my current script doing is follows:
for i in range(1,4):
#It takes each "i" elements and substituting only the last element
str='''s=selection( self.atoms["CA:"+$i+':'+" "].select_sphere(10) )
What I am getting is as follows:
s=selection( self.atoms["CA:"+3+':'+" "].select_sphere(10) )
What, I am expecting is as follows:
s=selection ( self.atoms["CA:"+1+':'+" "].select_sphere(10),self.atoms["CA:"+2+':'+" "].select_sphere(10),self.atoms["CA:"+3+':'+" "].select_sphere(10) )
My script:
import os
from string import Template
for i in range(1,4):
str='''
s=selection( self.atoms["CA:"+$i+':'+" "].select_sphere(10) )
'''
str=Template(str)
file = open(os.getcwd() + '/' + 'example.py', 'w')
file.write(str.substitute(i=i))
file.close()
I use this two scripts to get my desired output:
import os
from string import Template
a=[]
for i in range(1,4):
a.append(''.join("self.atoms["+ "'CA:' "+str(i)+""':'+" "+"]"+".select_sphere(10)"))
str='''s=selection( $a ).by_residue()'''
str=Template(str)
file = open(os.getcwd() + '/' + 'example.py', 'w')
file.write(str.substitute(a=a))
with open('example.py', 'w') as outfile:
selection_template = '''self.atoms["CA:"+{}+':'+" "].select_sphere(10)'''
selections = [selection_template.format(i) for i in range(1, 4)]
outfile.write('s = selection({})\n'.format(', '.join(selections)))
One problem is that your code, because it opens the output file with mode 'w', overwrites the file on each iteration of the for loop. That is why you only see the last one in the file.
Also I wouldn't use string.Template to perform these substitutions. Just use str.format(). Generate a list of selections and use str.join() to produce the final string:
with open('example.py', 'w') as outfile:
selection_template = 'self.atoms["CA:"+{}+":"+" "].select_sphere(10)'
selections = [selection_template.format(i) for i in range(1, 4)]
outfile.write('s = selection({})\n'.format(', '.join(selections)))
Here selection_template uses {} as a placeholder for variable substitution and a list comprehension is used to construct the selection strings. These selection strings are then joined together using the string ', ' as the separator and the resulting string inserted into the call to selection(), again using str.format().
In this example I use Python's built-in format string method, which is relatively easy to understand. If you prefer to use string templating you can easily adapt it.
The trick is to observe that there are two separate operations to perform:
Create the list of arguments
Substitute the argument list in the required output line
I use a generator-expression argument to join to achieve the necessary iteration and part 1, and then a simple string formatting to accomplish step 2.
I use the string's format method as a bound function to simplify the code by abbreviating the method calls.
main_format = '''
s = selection({})
'''.format
item_format = 'self.atoms["CA:"+{s}+\':\'+" "].select_sphere(10)'.format
items = ", ".join(item_format(s=i) for i in range(1, 4))
print(main_format(items))
So I have a bunch of line of codes like these in a row in my program:
str = str.replace('ten', '10s')
str = str.replace('twy', '20s')
str = str.replave('fy', '40s')
...
I want to make it such that I don't have to manually open my source file to add new cases. For example ('sy', '70'). I know I have to put all these in a function somehow, but I'd like to map cases that are not in my "mapper lib" from the command line. Configuration file maybe? how?
Thanks!
You could use a config file in json format like this:
[
["ten", "10s"],
["twy", "20s"],
["fy", "40s"]
]
Save it as 'replacements.json' and then use it this way:
import json
with open('replacements.json') as i:
replacements = json.load(i)
text = 'ten, twy, fy'
for r in replacements:
text = text.replace(r[0], r[1])
Then when you need to change the values just edit the replacements.json file without touching any Python code.
The format for you replacements file could be anything but json is easy to use and edit.
a simple solution could be to put those in a file, read them in your program and do your replaces in a loop..
Many ways to do this, if it's a rarely changing thing you could consider doing it with a Python dict:
mappings = {
'ten': '10s',
'twy': '20s',
'fy': '40s',
}
def replace(str_):
for s, r in mappings.iteritems():
str_.replace(s, r)
return str_
Alternatively in a Text file (make sure you use a safe delimiter which isn't used in any of the keys!)
mappings.txt
ten|10s
twy|20s
fy|40s
And the Python part:
mappings = {}
for line in open('mappings.txt'):
k, v = line.split('|', 1)
mappings[k] = v
And use the replace from above :)
You could use csv to store the replacements in a human-editable form in a file:
import csv
with open('replacements.csv', 'rb') as f:
replacements = list(csv.reader(f))
for old, new in replacements:
your_string = your_string.replace(old, new)
where replacements.csv:
ten,10s
twy,20s
fy,40s
It avoids unnecessary markup such as ", [] in the json format and allows a delimiter (,) to be present in a string itself unlike the plain text format from #WoLpH's answer.
(live example)