Check if person's id exists in a function's dictionary - python

I have this code to check if a person exists given their id. If they do exist, it has to print the name and last name. If they don't exists, it has to print some error. The thing is, my code only prints the error even though I tried the code with a number I know corresponds to an existing person. How do I fix that?
This is my view:
from django.shortcuts import render, HttpResponse
import requests
from django.views.generic import FormView
from .forms import MonotributoForm
from app.ws_sr_padron import get_persona
class ConstanciaInscripcion(FormView):
def get(self, request):
return render(request, 'app/constancia-inscripcion.html')
def post(self,request):
form = MonotributoForm(request.POST)
try:
cuit_r = int(request.POST.get('cuit', '-1')) # Get 'cuit' with default of -1
except ValueError:
pass
response= get_persona(cuit_r)
if response is True:
print(response["persona"]['name'])
print(response['persona']['lastname'])
else:
print("cuit doesn't exist")
if form.is_valid():
cuit = form.cleaned_data.get('cuit')
email = form.cleaned_data.get('email')
cuit.save()
email.save()
return HttpResponseRedirect('app/constancia-inscripcion.html')
return render(request, 'app/constancia-inscripcion.html')
The code for get_persona (I cannot modify this as I did not write it and it was given to me this way):
def get_persona(cuit_requested, ta_sign=None, ta_token=None):
try:
if ta_sign is None and ta_token is None:
ta_sign, ta_token = wsaa.get_ta_sign_token('ws_sr_padron_a13')
client = Client(padron13_wsdl)
response = client.service.getPersona(
sign=ta_sign,
token=ta_token,
cuitRepresentada=cuit_consultante,
idPersona=cuit_requested,
)
return serialize_object(response, target_cls=dict)
except Fault as e:
if e.message == 'No person with Id':
return None
elif e.message == 'inactive':
return 'inactive'
print('Error: ', e)
return None
except Exception as e:
print('Error: ', e)
return None
Result of get_persona with an existing id (tried on terminal):
{'metadata': {'fechaHora': datetime.datetime(2021, 3, 4, 15, 13, 54, 738000, tzinfo=<FixedOffset '-03:00'>), 'servidor': 'linux11b'}, 'persona': {'apellido': 'POLAR', 'estadoClave': 'ACTIVO', 'idPersona': 2231230211, 'mesCierre': 12, 'nombre': 'MAURICIO', 'tipoClave': 'CUIT'}}
The output of response on it's own seems to be None for some reason.

