Extending the Twilio Weather By Phone app to create python TwiML server - python

I am trying to create a demo webserver that returns a TwiML Say block with custom text inside it based on parameters provided with the URL (Yes, POSTing would be better, but I'm not quite sure how to do that). It would work a lot like https://www.twilio.com/labs/twimlets/message except I want to write my own code so I can add more customizations.
I have started by building off of the Weather by Phone demo because it contains customized text inside of xml.
I have created my own google appengine called gracklevoice, and I got the weatherbyphone example working. Now, I'm having trouble when I try to simplify it. My code looks like this:
import os
import wsgiref.handlers
from google.appengine.ext.webapp import template
from google.appengine.ext import webapp
BASE_URL = "http://gracklevoice.appspot.com/"
def xml_response(handler, page, templatevalues=None):
"""
Renders an XML response using a provided template page and values
"""
path = os.path.join(os.path.dirname(__file__), page)
handler.response.headers["Content-Type"] = "text/xml"
handler.response.out.write(template.render(path, templatevalues))
class GracklePage(webapp.RequestHandler):
def get(self):
self.post()
def post(self):
xml_response(self, 'notification.xml')
def main():
application = webapp.WSGIApplication([ \
('/', GracklePage)],
debug=True)
wsgiref.handlers.CGIHandler().run(application)
if __name__ == "__main__":
main()
There is the yaml file too:
application: gracklevoice
version: 1
runtime: python27
api_version: 1
threadsafe: no
handlers:
- url: /.*
script: gracklevoice.py
And notification.xml
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say voice="alice" language="en-US">
This is a message from Grackle.
</Say>
</Response>
This seems it should be really simple, but when my client app sets the call url to http://gracklevoice.appspot.com/ I get an error instead of the voice message: "We are sorry. an application error has occurred. Goodbye." What am I missing?
Looking in the appEngine logs (which are limited in length, welp), I see:
2013-11-18 14:45:09.781
Traceback (most recent call last):
E 2013-11-18 14:45:09.781
File "/base/data/home/runtimes/python27/python27_dist/lib/python2.7/wsgiref/handlers.py", line 86, in run
E 2013-11-18 14:45:09.781
self.finish_response()
E 2013-11-18 14:45:09.781
File "/base/data/home/runtimes/python27/python27_dist/lib/python2.7/wsgiref/handlers.py", line 128, in finish_response
E 2013-11-18 14:45:09.781
self.write(data)
E 2013-11-18 14:45:09.781
File "/base/data/home/runtimes/python27/python27_dist/lib/python2.7/wsgiref/handlers.py", line 204, in write
E 2013-11-18 14:45:09.781
assert type(data) is StringType,"write() argument must be string"
E 2013-11-18 14:45:09.781
AssertionError: write() argument must be string

Twilio Developer Evangelist here. Cast the output of template.render(path, templatevalues) with the unicode() function. Your new line of code will end up as
handler.response.out.write(unicode(template.render(path, templatevalues)))
The output of the template.render function is a StringType, instead of a str type, which is what the write function needs. Casting with the unicode function converts the output to the input format you require.
There is additional information in this question about issues with StringType and unicode.

Related

google ads api - "argument should be integer or bytes-like object, not 'str'"

I've been trying to follow the examples and documentation for the python ad_manager library for the google ads API, but I haven't been able to complete a successful request. I currently have my developer token, client_id, client_secret, and refresh_token in my google ads YAML file, but I'm constantly getting the error "argument should be integer or bytes-like object, not 'str'" when calling the function WaitForReport following the example code below. I was wondering if anyone had any advice on how I could tackle this issue.
import tempfile
# Import appropriate modules from the client library.
from googleads import ad_manager
from googleads import errors
def main(client):
# Initialize a DataDownloader.
report_downloader = client.GetDataDownloader(version='v202111')
# Create report job.
report_job = {
'reportQuery': {
'dimensions': ['COUNTRY_NAME', 'LINE_ITEM_ID', 'LINE_ITEM_NAME'],
'columns': ['UNIQUE_REACH_FREQUENCY', 'UNIQUE_REACH_IMPRESSIONS',
'UNIQUE_REACH'],
'dateRangeType': 'REACH_LIFETIME'
}
}
try:
# Run the report and wait for it to finish.
report_job_id = report_downloader.WaitForReport(report_job)
except errors.AdManagerReportError as e:
print('Failed to generate report. Error was: %s' % e)
# Change to your preferred export format.
export_format = 'CSV_DUMP'
report_file = tempfile.NamedTemporaryFile(suffix='.csv.gz', delete=False)
# Download report data.
report_downloader.DownloadReportToFile(
report_job_id, export_format, report_file)
report_file.close()
# Display results.
print('Report job with id "%s" downloaded to:\n%s' % (
report_job_id, report_file.name))
if __name__ == '__main__':
# Initialize client object.
ad_manager_client = ad_manager.AdManagerClient.LoadFromStorage()
main(ad_manager_client)
Edit:
Below is the stack trace:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/googleads/common.py", line 984, in MakeSoapRequest
return soap_service_method(
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/zeep/proxy.py", line 46, in __call__
return self._proxy._binding.send(
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/zeep/wsdl/bindings/soap.py", line 135, in send
return self.process_reply(client, operation_obj, response)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/zeep/wsdl/bindings/soap.py", line 229, in process_reply
return self.process_error(doc, operation)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/zeep/wsdl/bindings/soap.py", line 317, in process_error
raise Fault(
zeep.exceptions.Fault: Unknown fault occured
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "google_ads.py", line 72, in <module>
main(ad_manager_client)
File "google_ads.py", line 33, in main1
report_job_id = report_downloader.WaitForReport(report_job)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/googleads/ad_manager.py", line 784, in WaitForReport
report_job_id = service.runReportJob(report_job)['id']
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/googleads/common.py", line 989, in MakeSoapRequest
underlying_exception = e.detail.find(
TypeError: argument should be integer or bytes-like object, not 'str'
In your YAML file, do you have your account number in quotes? (either single or double?)
Additionally, I would highly recommend not going with this API if you have the option. It will be sunset in April and will no longer work. The newer google ads API (as opposed to the AdWords API) is available, stable and much easier to work with. The ad manager examples are good too.
The problem seems to be that zeep raises a WebFault which includes the returned XML response as a string in zeep.Fault.detail.
Somewhat counter-intuitive, this attribute is not a string, but a bytes sequence because zeep.wsdl.utils.etree_to_string calls etree.tostring() with encoding="utf-8" instead of encoding="unicode"—the latter would make sure it's a proper string.
googleads then tries to look for specific error strings inside the XML using find(), but even though find() is defined both on str and bytes, the type of the substring to look for needs to align.
Thus, in
underlying_exception = e.detail.find(
'{%s}ApiExceptionFault' % self._GetBindingNamespace())
bytes.find() is called with a str argument, causing the ValueError you experience.
I'd argue that zeep.wsdl.utils.etree_to_string() should be adjusted to actually return a str instead of bytes. You could try opening an issue on Zeep's Github repository.

Missing request - Pact python

I'm new to pact and I've understood the concept but having hard time understanding and implementing the code.
Here I'm trying to do a simple pact for get_users from reqres.in.
I believe the first (pact ... code does the mock provider part and I compare that using the pact.json file.
import os
import requests
import pytest
from pact import Consumer, Provider, Format
import unittest
import json
pact = Consumer('Consumer').has_pact_with(Provider('Provider'), port=1234, host_name='localhost')
pact.start_service()
CURR_FILE_PATH = os.path.dirname(os.path.abspath(__file__))
PACT_DIR = os.path.join(CURR_FILE_PATH, '')
PACT_FILE = os.path.join(PACT_DIR, 'pact.json')
#defining class
class GetUsers(unittest.TestCase):
def test_get_board(self):
with open(os.path.join(PACT_DIR, PACT_FILE), 'rb') as path_file:
pact_file_json = json.load(path_file)
print('pact_json')
(pact
.given('Request to send message')
.upon_receiving('a request for response or send message')
.with_request(method = 'GET', path = '/api/users?page=2')
.will_respond_with(status = 200, body = pact_file_json))
with pact:
result = requests.get('http://reqres.in/api/users?page=2')
print('actual response')
self.assertEqual(pact_file_json, result.json())
pact.verify()
ge = GetUsers()
print(ge.test_get_board())
however, when I run the code, I get the following error
the data do not match but I verified it in another code.
Traceback (most recent call last):
File "C:\Users\Desktop\Pact\contract_test.py", line 41, in <module>
print(ge.test_get_board())
File "C:\Users\Desktop\Pact\contract_test.py", line 34, in test_get_board
print(data)
File "C:\Users\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pact\pact.py", line 370, in __exit__
self.verify()
File "C:\Users\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pact\pact.py", line 269, in verify
assert resp.status_code == 200, resp.text
AssertionError: Actual interactions do not match expected interactions for mock MockService.
says missing requests
Missing requests:
GET https://reqres.in/api/users?page=2
I'm not sure what you're trying to attempt here - why are you opening up a pact.json file in this context? The consumer pact package will automatically serialise any contracts if successful, and you don't seem to be reading the file in anywhere.
The second problem seems to be that some code somewhere, is issuing (or requesting?) the query string page=2 but the code you've shown doesn't make use of any query strings.
Could you have another mock service running somewhere?
Examples
https://docs.pactflow.io/docs/examples/python/consumer/readme
https://github.com/pact-foundation/pact-python/blob/master/examples/e2e/tests/consumer/test_user_consumer.py

Python: Access data from Solr using Pysolr

I am using simple Python script to fetch example data from Solr using Pysolr. First I created my core using the following
[user#user solr-7.1.0]$ ./bin/solr create -c json_db
WARNING: Using _default configset. Data driven schema functionality is enabled by default, which is
NOT RECOMMENDED for production use.
To turn it off:
curl http://localhost:8983/solr/json_db/config -d '{"set-user-property": {"update.autoCreateFields":"false"}}'
Created new core 'json_db'
[user#user solr-7.1.0]$ ./bin/post -c json_db example/exampledocs/*.json
SimplePostTool version 5.0.0
Posting files to [base] url http://localhost:8983/solr/json_db/update...
Entering auto mode. File endings considered are xml,json,jsonl,csv,pdf,doc,docx,ppt,pptx,xls,xlsx,odt,odp,ods,ott,otp,ots,rtf,htm,html,txt,log
POSTing file books.json (application/json) to [base]/json/docs
1 files indexed.
COMMITting Solr index changes to http://localhost:8983/solr/json_db/update...
Time spent: 0:00:00.398
After creating the core I ran simple python script to fetch data
from pysolr import Solr
conn = Solr('http://localhost:8983/solr/json_db/')
results = conn.search('*:*')
I am getting this error
Traceback (most recent call last):
File "/home/user/PycharmProjects/APP/application/solr_test.py", line 4, in <module>
results = conn.search({'*:*'})
File "/home/user/PycharmProjects/APP/venv/lib/python3.5/site-packages/pysolr.py", line 723, in search
response = self._select(params, handler=search_handler)
File "/home/user/PycharmProjects/APP/venv/lib/python3.5/site-packages/pysolr.py", line 421, in _select
return self._send_request('get', path)
File "/home/user/PycharmProjects/APP/venv/lib/python3.5/site-packages/pysolr.py", line 396, in _send_request
raise SolrError(error_message % (resp.status_code, solr_message))
pysolr.SolrError: Solr responded with an error (HTTP 404): [Reason: Error 404 Not Found]
But when I try to run the query directly from solr I got results like the following
Can somebody guide me what I am doing wrong here ? Thanks
You can just run the script below to fetch the result without using pysolr library.
#! /usr/bin/python
import urllib
import json as simplejson
import pprint
import sys
url = 'give the url here'
wt = "wt=json"
connection = urllib.urlopen(url)
if wt == "wt=json":
response = simplejson.load(connection)
else:
response = eval(connection.read())
print "Number of hits: " + str(response['response']['numFound'])
pprint.pprint(response['response']['docs'])

Google App Engine - Django - Python - Ubuntu - Problems

I am reading 'Head First Python'. I am on Chapter 10 where Google App Engine is introduced. The initial hello world of using Python and Google App Engine was successful but subsequent programs have all failed.
I have the following app.yaml file:
application: three
version: 1
runtime: python27
api_version: 1
threadsafe: false
handlers:
- url: /.*
script: page368b.py
libraries:
- name: django
version: "1.3"
With the following Python code (page368b.py):
import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp import template
#this line throws the error when accessing the web-page
from google.appengine.ext.db import djangoforms
import birthDB
class BirthDetailsForm(djangoforms.ModelForm):
class Meta:
model = birthDB.BirthDetails
class SimpleInput(webapp.RequestHandler):
def get(self):
html = template.render('templates/header.html', {'title': 'Provide your birth details'})
html = html + template.render('templates/form_start.html', {})
html = html + str(BirthDetailsForm(auto_id=False))
html = html + template.render('templates/form_end.html', {'sub_title': 'Submit Details'})
html = html + template.render('templates/footer.html', {'links': ''})
self.response.out.write(html)
def main():
app = webapp.WSGIApplication([('/.*', SimpleInput)], debug=True)
wsgiref.handlers.CGIHandler().run(app)
if __name__ == '__main__':
main()
Here is another Python module imported into the one above called birthDB.py:
from google.appengine.ext import db
class BirthDetails(db.Model):
name = db.StringProperty()
date_of_birth = db.DateProperty()
time_of_birth = db.TimeProperty()
There is a templates folder that the above Python module calls. They have HTML code in them with some Django code. Here is an example using the footer.html.
<p>
{{ links }}
</p>
</body>
</html>
The other HTML files are similar. I can start the Google App Engine with no problems using this command from BASH: python google_appengine/dev_appserver.py ~/Desktop/three The directory three contains the templates folder, the app.yaml file, the Python modules shown above.
My problem is when I access the web-page at http://localhost:8080 nothing is there and the BASH shell where the command is run to start this shows all the calls in the Python program that caused the problem and then finally says: ImportError: Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.
I have read in a few different places a few different things to try so I thought I would go ahead and make a new post and hope that some expert Python programmers would chime in and lend their assistance to a lost hobbit such as myself.
Also, the book says to install Python2.5 to use this code but Google App Engine now supports Python2.7 that was not available as of the time of the books writing. Also, I just checked and Python2.5 is not even an option to use with Google App Engine. Python2.5 deprecated
This is probably too complex to solve on here. I am surprised all of these different technologies are used in a Head First Python book. It is asking a lot of a Python noob. ^_^
Regards,
user_loser
UPDATE - I installed Django on my Ubuntu Operating System
When I change the line in the python module 368b.py from google.appengine.ext.db import djangoforms to from django import forms I receive the following error on the console when accessing the web-page on localhost:
loser#loser-basic-box:~/Desktop$ google_appengine/dev_appserver.py three
INFO 2014-09-06 21:08:36,669 api_server.py:171] Starting API server at: http://localhost:56044
INFO 2014-09-06 21:08:36,677 dispatcher.py:183] Starting module "default" running at: http://localhost:8080
INFO 2014-09-06 21:08:36,678 admin_server.py:117] Starting admin server at: http://localhost:8000
ERROR 2014-09-06 21:08:48,942 cgi.py:121] Traceback (most recent call last):
File "/home/loser/Desktop/three/page368b.py", line 13, in <module>
class BirthDetailsForm(forms.ModelForm):
File "/home/loser/Desktop/google_appengine/lib/django-1.3/django/forms/models.py", line 205, in __new__
opts.exclude, opts.widgets, formfield_callback)
File "/home/loser/Desktop/google_appengine/lib/django-1.3/django/forms/models.py", line 145, in fields_for_model
opts = model._meta
AttributeError: type object 'BirthDetails' has no attribute '_meta'
INFO 2014-09-06 21:08:48,953 module.py:652] default: "GET / HTTP/1.1" 500 -
ERROR 2014-09-06 21:08:49,031 cgi.py:121] Traceback (most recent call last):
File "/home/loser/Desktop/three/page368b.py", line 13, in <module>
class BirthDetailsForm(forms.ModelForm):
File "/home/loser/Desktop/google_appengine/lib/django-1.3/django/forms/models.py", line 205, in __new__
opts.exclude, opts.widgets, formfield_callback)
File "/home/loser/Desktop/google_appengine/lib/django-1.3/django/forms/models.py", line 145, in fields_for_model
opts = model._meta
AttributeError: type object 'BirthDetails' has no attribute '_meta'
Update Errors from running the program as is without making any changes:
loser#loser-basic-box:~/Desktop$ google_appengine/dev_appserver.py three/
INFO 2014-09-06 21:35:19,347 api_server.py:171] Starting API server at: http://localhost:60503
INFO 2014-09-06 21:35:19,356 dispatcher.py:183] Starting module "default" running at: http://localhost:8080
INFO 2014-09-06 21:35:19,358 admin_server.py:117] Starting admin server at: http://localhost:8000
ERROR 2014-09-06 21:35:25,011 cgi.py:121] Traceback (most recent call last):
File "/home/loser/Desktop/three/page368b.py", line 13, in <module>
class BirthDetailsForm(djangoforms.ModelForm):
File "/home/loser/Desktop/google_appengine/google/appengine/ext/db/djangoforms.py", line 772, in __new__
form_field = prop.get_form_field()
File "/home/loser/Desktop/google_appengine/google/appengine/ext/db/djangoforms.py", line 370, in get_form_field
return super(DateProperty, self).get_form_field(**defaults)
File "/home/loser/Desktop/google_appengine/google/appengine/ext/db/djangoforms.py", line 353, in get_form_field
return super(DateTimeProperty, self).get_form_field(**defaults)
File "/home/loser/Desktop/google_appengine/google/appengine/ext/db/djangoforms.py", line 200, in get_form_field
return form_class(**defaults)
File "/home/loser/Desktop/google_appengine/lib/django-1.3/django/forms/fields.py", line 340, in __init__
super(DateField, self).__init__(*args, **kwargs)
File "/home/loser/Desktop/google_appengine/lib/django-1.3/django/forms/fields.py", line 99, in __init__
widget = widget()
File "/home/loser/Desktop/google_appengine/lib/django-1.3/django/forms/widgets.py", line 382, in __init__
self.format = formats.get_format('DATE_INPUT_FORMATS')[0]
File "/home/loser/Desktop/google_appengine/lib/django-1.3/django/utils/formats.py", line 67, in get_format
if use_l10n or (use_l10n is None and settings.USE_L10N):
File "/home/loser/Desktop/google_appengine/lib/django-1.3/django/utils/functional.py", line 276, in __getattr__
self._setup()
File "/home/loser/Desktop/google_appengine/lib/django-1.3/django/conf/__init__.py", line 40, in _setup
raise ImportError("Settings cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLE)
ImportError: Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.
I assume you're working with the example code that accompanies the book, available from this website: http://examples.oreilly.com/0636920003434/
If you download and expand the chapter 10 archive (chapter10.zip), you'll see several example files, and also several .zip archives. The page368b.py file corresponds with the webapp-chapter10-simpleform.zip archive. Open that archive to create a webapp-chapter10-simpleform directory. This directory contains an app.yaml file, the simpleform.py file (identical to page368b.py), birthDB.py (an ext.db model class), and static and template file directories.
Unfortunately, as you may have already noticed, the example doesn't work out of the box with the latest SDK. (I'm using version 1.9.10 of the SDK, which was just released.) It reports "ImportError: No module named django.core.exceptions" when you attempt to load the page. Strictly speaking, this example is not a Django application, but is merely trying to use a library that depends on Django being present.
The Python 2.5 runtime environment, which is selected by the app.yaml file included with this example, is meant to include Django 0.96 by default. However, this behavior has changed in the SDK since Head First Python was written. The smallest fix to get this example to work is to add these lines to simpleform.py prior to the import of djangoforms:
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from google.appengine.dist import use_library
use_library('django', '0.96')
Then create a file named settings.py in your application root directory (the webapp-chapter10-simpleform directory). This file can be empty in this case. (As other commenters have noted, there is a better way to generate this file when using the Django framework, but in this case we just need the import to succeed.)
To upgrade this example to use the Python 2.7 runtime environment, modify app.yaml as follows:
application: simpleform
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /static
static_dir: static
- url: /*.
script: simpleform.app
The changes:
runtime: is now python27
threadsafe: true is added
The reference to simpleform.py is now a Python object path to the global variable app.
Then modify simpleform.py so that everything following the definition of the SimpleInput class is replaced with:
app = webapp.WSGIApplication([('/.*', SimpleInput)], debug=True)
Instead of running the simpleform.py script, the Python 2.7 runtime environment imports it as a module, then looks for a WSGI application object in a global variable. The lines we removed executed the app, and that's now done for us by the runtime environment.
From here, you can use a libraries: clause as you have done to select a newer version of Django, if you wish. A quick test in a dev server shows that the modified example works with Django 1.5, which is the latest supported version.

i am trying to connect mysql using bottle.py, but it is showing error

I followed this link : "https://pypi.python.org/pypi/bottle-mysql/0.1.1"
and "http://bottlepy.org/docs/dev/"
this is my py file:
import bottle
from bottle import route, run, template
import bottle_mysql
app = bottle.Bottle()
# # dbhost is optional, default is localhost
plugin = bottle_mysql.Plugin(dbuser='root', dbpass='root', dbname='delhipoc')
app.install(plugin)
#route('/hai/<name>')
def show(name,dbname):
dbname.execute('SELECT id from poc_people where name="%s"', (name))
print "i am in show"
return template('<b>Hello {{name}}</b>!',name=name)
run(host='localhost', port=8080)
this is my code and it is throwing error like:
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\bottle.py", line 764, i
return route.call(**args)
File "C:\Python27\lib\site-packages\bottle.py", line 1575,
rv = callback(*a, **ka)
TypeError: show() takes exactly 2 arguments (1 given)
please help me
Not familiar with bottle-mysql, but in the example you provided:
#app.route('/show/:<tem>')
In your code:
#route('/hai/<name>')
It might expect:
#route('/hai/:<name>')
Simple. Change this line:
def show(name,dbname):
to this:
def show(name, delhipoc):
Better yet, use dbname = 'db' and then
def show(name, db):
The MySQL plugin has chosen an unfortunate name for its db name param. It would've been more clear to call it something like db_parameter_name, because what it actually refers to is the name of the db parameter in the decorated Python function.

Categories

Resources