Usage and Migration Guide for Twilio's Python Helper Library 6.x
Deprecation notice: New functionality will only be added to the new library (Python Helper Library 6.x). The old library (5.x) is deprecated and Twilio will no longer provide bug fixes. Support might ask you to upgrade before debugging issues.
The Twilio Python Helper Library has undergone a number of changes from version 5.x to 6.x - we'll break down the major changes here to make migrating to the new version as painless as possible. If you're integrating Twilio in your Python app for the first time, you can skip straight to the install page.
Python Version Support
Version 6.x of the Python SDK requires at least Python version 2.7. It will work with later versions, including Python 3.x versions.
Importing the Library
In twilio-python
5.x, you would import clients like this:
from twilio.rest import TwilioRestClient
from twilio.rest import TwilioLookupsClient
from twilio.rest import TwilioTaskRouterClient
...
Now, in 6.x, there is only 1 object you need to import:
from twilio.rest import Client
You can initialize it just as you did TwilioRestClient
before:
from twilio.rest import Client
client = Client('ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'your_auth_token')
Accessing Resources
# Old
call = client.account.calls('CA123xxx')
# New
call = client.api.v2010.calls('CA123xxx').fetch()
## OR
call = client.calls('CA123xxx').fetch()
The new library makes Twilio API subdomains (Lookups, Conversations, Monitor, etc.) first-class citizens. You can now also pin your interactions to the Twilio API to specific versions of that API (so here, .v2010.
ensures we always talk to the 2010-04-01 version of the API). This allows you to migrate portions of your code to future versions independently without having to do a full upgrade when you update the library.
You'll also notice you have to call fetch
at the end to get the actual instance of a Call
. This is because .calls('CAxxx')
returns a "Context", which we can then fetch
to retrieve an "Instance", with all of it's properties attached. This allows for better network efficiency and makes it more clear when the library is actually performing HTTP interactions.
> workspace = client.taskrouter.workspaces('WSxxx')
#=> <WorkspaceContext ...>
> workspace.fetch()
#=> <WorkspaceInstance status='active'...>
Phone Numbers endpoints
In 5.x, IncomingPhoneNumbers
and AvailablePhoneNumbers
were rolled into one resource:
# Old
numbers = client.account.phone_numbers.search(country_code='US', type='Local', area_code='415')
if numbers:
new_number = client.account.phone_numbers.create(phone_number=numbers[0].phone_number)
print('Bought {}!'.format(new_number.phone_number))
In 6.x, we split the two endpoints so that they were consistent with the rest of the endpoints and so that it is more clear what endpoints of the Twilio API you are actually interacting with at any given time:
numbers = client.api.available_phone_numbers('US').local.list(area_code='415')
if numbers:
new_number = client.incoming_phone_numbers.create(phone_number=numbers[0].phone_number)
print('Bought {}!'.format(new_number.phone_number))
Listing Resources
There are now 2 ways to get a list of resources: list
and stream
.
list
does exactly what it always has: it returns anArray
that contains the Instances of resources.
> client.api.messages.list()
#=> [#<MessageInstance ..>, #<MessageInstance ..>, ...]
stream
returns agenerator
, it efficiently pages the list of resources for you and will yieldlimit
amount of instances (or every resource in the entire list, if nolimit
is set).
> for message in client.api.messages.stream(limit=5)
> .. print(message.sid)
MS111xxx
MS222xxx
MS333xxx
MS444xxx
MS555xxx
Paging
The library now automatically handles paging for you! In both list
and stream
, you can specify the amount of instances you want to grab (limit
), the maximum size you want each page fetch to be (page_size
), and the maximum amount of pages to fetch (page_limit
). The library will then handle the rest for you (as efficiently as possible)!
for number in client.api.incoming_phone_numbers.stream(limit=3000, page_size=100):
print(number.phone_number)
> len(client.conversations.completed.list(page_size=100, page_limit=10))
#=> 1000
Proper Types
twilio-python
resources now serialize/deserialize appropriate types. For example, in 5.x, a date would be represented as a string
, leaving it up to you to serialize/deserialize strings into usable types. In 6.x, we deal with datetime
objects:
# Old
feedback = client.account.calls.feedback_summary.create(start_date='2016-01-01', end_date='2016-01-05')
feedback.start_date #=> "2016-01-01"
# New
feedback = client.api.calls.feedback_summary.create(start_date=datetime(2016, 1, 1),
end_date=datetime(2016, 1, 5))
feedback.start_date #=> datetime.datetime(2016, 1, 1, 0, 0)
Configurable HTTP Client
You can now plug your own HTTP client into the Twilio
client! Just make a wrapper that conforms to the HttpClient Interface. Then, pass an initialized object into the Twilio
object:
custom_client = MyCustomClient()
client = Twilio('ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 'your_auth_token', http_client=custom_client)
See a complete example of creating a custom client in the Twilio helper library.
TwiML Generation
You can now chain your calls to output simple TwiML like so:
from twilio.twiml.voice_response import VoiceResponse
def output_quick_polite_twiml():
return VoiceResponse().say('Hello!').hangup()
Notice also, there is now two responses types depending on what kind of response you want to output, VoiceResponse
for all voice related verbs and MessagingResponse
for everything message related.
You can find any voice verbs available as a method of a VoiceResponse
instance. And you can set any attributes for those verbs using keyword arguments. All of them are using the underscore notation.
Nesting verbs are no longer using the with
syntax, but instead, are append
to a parent.
The same changes apply to MessagingResponse
:
And a nested example:
Debugging API Requests
To assist with debugging, the library allows you to access the underlying request and response objects. This capability is built into the default HTTP client that ships with the library.
For example, you can retrieve the status code of the last response like so:
from twilio.rest import Client
# put your own credentials here
account_sid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
auth_token = "your_auth_token"
client = Client(account_sid, auth_token)
client.messages.create(to="+14158675309", from_="+14258675310", body="Ahoy!")
# Retrieve the status code of the last response from the HTTP client
print(client.http_client.last_response.status_code)
Handling exceptions
Version 6.x of twilio-python
exports an exception class to aid with handling exceptions that are specific to Twilio methods.
To use it, import the TwilioRestException
and catch it in a given try-except
block.
from twilio.base.exceptions import TwilioRestException
try:
# This could potentially throw an exception!
message = client.messages.create(
to="+15558675309",
from_="+15017250604",
body="Hello there!")
except TwilioRestException as e:
# Implement your fallback code
print(e)
Where to Find Help
All of the Quickstarts, Tutorials, and API Reference documentation will have example code in both the older 5.x library and the new 6.x library. There are hundreds of samples just waiting for you to copy and paste.
The Twilio Python helper library is open source software. Please visit us on GitHub to view the source, open issues, or submit pull requests.
Finally, we are always ready to help. Just contact us directly for support.
Need some help?
We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd by visiting Twilio's Stack Overflow Collective or browsing the Twilio tag on Stack Overflow.