The issue is due to the conditional in your code: if response is True.
If you look at the value that get_persona returns, it can be the result of the function serialize_object(...), None, or "inactive".
If the serialize_object(...) function returns a None or the string "inactive", the statement response is True will be false.
>>> type(True)
bool
>>> type({"a": 1})
dict
>>> type("inactive")
str
# To test this, I created this function
>>> def test_response(response):
return response is True
>>> test_response(None)
False
>>> test_response({"persona": True})
False
>>> test_response("inactive")
False
# The only value of response that `is True` is the value `True` itself!
>>> test_response(True)
True
What you want to do is change your conditional to check for a useful response value. In this case, you could test if the response value is a dict, but what if it doesn't have the persona value -- or what if the persona exists, but it doesn't have a nombre?
>>> response = {"a": 1}
>>> response["persona"]["nombre"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'persona'
>>> response = {"persona": None}
>>> response["persona"]["nombre"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not subscriptable
A better solution than an if statement would be a try/except, which can handle both types of errors gracefully and default to the invalid/error case.
response = get_persona(cuit_r)
try:
nombre = response["persona"]["nombre"]
apellido = response["persona"]["apellido"]
except KeyError:
nombre, apellido = None, None
print("get_persona response is missing keys!")
except TypeError:
nombre, apellido = None, None
print("get_persona response had wrong type!")
else:
print("get_persona returned a valid response!")
print("nombre:", nombre)
print("apellido:", apellido)
Update #1
Based on your comments, it also sounds like you're having trouble with the cuit_r value as well. You should change your code to properly handle the possible exceptions as separate statements:
try:
cuit_r = int(request.POST["cuit"])
except KeyError:
print("The key 'cuit' was missing from the POST data.")
print("Defaulting to cuit_r = -1")
cuit_r = -1
except TypeError:
print(
"The 'cuit' value is the wrong type:",
type(request.POST["cuit"]),
)
print("Defaulting to cuit_r = -1")
cuit_r = -1
print(f"Resolved value of cuit_r: {type(cuit_r).__name__}({cuit_r!r})")

Related

Value error: view didn't return an HttpResponse object. It returned None instead Django

I'm yet to understand why I'm getting 'HttpResponse' error.
Traceback (most recent call last):
File "C:\Python27\Scripts\covaenv\lib\site-packages\django\core\handlers\exception.py", line 42, in inner
response = get_response(request)
File "C:\Python27\Scripts\covaenv\lib\site-packages\django\core\handlers\base.py", line 198, in _get_response
"returned None instead." % (callback.__module__, view_name)
ValueError: The view exampleapp.views.get_recieve_update didn't return an HttpResponse object. It returned None instead.
This view is responsible for getting a POST request from an API and load the data and do things with it.
Views:
#csrf_exempt
def get_recieve_update(request):
if request.method=="POST":
man= json.loads(request.body)
txId = man['hash']
uri = bgo_main_base_url + '/wallet/{}/tx/{}'.format(WALLETID, txId)
rexa = requests.get(uri, headers=headers)
vd = rexa.json()
isMine = vd['outputs'][0]['isMine']
confirmations = vd['confirmations']
if isMine == True and confirmations > 1:
address = vd['outputs'][0]['account']
value = vd['outputs'][0]['value']
try:
get_adr = CPro.objects.get(address = address)
except CPro.DoesNotExist:
get_adr = None
if not get_adr.is_used==True and get_adr.is_active==False:
update_cw = CW.objects.filter(user =
get_adr.user).update(current_btc_balance=F('current_btc_balance') + value , modified_date=datetime.datetime.now())
return HttpResponse('done')
elif get_adr.is_used==True and get_adr.is_active==False:
address = vd['outputs'][0]['account']
value = vd['outputs'][0]['value']
send_mail('Recieved on Used Address','failed to credit for {} with {} and id {}'.format(address, value, txId), DEFAULT_FROM_EMAIL,[DE_MAIL,])
else:
address = vd['outputs'][0]['account']
value = vd['outputs'][0]['value']
send_mail('Recieved Callback Error','failed to credit for {} with {}'.format(address, value), DEFAULT_FROM_EMAIL,[DE_MAIL,])
What am I missing here?
You need to return an HttpResponse on every condition.In last if else statement you can see you are not returning anything from the view so you have to return an appropriate http response for every case in your view. See updated code below.
#csrf_exempt
def get_recieve_update(request):
if request.method=="POST":
man= json.loads(request.body)
txId = man['hash']
uri = bgo_main_base_url + '/wallet/{}/tx/{}'.format(WALLETID, txId)
rexa = requests.get(uri, headers=headers)
vd = rexa.json()
isMine = vd['outputs'][0]['isMine']
confirmations = vd['confirmations']
if isMine == True and confirmations > 1:
address = vd['outputs'][0]['account']
value = vd['outputs'][0]['value']
try:
get_adr = CPro.objects.get(address = address)
except CPro.DoesNotExist:
get_adr = None
if not get_adr.is_used==True and get_adr.is_active==False:
update_cw = CW.objects.filter(user =
get_adr.user).update(current_btc_balance=F('current_btc_balance') + value , modified_date=datetime.datetime.now())
return HttpResponse('done')
elif get_adr.is_used==True and get_adr.is_active==False:
address = vd['outputs'][0]['account']
value = vd['outputs'][0]['value']
send_mail('Recieved on Used Address','failed to credit for {} with {} and id {}'.format(address, value, txId), DEFAULT_FROM_EMAIL,[DE_MAIL,])
return HttpResponse("Some appropriate response")
else:
# return something. If both condition from does not get true then there will be no return from view
else:
address = vd['outputs'][0]['account']
value = vd['outputs'][0]['value']
send_mail('Recieved Callback Error','failed to credit for {} with {}'.format(address, value), DEFAULT_FROM_EMAIL,[DE_MAIL,])
return HttpResponse("Some appropriate response") # <-- here you were not returning a response
Another Helpful answer

Handling key error in python

The below function parses the cisco command output,stores the output in dictionary and returns the value for a given key. This function works as expected when the dictionary contains the output. However, if the command returns no output at all the length of dictionary is 0 and the function returns a key error . I have used exception KeyError: But this doesn't seem to work.
from qa.ssh import Ssh
import re
class crypto:
def __init__(self, username, ip, password, machinetype):
self.user_name = username
self.ip_address = ip
self.pass_word = password
self.machine_type = machinetype
self.router_ssh = Ssh(ip=self.ip_address,
user=self.user_name,
password=self.pass_word,
machine_type=self.machine_type
)
def session_status(self, interface):
command = 'show crypto session interface '+interface
result = self.router_ssh.cmd(command)
try:
resultDict = dict(map(str.strip, line.split(':', 1))
for line in result.split('\n') if ':' in line)
return resultDict
except KeyError:
return False
test script :
obj = crypto('uname', 'ipaddr', 'password', 'router')
out = obj.session_status('tunnel0')
status = out['Peer']
print(status)
Error
Traceback (most recent call last):
File "./test_parser.py", line 16, in <module>
status = out['Peer']
KeyError: 'Peer'
The KeyError did not happend in the function session_status,it is happend in your script at status = out['Peer'].So your try and except in session_status will not work.you should make a try and except for status = out['Peer']:
try:
status = out['Peer']
except KeyError:
print 'no Peer'
or :
status = out.get('Peer', None)
Your exception is not in the right place. As you said you just return an empty dictionary with your function. The exception is trying to lookup the key on empty dictionary object that is returned status = outertunnel['Peer']. It might be easier to check it with the dict get function. status = outertunnel.get('Peer',False) or improve the test within the function session_status, like testing the length to decide what to return False if len(resultDict) == 0
This explains the problem you're seeing.
The exception happens when you reference out['Peer'] because out is an empty dict. To see where the KeyError exception can come into play, this is how it operates on an empty dict:
out = {}
status = out['Peer']
Throws the error you're seeing. The following shows how to deal with an unfound key in out:
out = {}
try:
status = out['Peer']
except KeyError:
status = False
print('The key you asked for is not here status has been set to False')
Even if the returned object was False, out['Peer'] still fails:
>>> out = False
>>> out['Peer']
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
out['Peer']
TypeError: 'bool' object is not subscriptable
I'm not sure how you should proceed, but dealing with the result of session_status not having the values you need is the way forward, and the try: except: block inside the session_status function isn't doing anything at the moment.

skipping a json key if does not exist

I'm running the following:
for server in server_list:
for item in required_fields:
print item, eval(item)
There is a possibility that some keys may not exist, but worse it's represented on a parent key not the one I'm scanning for.
So I'm scanning the json for the following key:
server['server_management']['server_total_cost_of_ownership']['description']
Which doesn't exist but it's actually the parent that is null:
server['server_management']['server_total_cost_of_ownership']
How do I write my code to account for this? It's not giving a key error. Right now I get the following traceback:
Traceback (most recent call last):
File "C:/projects/blah/scripts/test.py", line 29, in <module>
print item, eval(item)
File "<string>", line 1, in <module>
TypeError: 'NoneType' object has no attribute '__getitem__'
Full code:
import csv
import json
import os
import requests
import sys
required_fields = ["server['server_name']","server['server_info']['asset_type']['display_name']",
"server['asset_status']['display_name']", "server['record_owner']['group_name']",
"server['server_management']['server_total_cost_of_ownership']['description']",
"server['server_management']['primary_business_owner']['name']",
"server['environment']['display_name']", "server['is_virtual']",
"server['managed_by']['display_name']", "server['server_info']['billable_ibm']",
"server['server_info']['billing_sub_type']['display_name']",
"server['server_info']['serial_number']", "server['location']['display_name']",
"server['inception_date']", "server['server_info']['decommission_date']" ]
# Query API for all servers
def get_servers_info():
servers_info = requests.get('url')
return servers_info.json()
def get_server_info(sid):
server_info = requests.get('url')
return server_info.json()
server_list = get_servers_info()
for server in server_list:
for item in required_fields:
print item, eval(item)
In fact you should avoid eval. After the json load since you know the key name, you can use a list to go deeper in the tree.
server['server_management']['primary_business_owner']['name']" => ["server_management', 'primary_business_owner', 'name']
Here a snippet for a json validation against a list of required fields.
data={
"d": {
"p":{
"r":[
"test"
]
}
},
"a": 3
}
def _get_attr(dict_, attrs):
try:
src = attrs[:]
root = attrs.pop(0)
node = dict_[root]
null = object()
for i, attr in enumerate(attrs[:]):
try:
node = node.get(attr, null)
except AttributeError:
node = null
if node is null:
# i+2 pop and last element
raise ValueError("%s not present (level %s)" % (attr, '->'.join(src[: i+2])))
return node
except KeyError:
raise ValueError("%s not present" % root)
# assume list of required field
reqs = [
["d", "p", "r"],
["d"],
["k"],
["d", "p", "r", "e"],
]
for req in reqs:
try:
_get_attr(data, req)
except ValueError as E:
print(E)
# prints
# k not present
# e not present (level d->p->r->e)
Ignoring the context of the code and not understanding the use of eval here, the way to do this is to use .get() and seed it with reasonable defaults.
For example:
server['server_management']['server_total_cost_of_ownership']['description']
Can be:
server.get('server_management', {}).get('server_total_cost_of_ownership', {}).get('description', '')
Then if any of the keys do not exist you will always get back an empty description ''.
Your problem here is totally unrelated to using eval[1]. The exception you get is the same as if the code would have been there directly. What you are running (via eval) is:
a = server['server_management']
b = a['server_total_cost_of_ownership']
c = b['description']
Yet, b is None, so resolving it to c will fail. Like a KeyError, you can also catch a TypeError:
for server in server_list:
for item in required_fields:
try:
print item, eval(item)
except TypeError:
print("Guess you're lucky you didn't include a fork bomb in your own code to eval.")
You may of course alternatively pass, print the offending item, open a browser to some page or do whatever error handling is appropriate given your input data.
[1] While not bickering around, I've made a new answer that works without eval. You can use precisely the same error handling:
for server in server_list:
for item in required_fields:
value = server
for key in parse_fields(field):
try:
value = value[key]
except TypeError:
print("Remember Kiddo: Eval is Evil!")
break
else: # for: else: triggers only if no break was issued
print item, value

AttributeError: 'unicode' object has no attribute 'success'

I have a simple script using requests to validate a list of emails. Relevant code:
def ___process_email(email, output_file=None):
profile = request(email)
if profile and profile.success != 'nothing_useful':
logger.info('Found match for {0}'.format(email))
print(profile)
if output_file:
output_file.write(str(profile) + '\n')
else:
print("No information found\n")
This ran through 5 loops successfully then threw:
Traceback (most recent call last):
File "app.py", line 147, in <module> main()
File "app.py", line 141, in main ___process_email(arg, output)
File "app.py", line 107, in ___process_email if profile and profile.success != 'nothing_useful':
AttributeError: 'unicode' object has no attribute 'success'
Here's the model:
class Profile(object):
def __init__(self, person):
if person:
self.name = person.get('name')
self.jobinfo = [
(occupation.get('job_title'), occupation.get('company'))
for occupation in person.get('occupations', [])
]
self.memberships = [
(membership.get('site_name'), membership.get('profile_url'))
for membership in person.get('memberships', [])
]
self.success = person.get('success')
def __str__(self):
return dedent("""
Name: {0}
{1}
{2}
""").format(
self.name,
"\n".join(
"{0} {1}".format(title, company)
for title, company in self.jobinfo),
"\n".join(
"\t{0} {1}".format(site_name, url)
for site_name, url in self.memberships)
)
Request:
import requests
def request(email):
status_url = STATUS_URL.format(email)
response = requests.get(status_url).json()
session_token = response.get('session_token')
# fail gracefully if there is an error
if 'error' in response:
return response['error']
elif response['status'] == 200 and session_token:
logger.debug('Session token: {0}'.format(session_token))
url = URL.format(email)
headers = {'X-Session-Token': session_token}
response = requests.get(url, headers=headers).json()
if response.get('success') != 'nothing_useful':
return Profile(response.get('contact'))
return {}
Anyone see why my strings are unicode? thanks
If there is an error in the response, you return the error string:
if 'error' in response:
return response['error']
That's your unicode value there. Note that the same function returns either the 'error' value, a new Profile() instance, or an empty dictionary. You may want to make this more consistent, return only Profile() istances and None instead.
Instead of the error string, raise an exception and handle the exception in your ___process_email method:
class EmailValidationError(Exception):
pass
and in your request() function:
if 'error' in response:
raise EmailValidationError(response['error'])
then handle this in __process_email() with something like:
try:
profile = request(email)
if profile and profile.success != 'nothing_useful':
logger.info('Found match for {0}'.format(email))
print(profile)
if output_file:
output_file.write(str(profile) + '\n')
else:
print("No information found\n")
except EmailValidationError:
# Do something here

Error when the Email formencode validator

I wanted to create an IDN-aware formencode validator to use in one of my projects. I used a portion of code from the Django project (http://code.djangoproject.com/svn/django/trunk/django/core/validators.py) to do that, but there must be a trivial error in my code I can't find :
class Email(formencode.validators.Email):
def _to_python(self, value, state):
try:
return super(Email, self)._to_python(value, state)
except formencode.Invalid as e:
# Trivial case failed. Try for possible IDN domain-part
print 'heywo !'
if value and u'#' in value:
parts = value.split(u'#')
try:
parts[-1] = parts[-1].encode('idna')
except UnicodeError:
raise e
try:
super(Email, self)._to_python(u'#'.join(parts), state)
except formencode.Invalid as ex:
raise ex
return value
else:
raise e
When I try to validate an email with an IDN domain (ex: test#wääl.de), the Invalid exception raised by the first call is thrown, and the portion of code after the first except is never executed ('heywo !' is never printed).
There is an example :
>>> from test.lib.validators import Email
>>> Email().to_python(u'test#zääz.de')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.6/dist-packages/FormEncode-1.2.3dev-py2.6.egg/formencode /api.py", line 416, in to_python
vp(value, state)
File "/usr/local/lib/python2.6/dist-packages/FormEncode-1.2.3dev-py2.6.egg/formencode /validators.py", line 1352, in validate_python
value, state)
Invalid: The domain portion of the email address is invalid (the portion after the #: z\xe4\xe4z.de)
What did I do wrong ?
Thanks.
Okay, found the answer. I was overloading _to_python instead of validate_python. The class now looks like :
class Email(formencode.validators.Email):
def validate_python(self, value, state):
try:
super(Email, self).validate_python(value, state)
except formencode.Invalid as e:
# Trivial case failed. Try for possible IDN domain-part
if value and u'#' in value:
parts = value.split(u'#')
try:
parts[-1] = parts[-1].encode('idna')
except UnicodeError:
raise e
try:
super(Email, self).validate_python(u'#'.join(parts), state)
except formencode.Invalid as ex:
raise ex
else:
raise e
It's working perfectly :)

Categories

Resources