Trying to e.164 a phone number from form input - python

I'm trying to take a UK mobile phone number input from a web form and use Python to clean it into a E.164 format, then validate it, before entering it into a database.
The library I'm trying to use is "Phonenumbers" and the code I'm experimenting with so far is:
def Phone():
my_number = '+4407808765066'
clean_phone = phonenumbers.parse(my_number, "GB")
cleaner_phone = phonenumbers.format_number(clean_phone,
phonenumbers.PhoneNumberFormat.E164)
valid = phonenumbers.is_possible_number(cleaner_phone)
print(cleaner_phone)
Just working through the logic, my expectation is that it should take the contents of my_number variable, format it through into the clean_phone variable, then format it to E.164 standard before passing it to the validation and return the output to valid. The print statement is for me to see the output.
Everything looks to work ok if I comment out the valid variable line. As soon as I uncomment it, I get an error (see below).
Traceback (most recent call last):
File "phone_test.py", line 14, in <module>
Phone()
File "phone_test.py", line 10, in Phone
valid = phonenumbers.is_possible_number(cleaner_phone)
File "D:\Dropbox\Coding Projects\learner_driver_app\env\lib\site-packages\phonenumbers\phonenumberutil.py", line 2257, in is_possible_number
result = is_possible_number_with_reason(numobj)
File "D:\Dropbox\Coding Projects\learner_driver_app\env\lib\site-packages\phonenumbers\phonenumberutil.py", line 2358, in is_possible_number_with_reason
return is_possible_number_for_type_with_reason(numobj, PhoneNumberType.UNKNOWN)
File "D:\Dropbox\Coding Projects\learner_driver_app\env\lib\site-packages\phonenumbers\phonenumberutil.py", line 2393, in is_possible_number_for_type_with_reason
national_number = national_significant_number(numobj)
File "D:\Dropbox\Coding Projects\learner_driver_app\env\lib\site-packages\phonenumbers\phonenumberutil.py", line 1628, in national_significant_number
if numobj.italian_leading_zero:
AttributeError: 'str' object has no attribute 'italian_leading_zero'
Where am I going wrong?

Your my_number is a variable of type str (string), thus the last line of your error). The string class does not know the attribute national_number.
Reading through their examples on GitHub, I suspect you need to pass your string through the parse() function first before you can use functions from the library.
def Phone():
my_number = '+4407811111111'
number_prased = phonenumbers.parse(my_number, None) # this is new
clean_phone = phonenumbers.format_number(number_parsed,
phonenumbers.PhoneNumberFormat.E164)
return clean_phone
The None in parse() may be replaced by a country code if it is known. Otherwise, it will try to figure it out but may fail.
Edit to account for more information in the original question:
Apparently phonenumbers.format_number() returns a string, therefore you have to re-parse the number again to get an object of type phonenumbers.phonenumber.PhoneNumber (you can check the type of objects with type(my_object)). After that, your code will return True.

You can't use the format_number function with a string as argument, it expects a PhoneNumber object.
You can get one by using the parse function.
See https://github.com/daviddrysdale/python-phonenumbers/tree/dev/python#example-usage

Related

How to use click.prompt to get a valid date from the user?

