Python3 Trace back issue - python-3.x

First, let me disclaim that I am extremely new to the coding world and work requires me to use Python going forward. My experience is limited to having just completed SANS 573.
I'm trying to obtain the Date and Time from image files in their various formats. Excuse the example, I'm just using this to try and get it working.
This what I currently have:
from pathlib import Path
from PIL import Image
L88 = Path("L88.jpg")
def corvette(L88):
imgobj=Image.open(L88)
info=imgobj._getexif()
return info[36867]
>>> corvette(L88)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in corvette
KeyError: 36867
>>>
I am running the function from the desktop which is where I have the image currently saved.
I don't understand the error messages.
KeyError: 36867 also has me confused too as when I looked up the tag, that is what I found and what worked when I just did my course.

The _getexif() method returns a Python datastructury called a dictionary.
The values in a dictionary are accessed by their key.
In this case, the keys are numbers.
Not all keys are mandatory. You can use the keys() method to see which ones exist. Try:
print(info.keys())
to see which keys exist.
You can also test if a key exists:
if 36867 in info:
return info[36867]
else:
return None
Note that there is a mapping between these numbers and their exif tags names available.
You can use that to create a readable dictionary.
Note that not all JPEG images have EXIF information. In that case, the _getexif() method returns None, so you should take that into account and test for that:
from PIL import Image, ExifTags
def image_info(path):
imgobj = Image.open(path)
info = imgobj._getexif()
if info is None:
return None
rv = {
ExifTags.TAGS[key]: info[key]
for key in info.keys()
}
return rv

Related

Why can't get price pair (USDT/KGS, USDT/KZT) by ticker in BINANCE API?

