Python - KeyError while creating an index - python

Here is the code (it runs inside class):
if profile['profile_picture']:
profile['profile_picture_raw_path'], # Line 26
profile['profile_picture_thumbnail'],
profile['profile_picture'] = self.picture_path(profile['profile_picture'])
Keys don't exist. The typical result returned by picture_path is
('//domain.com/218971848/21924823397471f5e4e41a803da17f7c.jpg:large', '//domain.com/profile-images/218971848/21924823397471f5e4e41a803da17f7c.jpg:thumb-100', '//domain.com/profile-images/218971848/21924823397471f5e4e41a803da17f7c.jpg:exact')
As you can see the result is a tuple of 3 elements.
And I got an error:
File "/srv/rwt/production/application/rwt/profile.py", line 26, in load_profile
profile['profile_picture_raw_path'],
KeyError: 'profile_picture_raw_path'
Why does this error appear? Searched Stack Overflow for similar questions, but they seem to be asked about accessing dictionary values by not-existing keys.

profile['profile_picture_raw_path'], on a line by itself is parsed as a standalone expression (a rather useless one, though).
You need to tell the Python interpreter that the next lines are part of the expression:
profile['profile_picture_raw_path'], \
profile['profile_picture_thumbnail'], \
profile['profile_picture'] = self.picture_path(profile['profile_picture'])

use a bracket
if profile['profile_picture']:
(profile['profile_picture_raw_path'], # Line 26
profile['profile_picture_thumbnail'],
profile['profile_picture']) = self.picture_path(profile['profile_picture'])

Related

Python list(?) sending incorrect number of values to other program

I have been trying to upload close to a thousand SVG files to a particular program (FontForge) and as such searched for a way to automate it. Unfortunately I am really unfamiliar with Python, to the extent that I'm not sure if what I changed about the code ended up changing something fundamental.
The original code you were meant to individually continue the table that the original coder left with the file name and glyph names of the SVG files. This would require doing it manually, as I realized quickly it wouldn't allow loops within the brackets itself. The original code was as follows, albeit with more items:
select = [
('null', 'null'),
('bs-info-circle', 'infoCircle'),
]
Looking at it, and with a lot of googling and experimentation, I guessed that it was a list of tuples. As such, I created various loops adding onto a toSelect list that I created. Since they are rougly the same I'll just show one here:
for x in svc:
icon="svc-"+x+"con_lang"
glyph=x
#print((icon, glyph))
toSelect.extend(((icon, glyph),)) #comma necessary to force it to add in a pair, rather than individually
The variable svc is a list of strings: ['ba', 'be', 'bi', 'bo'...] pulled from a TXT file. The variable toSelect, when printed, looks as follows:
[('svc-bacon_lang', 'ba'), ('svc-becon_lang', 'be'), ('svc-bicon_lang', 'bi'), ...]
Long story short, I now have a list that seems to be formatted the same as the contents of the original code. As such, I set it equal in a simple manner:
select = toSelect
However, running the build program that pulls from this code is giving the following error message:
Traceback (most recent call last):
File "C:\Users\*****\Downloads\ff-batch-main\ff-batch-main\build.py", line 392, in <module>
run_fontforge(config)
File "C:\Users\*****\Downloads\ff-batch-main\ff-batch-main\build.py", line 148, in run_fontforge
for key, name in config.select:
ValueError: not enough values to unpack (expected 2, got 1)
I have tried every variation of declaring select that I can, including a few that cause the following error message:
Traceback (most recent call last):
File "C:\Users\*****\Downloads\ff-batch-main\ff-batch-main\build.py", line 392, in <module>
run_fontforge(config)
File "C:\Users\*****\Downloads\ff-batch-main\ff-batch-main\build.py", line 148, in run_fontforge
for key, name in config.select:
ValueError: too many values to unpack (expected 2)
Printing the value of select[0] does seem to tell me that that error is caused by all of the entries being considered one entry on the list? So at least I know that.
Still, I can't figure out why it doesn't take my original attempt, as select[0] = ('null', 'null'). I'm worried that select isn't supposed to be a list at all, but is something different that I'm simply unfamiliar with since I do not know python. Is this some sort of function that I broke by adding items sequentially instead of all at once?
I will also show the code from the 'build' program that is flagged as the problem. The only thing that I edited was the 'config' program, as instructed by the coder, but hopefully this at least will give context?
def run_fontforge(config):
from icon_map import maps
try:
from select_cache import maps as icons
except:
icons = {}
print(f"Generating fonts => {config.build_dir}/{config.font_name}.ttf")
with open('select_cache.py', 'w') as f:
f.write("# SVG to Font Icon mapping\n")
f.write(f"# Generated: {datetime.now()}\n")
f.write("maps = {\n")
last = config.font_start_code - 1
for _,m in icons.items():
last = max(last, m['code'])
last += 1
for key, name in config.select:
icon = icons.get(key)
src = maps.get(key)
So yeah. Um, any advice or explanations would be greatly appreciated, and I'll do my best to give additional information when possible? Unfortunately I started trying to understand Python yesterday and am coming at this from a rusty knowledge of java so I am not really fluent, might not know terms and whatnot. I just wanted to import some files man...
You've gotten quite far just 1 day into Python.
My hypothesis for the bug is config.select not containing the toSelect data.
Ways to investigate:
Interactively run this to verify that toSelect is a list of pairs:
for k, n in toSelect: pass
print both variables, or interactively evaluate config.select == toSelect to compare them, or set breakpoints in the PyCharm or VSCode debugger and examine these variables.
Is this some sort of function that I broke by adding items sequentially instead of all at once?
No.
BTW, you can make:
toSelect.extend(((icon, glyph),))
easier to understand by writing it as:
toSelect.append((icon, glyph))
Bonus: The most "Pythonic" way to write that for loop is as a list comprehension:
toSelect = [("svc-"+x+"con_lang", x) for x in svc]