Hello,
I'm actually learning how to use some elements from the click package, and I'd like to be able to get a valid date from the user by using the promptcommand.
I tried to look up the docs, and I found this under http://click.pocoo.org/5/prompts/:
To manually ask for user input, you can use the prompt() function. By default, it accepts any Unicode string, but you can ask for any other type.
So I wrote this code and tried to pass the class datetime.datetime as the wanted type of input:
import datetime
value = click.prompt("Enter a date", type=datetime.datetime)
when I execute this code the prompt appears, but after I insert a valid date and press the enter key I'm getting this error message:
Traceback (most recent call last):
File "", line 1, in
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/click/termui.py", line 98, in prompt
result = value_proc(value)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/click/types.py", line 38, in call
return self.convert(value, param, ctx)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/click/types.py", line 87, in convert
return self.func(value)
TypeError: an integer is required (got type str)
Please, could you show me what am I doing wrong in this code ?
Basically I'd like to get a date value properly formatted by writing something like this piece of (partially imaginary) code:
import datetime
value = click.prompt("Enter a date",
type=datetime.datetime,
format="%d/%m/%Y",
default=datetime.datetime.now())
Thank you very much
It doesn't seem that Click handles dates now, but it is probably something that may change in the future.
Instead you could pass a parser with the value_proc parameter. I've used dateutil, but you can change it to datetime if you prefer it:
from dateutil import parser
import click
def parse(value):
try:
date = parser.parse(value)
except:
raise click.BadParameter("Couldn't understand date.", param=value)
return value
value = click.prompt("Enter a date", value_proc=parse)

TypeError: cannot concatenate 'str' and 'SFType' objects (simple-salesforce)

my project is to extract the contents of all my salesforce tables, including the custom ones. To do this, I need to know the names of the columns (fields), since SOQL does not support "SELECT * from TABLENAME".
With simple-salesforce, I know that the following works:
sf = Salesforce(username='foo#bar.com', password='abcd', security_token='ZCdsdPdE4eI2DZMl5gwCFIGEFU')
field_data = sf.Contact.describe()["fields"]
But my problem is that I need to parameterize the "Contact" string in the actual method call above, so that I can call this method for objects that I do not know the names of (ie not defined in standard salesforce). For example I need to do:
field_data = sf.CustomTableName.describe()["fields"]
When I try and use the SFType class:
contact = SFType('Contact',sf.sessionid,sf.sf_instance)
f = contact.describe()
I get this error:
Traceback (most recent call last):
File "./simple-example.py", line 13, in <module>
f = contact.describe()["fields"]
File "/Library/Python/2.7/site-packages/simple_salesforce/api.py", line 430, in describe
result = self._call_salesforce('GET', self.base_url + 'describe')
File "/Library/Python/2.7/site-packages/simple_salesforce/api.py", line 570, in _call_salesforce
'Authorization': 'Bearer ' + self.session_id,
TypeError: cannot concatenate 'str' and 'SFType' objects
Thanks in advance for any advice.
If you look in the source code for simple-salesforce (as of 2015-11-12) you'll see that in the init() of Salesforce() we set the session to self.session_id and instance to self.sf_instance
In your case, you're using sf.sessionid, and because simple-salesforce is setup to return a SFType() object whenever a method or property does not exist on Salesforce() (and sessionid does not exist on Salesforce()) you're actually inserting a SFType() object into the init of your SFType()
SFType.__init__() doesn't do any form of validation to confirm you're passing in strings as arguments, so the error you're getting is from simple-salesforce trying to use the SFType() object you're passing in as a string.
Try this code:
contact = SFType('Contact', sf.session_id, sf.sf_instance)
f = contact.describe()
I ran into the same issue and seemed to have fixed this by removing the protocol ("https://") from the instance_url. This is weird but seems to work for me now and I can do contact.describe()
Something like this:
contact = SFType(sf_object, session_id, instance_url.replace("https://",''))
contact.describe()

Python sys.argv TypeErrors with printing function results?