`So, this is my code
# Import libraries
import json
import requests
# defining key/request url
key = "https://api.binance.com/api/v3/ticker/price?symbol=USDTKGS"
# requesting data from url
data = requests.get(key)
data = data.json()
print(f"{data['symbol']} price is {data['price']}")
But for some reason I get this error:
Traceback (most recent call last):
File "rate.py", line 11, in <module>
print(f"{data['symbol']} price is {data['price']}")
KeyError: 'symbol'
Probably, this pair doesn't exist, but what to do in such situation?
I need to get the pair by API, but don't see any other ways to do so...
Please, help me!
I tried to use usual pairs like USDT/UAH, EUR/USDT - they work
But USDT/KGS, USDT/KZT doesn't work - they print error, but I need to get it
There is no such pair in Binance API currently (12/10/2022)

Calling a function, that yields, twice

Working with python3, I had a requirement:
Perform some pre-work
Do the core work
Cleanup the pre-work
Taking inspiration from fixtures in pytest I came across this post and wrote some crazy code.
Though this crazy code works, I wish to understand the yield sorcery that makes it working :)
def db_connect_n_clean():
db_connectors = []
def _inner(db_obj):
db_connectors.append(db_obj)
print("Connect : ", db_obj)
yield _inner
for conn in db_connectors:
print("Dispose : ", conn)
This is the driver code:
pre_worker = db_connect_n_clean()
freaky_function = next(pre_worker)
freaky_function("1")
freaky_function("2")
try:
next(pre_worker)
except:
pass
It produces this output:
Connect : 1
Connect : 2
Dispose : 1
Dispose : 2
Traceback (most recent call last):
File "junk.py", line 81, in <module>
next(pre_worker)
StopIteration
What confuses me in this code is, that all the calls to the same generator freaky_func is maintaining a single list of db_connectors
After the first yield, all the objects are disposed and I hit StopIteration
I was thinking that calling freaky_func twice would maintain 2 separate lists and there would be 2 separate yields
Update: The goal of this question is not to understand how to achieve this. As it is evident from the comments, context-manager is the way to go. But my question is to understand how this piece of code is working. Basically, the python side of it.
One of my favorite tools to visualize Python with is PythonTutor.
Basically, you can see that on the first run next(pre_worker) returns the _inner function. Since _inner is inside db_connect_n_clean, it can access all of its variables.
Internally, in Python, _inner contains a reference to db_connectors. You can see the reference under __closure__:
>>> gen = db_connect_n_clean()
>>> inner = next(gen)
>>> inner.__closure__
(<cell at 0x000001B73FE6A3E0: list object at 0x000001B73FE87240>,)
>>> inner.__closure__[0].cell_contents
[]
The name of the reference is the same as the variable:
>>> inner.__code__.co_freevars
('db_connectors',)
Every time this specific function, with this specific __closure__ tries to access the db_connectors, it goes to the same list.
>>> inner(1)
Connect : 1
>>> inner(2)
Connect : 2
>>> inner.__closure__[0].cell_contents
[1, 2]
The original generator gen() is still paused at the first yield:
>>> gen.gi_frame.f_lineno
6 # Gen is stopped at line #6
>>> gen.gi_frame.f_locals["db_connectors"]
[1, 2]
When you advance it again using next() it continues on from the yield and closes everything:
>>> next(gen)
Dispose : 1
Dispose : 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
If you wish to understand how do generators work in general, there are plenty of answers and articles on the subject. I wrote this one for example.
If I didn't fully explain the situation, feel free to ask for clarification in the comments!

"RuntimeError: dictionary keys changed during iteration" when attempting to call add_attachment for Jira issue object, but dictionaries aren't used?

I am attempting to just add a csv file to my issues as a test, but I keep receiving the error:
RuntimeError: dictionary keys changed during iteration
Here is the code (I've removed the parameters for server, username and password):
from jira import JIRA
options = {"server": "serverlinkgoeshere"}
jira = JIRA(options, basic_auth=('username', 'password'))
issuesList = jira.search_issues(jql_str='', startAt=0, maxResults=100)
for issue in issuesList:
with open("./csv/Adobe.csv",'rb') as f:
jira.add_attachment(issue=issue, attachment=f)
f.close()
I'm at a loss, I'm not changing any dictionary keys in my code. Here is the full error message:
Traceback (most recent call last):
File "C:/Users/USER/PycharmProjects/extractor/main/jiraCSVDupdate.py", line 8, in <module>
jira.add_attachment(issue=issue, attachment=f)
File "C:\Users\USER\AppData\Roaming\Python\Python38\site-packages\jira\client.py", line 126, in wrapper
result = func(*arg_list, **kwargs)
File "C:\Users\USER\AppData\Roaming\Python\Python38\site-packages\jira\client.py", line 787, in add_attachment
url, data=m, headers=CaseInsensitiveDict({'content-type': m.content_type, 'X-Atlassian-Token': 'nocheck'}), retry_data=file_stream)
File "C:\Users\USER\AppData\Roaming\Python\Python38\site-packages\jira\utils\__init__.py", line 41, in __init__
for key, value in super(CaseInsensitiveDict, self).items():
RuntimeError: dictionary keys changed during iteration
References:
Jira add_attachment example:
https://jira.readthedocs.io/en/master/examples.html#attachments
add_attachment source code:
https://jira.readthedocs.io/en/master/_modules/jira/client.html#JIRA.add_attachment
The root of the problem is found at jira.utils.__init__py:
for key, value in super(CaseInsensitiveDict, self).items():
if key != key.lower():
self[key.lower()] = value
self.pop(key, None)
This is a programming mistake: one should not modify the data structure that is being iterated over. Therefore, this requires a patch and must be the only accepted solution for this.
In the meantime, I suggest a monkey patch:
import jira.client
class CaseInsensitiveDict(dict):
def __init__(self, *args, **kw):
super(CaseInsensitiveDict, self).__init__(*args, **kw)
for key, value in self.copy().items():
if key != key.lower():
self[key.lower()] = value
self.pop(key, None)
jira.client.CaseInsensitiveDict = CaseInsensitiveDict
The trick here is that you iterate over a copy of your dict structure, by doing self.copy().items(), and not your original one - the self one.
For reference, my package version: jira==2.0.0.
Should be fixed from jira lib version 3.1.1 (https://github.com/pycontribs/jira/commit/a83cc8f447fa4f9b6ce55beca8b4aee4a669c098)
so assuming you use reqirements edit your requirements.txt file with
jira>=3.1.1 and install them pip install -r requirements.txt
otherwise use:
pip install jira==3.1.1
This works as a fix using Python 3.9.
The dictionary keys in the following lines in client.py in the Jira site-packages are not all lower case.
headers=CaseInsensitiveDict({'content-type': None, 'X-Atlassian-Token': 'nocheck'}))
url, data=m, headers=CaseInsensitiveDict({'content-type': m.content_type, 'X-Atlassian-Token': 'nocheck'}), retry_data=file_stream)
This works as a solution.
You can alter the dictionary keys to be all lower case. This will then allow the attachment to be added to the JIRA ticket.
headers = CaseInsensitiveDict({'content-type': None, 'x-atlassian-token': 'nocheck'}))
url, data = m, headers = CaseInsensitiveDict({'content-type': m.content_type, 'x-atlassian-token': 'nocheck'}), retry_data = file_stream)

Youtube video download using python script

i have this script for downloading the youtube video
from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=kAGacI3JwS4')
#yt.title
#yt.thumbnail_url
#yt.streams.all()
stream = yt.streams.first()
#stream
stream.download('C:\\Users\')
but i wanted this to happened based on a user prompt mode.so it should ask the user to enter the url then from there take it further and download the video,so i did like this
>>> pk=input("Enter the url:")
Enter the url:https://www.youtube.com/watch?v=GhklL_kStto
>>> pk
'https://www.youtube.com/watch?v=GhklL_kStto'
>>> pk.title
<built-in method title of str object at 0x02362770>
>>> pk.stream()
Traceback (most recent call last):
File "<pyshell#44>", line 1, in <module>
>>pk.stream()
AttributeError: 'str' object has no attribute 'stream'
so this is what the error am getting. can someone help me to solve this issue?
appreciate your support!
I hope this answer isn't too late, but the problem is that pk is a string because of this:
pk=input("Enter the url:")
pk is assiged to a string here (aka whatever you input), so there's no way you would have created the relevant Youtube object.
The description you get when you enter pk.title attests to that where it says it's a built in method of a str object. You haven't even made a YouTube object for it to have even a stream method.
You can fix it like this:
url = input("Enter the url:")
pkl = YouTube(url)
pkl.stream()
Hope this helps

Django-haystack with whoosh

I am getting
SearchBackendError at /forum/search/
No fields were found in any search_indexes. Please correct this before attempting to search.
with search_indexes placed in djangobb app root directory:
from haystack.indexes import *
from haystack import site
import djangobb_forum.models as models
class PostIndex(RealTimeSearchIndex):
text = CharField(document=True, use_template=True)
author = CharField(model_attr='user')
created = DateTimeField(model_attr='created')
topic = CharField(model_attr='topic')
category = CharField(model_attr='topic__forum__category__name')
forum = IntegerField(model_attr='topic__forum__pk')
site.register(models.Post, PostIndex)
settings.py
# Haystack settings
HAYSTACK_SITECONF = 'search_sites'
HAYSTACK_SEARCH_ENGINE = 'whoosh'
HAYSTACK_WHOOSH_PATH = os.path.join(PROJECT_ROOT, 'djangobb_index')
also i havae haystack and whoosh in my installed apps.
In python interpreter:
>>> import haystack
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/.../lib/python2.7/django_haystack-1.2.5-py2.5.egg/haystack/__init__.py", line 26, in <module>
raise ImproperlyConfigured("You must define the HAYSTACK_SITECONF setting before using the search framework.")
django.core.exceptions.ImproperlyConfigured: You must define the HAYSTACK_SITECONF setting before using the search framework.
Has someone has any ideas? Thanks in advance for any help you might have to offer.
Notice that the value shown in the documentation for HAYSTACK_SITECONF is an example only. The real name should be the module where the SearchIndex-derived classes are defined. So, as in your case the module is search_indexes, then you should have HAYSTACK_SITECONF='search_indexes'
Also, about that error that appears at the interpreter, did you get it using python ./manage.py shell? If not, settings.py wasn't loaded at the interpreter.

Resources