How can I remove a JSON object via array? (Python)

I know the title looks a little confusing but once I share the code you'll know what I am talking about. I am fairly new to working with JSON and Python overall. I'm trying to make a grocery list program with 3 simple commands: list, add, and remove. List will list all of your groceries that you added via add. Remove removes an item by name. This is where I'm having trouble. This is what my setup looks like:
{"grocery_list":
[{"itemname": "Milk"},
{"itemname": "Bread"},
{"itemname": "Bacon"}]
}
This is my remove function and data:
with open('groceriesjson.json','r') as data_file:
data = json.load(data_file)
def removeitem(item):
global data
for i in range(len(data)):
if data[i]["itemname"] == item:
data.pop(i)
print("Successfully removed from your list.")
main()
When I run the program, I get this error:
Traceback (most recent call last):
File "C:\Users\me\Desktop\test.py", line 48, in <module>
main()
File "C:\Users\me\Desktop\test.py", line 44, in main
removeitem(toremove)
File "C:\Users\me\Desktop\test.py", line 18, in removeitem
if data[i]["itemname"] == item:
KeyError: 0
I have also tried using range(1,len(data)) but when I run it nothing happens. If you need any more snippets of code or anything else please comment. Thanks a lot
You can instead use a list comprehension
values = {
"grocery_list": [
{"itemname": "Milk"},
{"itemname": "Bread"},
{"itemname": "Bacon"}
]
}
print({
"grocery_list":
[v for v in values['grocery_list'] if v['itemname'] != 'Milk']
})
You have failed to test your program in stages; you now have multiple mistakes to correct. See this lovely reference for debugging help. If nothing else, insert frequent print commands to check your assumptions about data types and values.
You do not have a "JSON object"; you have a Python dict. For a better example, remove the input sequence and replace it with the hard-coded dict equivalent. The first step of debugging is to isolate the problem, and this demonstrates that the input is independent.
Now, look at your structure: the dict has one entry, keyed by the string "grocery_list". Your immediate error is that you tried to access this as a list, using subscript 0. This would work well with the next level down, data["grocery_list"], as that is a list.
Next, you will run into problems when you alter a list while you iterate over it. See the related questions on that topic for pointers. The "normal" way is to use a list comprehension, as you see in Sushanth's answer.
You call a routine main from within your removal loop; this is almost certainly a mistake, especially if that routine is, indeed, your main program. Put in print statements and follow the logic to see how this actually works.
Maybe something like this:
def removeitem(del_item):
global data
grocery_list = data['grocery_list']
for i, item in enumerate(grocery_list):
if item["itemname"] == del_item:
grocery_list.pop(i)
print("Successfully removed from your list.")
break
return grocery_list

Type error that shows on console, but not on pythontutor.com