I have been trying to learn how to use sys.argv properly, while calling an executable file from the command line.
I wanted to have the functions results print to the command line when passing the filename and argument on the command line but, I get a TypeError.
So far I have:
#! /usr/bin/env python
import mechanize
from BeautifulSoup import BeautifulSoup
import sys
def dictionary(word):
br = mechanize.Browser()
response = br.open('http://www.dictionary.reference.com')
br.select_form(nr=0)
br.form['q'] = sys.argv
br.submit()
definition = BeautifulSoup(br.response().read())
trans = definition.findAll('td',{'class':'td3n2'})
fin = [i.text for i in trans]
query = {}
for i in fin:
query[fin.index(i)] = i
return query
print dictionary(sys.argv)
When I call this:
./this_file.py 'pass'
I am left with this error message:
Traceback (most recent call last):
File "./hot.py", line 20, in <module>
print dictionary(sys.argv)
File "./hot.py", line 10, in dictionary
br.form['q'] = sys.argv
File "/usr/local/lib/python2.7/dist-packages/mechanize/_form.py", line 2782, in __setitem__
control.value = value
File "/usr/local/lib/python2.7/dist-packages/mechanize/_form.py", line 1217, in __setattr__
raise TypeError("must assign a string")
TypeError: must assign a string
With
br.form['q'] = sys.argv
you are assigning a list of strings here instead of a string.
>>> type(sys.argv)
<type 'list'>
>>> type(sys.argv[0])
<type 'str'>
>>>
You want to identify a specific string to assign via an index.
Most likely it will be be index 1 given what you have in your post (and since index 0 is the name of the script). So perhaps
br.form['q'] = sys.argv[1]
will do for you. Of course it could be another index too, depending on your particular application/needs.
Note as #Dougal observes in a helpful comment below, the function parameter word in the function is not being used. You are calling your dictionary function sending it sys.argv and then ought to refer to word inside the function. The type doesn't change only the name that you refer to the command line args inside your function. The idea of word is good as it avoids the use of global variables. If you refer to use globals (not really encouraged) then removing word is recommended as it will be confusing to have it there).
So your statement should really read
br.form['q'] = word[1]

TypeError: in Python

I have an issue, where a function returns a number. When I then try to assemble a URL that includes that number I am met with failure.
Specifically the error I get is
TypeError: cannot concatenate 'str' and 'NoneType' objects
Not sure where to go from here.
Here is the relevant piece of code:
# Get the raw ID number of the current configuration
configurationID = generate_configurationID()
# Update config name at in Cloud
updateConfigLog = open(logBase+'change_config_name_log.xml', 'w')
# Redirect stdout to file
sys.stdout = updateConfigLog
rest.rest(('put', baseURL+'configurations/'+configurationID+'?name=this_is_a_test_', user, token))
sys.stdout = sys.__stdout__
It works perfectly if I manually type the following into rest.rest()
rest.rest(('put', http://myurl.com/configurations/123456?name=this_is_a_test_, myusername, mypassword))
I have tried str(configurationID) and it spits back a number, but I no longer get the rest of the URL...
Ideas? Help?
OK... In an attempt to show my baseURL and my configurationID here is what I did.
print 'baseURL: '+baseURL
print 'configurationID: '+configurationID
and here is what I got back
it-tone:trunk USER$ ./skynet.py fresh
baseURL: https://myurl.com/
369596
Traceback (most recent call last):
File "./skynet.py", line 173, in <module>
main()
File "./skynet.py", line 30, in main
fresh()
File "./skynet.py", line 162, in fresh
updateConfiguration()
File "./skynet.py", line 78, in updateConfiguration
print 'configurationID: '+configurationID
TypeError: cannot concatenate 'str' and 'NoneType' objects
it-tone:trunk USER$
What is interesting to me is that the 369596 is the config ID, but like before it seems to clobber everything called up around it.
As kindall pointed out below, my generate_configurationID was not returning the value, but rather it was printing it.
# from generate_configurationID
def generate_configurationID():
dom = parse(logBase+'provision_template_log.xml')
name = dom.getElementsByTagName('id')
p = name[0].firstChild.nodeValue
print p
return p
Your configurationID is None. This likely means that generate_configurationID() is not returning a value. There is no way in Python for a variable name to "lose" its value. The only way, in the code you posted, for configurationID to be None is for generate_configurationID() to return None which is what will happen if you don't explicitly return any value.
"But it prints the configurationID right on the screen!" you may object. Sure, but that's probably in generate_configurationID() where you are printing it to make sure it's right but forgetting to return it.
You may prove me wrong by posting generate_configurationID() in its entirety, and I will admit that your program is magic.

AppEngine -> "AttributeError: 'unicode' object has no attribute 'has_key'" when using blobstore

There have been a number of other questions on AttributeErrors here, but I've read through them and am still not sure what's causing the type mismatch in my specific case.
Thanks in advance for any thoughts on this.
My model:
class Object(db.Model):
notes = db.StringProperty(multiline=False)
other_item = db.ReferenceProperty(Other)
time = db.DateTimeProperty(auto_now_add=True)
new_files = blobstore.BlobReferenceProperty(required=True)
email = db.EmailProperty()
is_purple = db.BooleanProperty()
My BlobstoreUploadHandler:
class FormUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
try:
note = self.request.get('notes')
email_addr = self.request.get('email')
o = self.request.get('other')
upload_file = self.get_uploads()[0]
# Save the object record
new_object = Object(notes=note,
other=o,
email=email_addr,
is_purple=False,
new_files=upload_file.key())
db.put(new_object)
# Redirect to let user know everything's peachy.
self.redirect('/upload_success.html')
except:
self.redirect('/upload_failure.html')
And every time I submit the form that uploads the file, it throws the following exception:
ERROR 2010-10-30 21:31:01,045 __init__.py:391] 'unicode' object has no attribute 'has_key'
Traceback (most recent call last):
File "/home/user/Public/dir/google_appengine/google/appengine/ext/webapp/__init__.py", line 513, in __call__
handler.post(*groups)
File "/home/user/Public/dir/myapp/myapp.py", line 187, in post
new_files=upload_file.key())
File "/home/user/Public/dir/google_appengine/google/appengine/ext/db/__init__.py", line 813, in __init__
prop.__set__(self, value)
File "/home/user/Public/dir/google_appengine/google/appengine/ext/db/__init__.py", line 3216, in __set__
value = self.validate(value)
File "/home/user/Public/dir/google_appengine/google/appengine/ext/db/__init__.py", line 3246, in validate
if value is not None and not value.has_key():
AttributeError: 'unicode' object has no attribute 'has_key'
What perplexes me most is that this code is nearly straight out of the documentation, and jives with other examples of blob upload handler's I've found online in tutorials as well.
I've run --clear-datastore to ensure that any changes I've made to the DB schema aren't causing problems, and have tried casting upload_file as all sorts of things to see if it would appease Python - any ideas on what I've screwed up?
Edit: I've found a workaround, but it's suboptimal.
Altering the UploadHandler to this instead resolves the issue:
...
# Save the object record
new_object = Object()
new_object.notes = note
new_object.other = o
new_object.email = email.addr
new_object.is_purple = False
new_object.new_files = upload_file.key()
db.put(new_object)
...
I made this switch after noticing that commenting out the files line threw the same issues for the other line, and so on. This isn't an optimal solution, though, as I can't enforce validation this way (in the model, if I set anything as required, I can't declare an empty entity like above without throwing an exception).
Any thoughts on why I can't declare the entity and populate it at the same time?
You're passing in o as the value of other_item (in your sample code, you call it other, but I presume that's a typo). o is a string fetched from the request, though, and the model definition specifies that it's a ReferenceProperty, so it should either be an instance of the Other class, or a db.Key object.
If o is supposed to be a stringified key, pass in db.Key(o) instead, to deserialize it.
Object is a really terrible name for a datastore class (or any class, really), by the way - the Python base object is called object, and that's only one capitalized letter away - very easy to mistake.
has_key error is due to the ReferenceProperty other_items. You are most likely passing in '' for other_items when appengine's api expects a dict. In order to get around this, you need to convert other_items to hash.
[caveat lector: I know zilch about "google_app_engine"]
The message indicates that it is expecting a dict (the only known object that has a has_key attribute) or a work-alike object, not the unicode object that you supplied. Perhaps you should be passing upload_file, not upload_file.key() ...

Categories