Ok, so I have a block of code that I am trying to debug, and I usually use Pythontutor.com to step through the code to see where it is going wrong. Problem is, the exact code works on the website, but not in my console.
row = []
row.append("Acid Arrow")
testList = ['Detect', 'Discern', 'Summon', 'Call', 'Binding']
nameList = row[0].split(' ')
print testList, nameList
a = list(set(testList) & set(nameList))
The error I am getting is this:
C:\Users\User\Dropbox\D&D\SpellBag>livingSpell.py
['Detect', 'Discern', 'Summon', 'Call', 'Binding'] ['Acid', 'Arrow']
Traceback (most recent call last):
File "C:\Users\User\Dropbox\D&D\SpellBag\livingSpell.py", line 121, in <module>
sb = spellBook(r'allSpells.csv')
File "C:\Users\User\Dropbox\D&D\SpellBag\livingSpell.py", line 27, in __init__
a = list(set(testList) & set(nameList))
TypeError: 'str' object is not callable
The above code works flawlessly on PythonTutor, but fails when I run it in the console. What it is intended to do is check if a word from the list is in the spell name, which if any of them are, the spell is passed over and it moves on. It should be returning an empty list, but instead I get the error.
The line that has the error is a = list(set(testList) & set(nameList)), and the error says "'str' object is not callable." This means the Python interpreter tried to call a function and found out it wasn't actually a function. This is the same error you would get if you typed "bad_code"(), since the string "bad_code" is not a function.
It's impossible to say exactly which of the two is having an issue, but either list or set has been overwritten and is now a string rather than the default functions provided in Python. That snippet of code works fine by itself in pythontutor.com because the offending line of code happens somewhere before it in your file (the error says you have 22 lines of code beforehand). In fact, if you started a blank file and only had the snippet you posted here on StackOverflow, it would run perfectly. Check for anything like list = ... or set = ... in your original source code.
It is a somewhat common convention in Python to avoid naming conflicts with reserved words (list, set, or, if, with, while, etc...) by appending an underscore to the name. In this case, that would mean writing either list_ = ... or set_ = .... A good coding practice in general though would be to come up with a specific name for your variable that describes it exactly. For example, you might use used_spell_list instead of list (just guessing...I have no idea how this was overwritten).

Trying to edit private dicom tag

I'm currently trying to edit a private dicom tag which is causing problems with a radiotherapy treatment, using pydicom in python. Bit of a python newbie here so bear with me.
The dicom file imports correctly into python; I've attached some of the output in the first image from the commands
ds = dicomio.read_file("xy.dcm")
print(ds)
This returns the following data:
pydicom output
The highlighted tag is the one I need to edit.
When trying something like
ds[0x10,0x10].value
This gives the correct output:
'SABR Spine'
However, trying something along the lines of
ds[3249,1000]
or
ds[3249,1000].value
returns the following output:
> Traceback (most recent call last):
File "<pyshell#64>", line 1, in <module>
ds[3249,1000].value
File "C:\Users\...\dataset.py", line 317, in __getitem__
data_elem = dict.__getitem__(self, tag)
KeyError: (0cb1, 03e8)
If I try accessing [3249,1010] via the same method, it returns a KeyError of (0cb1, 03f2).
I have tried adding the tag to the _dicom_dict.py file, as highlighted in the second image:
end of _dicom_dict.py
Have I done this right? I'm not even sure if I'm accessing the tags correctly - using
ds[300a,0070]
gives me 'SyntaxError: invalid syntax' as the output, for example, even though this is present in the file as fraction group sequence. I have also been made aware that [3249,1000] is connected to [3249,1010] somehow, and apparently since they are proprietary tags, they cannot be edited in Matlab, however it was suggested they could be edited in python for some reason.
Thanks a lot
It looks like your dicomio lookup is converting all inputs to hexadecimal.
You could try:
ds[0x3249,0x1000]
This should prevent any forced conversion to hexadecimal.
You can apparently access them directly as strings:
ds['3249', '1000']
However, your issue is that you are trying to access a data element that is nested several layers deep. Based on your output at the top, I would suggest trying:
first_list_item = ds['300a', '0070'][0]
for item in first_list_item['300c', '0004']:
print(item['3249','1000'])
Essentially, a data element from the top level Dataset object can be either a list or another Dataset object. Makes parsing the data a little harder, but probably unavoidable.
Have a look at this for more info.
As Andrew Guy notes in his last comment, you need to get the first sequence item for 300a,0070. Then get the second sequence item from the 300c,0004 sequence in that item. In that sequence item, you should be able to get the 3249,1000 attribute.

Writing tabs in a specific way (Not from lists) in python

I am new to Python and went through many posts regarding the question I am about to ask. If it is a duplicate, please feel free to put on hold.
Question : To write a file with tabs and multiple values (not from a list), i used the following snipet
for line in open("dat.Zmine"):
if "Zavg" in line:
char = line.split()[0]
value = line.split()[1]
fidzavg.write(str(stepval*filenum))
fidzavg.write("\t")
fidzavg.write(value)
fidzavg.write("\n")
where fidzavg is the file id . It looks a bit tedious as opposed to say in C++
printf(fidzavg,"%g\t%g\n", stepval*filenum, value)
Can i reduce the python snippet to something simular that I put for C++?
Any help will be appreciated.
You can do almost exactly the same thing in Python:
fidzavg.write("%g\t%g\n" % (stepval*filenum, float(value)))
or use str.format:
fidzavg.write("{0:g}\t{1:g}\n".format(stepval*filenum, float(value)))
Note that your assignment from the line can be simplified using slicing and tuple (un)packing:
char, value = line.split()[:2]

Categories