Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drop python<=3.7 support #801

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/test-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
timeout-minutes: 20
strategy:
matrix:
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11', '3.12' ]
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ]
steps:
- name: Checkout twilio-python
uses: actions/checkout@v3
Expand Down
1 change: 0 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
Expand Down
6 changes: 3 additions & 3 deletions examples/basic_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def example():

# Get all messages
all_messages = client.messages.list()
print("There are {} messages in your account.".format(len(all_messages)))
print(f"There are {len(all_messages)} messages in your account.")

# Get only last 10 messages...
some_messages = client.messages.list(limit=10)
Expand All @@ -25,7 +25,7 @@ def example():

# Get messages in smaller pages...
all_messages = client.messages.list(page_size=10)
print("There are {} messages in your account.".format(len(all_messages)))
print(f"There are {len(all_messages)} messages in your account.")

print("Sending a message...")
new_message = client.messages.create(to="XXXX", from_="YYYY", body="Twilio rocks!")
Expand All @@ -38,7 +38,7 @@ def example():
twiml_response.say("Hello!")
twiml_response.hangup()
twiml_xml = twiml_response.to_xml()
print("Generated twiml: {}".format(twiml_xml))
print(f"Generated twiml: {twiml_xml}")


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion examples/client_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def example():
print("Trying out client validation...")
messages = client.messages.list(limit=10)
for m in messages:
print("Message {}".format(m.sid))
print(f"Message {m.sid}")

print("Client validation works!")

Expand Down
4 changes: 1 addition & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
help_center="https://www.twilio.com/help/contact",
url="https://github.com/twilio/twilio-python/",
keywords=["twilio", "twiml"],
python_requires=">=3.7.0",
python_requires=">=3.8",
install_requires=[
"requests >= 2.0.0",
"PyJWT >= 2.0.0, < 3.0.0",
Expand All @@ -33,8 +33,6 @@
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand Down
2 changes: 1 addition & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class IntegrationTestCase(unittest.TestCase):
def setUp(self):
super(IntegrationTestCase, self).setUp()
super().setUp()
self.account_sid = "AC" + "a" * 32
self.auth_token = "AUTHTOKEN"
self.holodeck = Holodeck()
Expand Down
10 changes: 5 additions & 5 deletions tests/holodeck.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from twilio import __version__


class Hologram(object):
class Hologram:
def __init__(self, request, response):
self.request = request
self.response = response
Expand All @@ -32,7 +32,7 @@ def add_standard_headers(self, request):
platform.machine(),
platform.python_version(),
),
"X-Twilio-Client": "python-{}".format(__version__),
"X-Twilio-Client": f"python-{__version__}",
"Accept": "application/json",
"Accept-Charset": "utf-8",
}
Expand All @@ -54,7 +54,7 @@ def assert_has_request(self, request):
)
if self._requests:
message += "Requests received:\n"
message += "\n".join(" * {}".format(r) for r in self.requests)
message += "\n".join(f" * {r}" for r in self.requests)
else:
message += "No Requests received"

Expand All @@ -79,10 +79,10 @@ def request(
if hologram.request == request:
return hologram.response

message = "\nHolodeck has no hologram for: {}\n".format(request)
message = f"\nHolodeck has no hologram for: {request}\n"
if self._holograms:
message += "Holograms loaded:\n"
message += "\n".join(" - {}".format(h.request) for h in self._holograms)
message += "\n".join(f" - {h.request}" for h in self._holograms)
else:
message += "No Holograms loaded"

Expand Down
1 change: 0 additions & 1 deletion tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
Sphinx>=1.8.0
mock
pytest
pytest-cov
aiounittest
Expand Down
1 change: 0 additions & 1 deletion tests/unit/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@

1 change: 0 additions & 1 deletion tests/unit/base/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@

2 changes: 1 addition & 1 deletion tests/unit/base/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def get_instance(self, payload):

class StreamTestCase(IntegrationTestCase):
def setUp(self):
super(StreamTestCase, self).setUp()
super().setUp()

self.holodeck.mock(
Response(
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/http/test_async_http_client.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import aiounittest

from aiohttp import ClientSession
from mock import patch, AsyncMock
from unittest.mock import patch, AsyncMock
from twilio.http.async_http_client import AsyncTwilioHttpClient


class MockResponse(object):
class MockResponse:
"""
A mock of the aiohttp.ClientResponse class
"""
Expand Down
3 changes: 1 addition & 2 deletions tests/unit/http/test_http_client.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
import os
import unittest
from collections import OrderedDict

from mock import Mock, patch
from unittest.mock import Mock, patch
from requests import Session

from twilio.base.exceptions import TwilioRestException
Expand Down
4 changes: 1 addition & 3 deletions tests/unit/http/test_validation_client.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-

import unittest

from mock import patch, Mock
from unittest.mock import patch, Mock
from requests import Request
from requests import Session

Expand Down
1 change: 0 additions & 1 deletion tests/unit/jwt/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@

4 changes: 2 additions & 2 deletions tests/unit/jwt/test_access_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ def assert_is_not_none(obj):


def assert_in(obj1, obj2):
assert obj1 in obj2, "%r is not in %r" % (obj1, obj2)
assert obj1 in obj2, "{!r} is not in {!r}".format(obj1, obj2)


def assert_greater_equal(obj1, obj2):
assert obj1 > obj2, "%r is not greater than or equal to %r" % (obj1, obj2)
assert obj1 > obj2, "{!r} is not greater than or equal to {!r}".format(obj1, obj2)


class AccessTokenTest(unittest.TestCase):
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/jwt/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
class ClientCapabilityTokenTest(unittest.TestCase):
def assertIn(self, foo, bar, msg=None):
"""backport for 2.6"""
assert foo in bar, msg or "%s not found in %s" % (foo, bar)
assert foo in bar, msg or "{} not found in {}".format(foo, bar)

def now(self):
return int(time.time())
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/jwt/test_jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import unittest

import jwt as jwt_lib
from mock import patch
from unittest.mock import patch

from twilio.jwt import Jwt, JwtDecodeError

Expand All @@ -24,7 +24,7 @@ def __init__(
headers=None,
payload=None,
):
super(DummyJwt, self).__init__(
super().__init__(
secret_key=secret_key,
issuer=issuer,
subject=subject,
Expand All @@ -46,7 +46,7 @@ def _generate_headers(self):
class JwtTest(unittest.TestCase):
def assertIn(self, foo, bar, msg=None):
"""backport for 2.6"""
assert foo in bar, msg or "%s not found in %s" % (foo, bar)
assert foo in bar, msg or "{} not found in {}".format(foo, bar)

def now(self):
return int(real_time.time())
Expand Down
12 changes: 6 additions & 6 deletions tests/unit/jwt/test_task_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ def test_defaults(self):
decoded = WorkerCapabilityToken.decode(token, self.auth_token)
self.assertNotEqual(None, decoded)

websocket_url = "https://event-bridge.twilio.com/v1/wschannels/{0}/{1}".format(
websocket_url = "https://event-bridge.twilio.com/v1/wschannels/{}/{}".format(
self.account_sid, self.worker_sid
)

Expand Down Expand Up @@ -297,7 +297,7 @@ def test_allow_activity_updates(self):
self.assertEqual(len(policies), 7)
policy = policies[6]

url = "https://taskrouter.twilio.com/v1/Workspaces/{0}/Workers/{1}".format(
url = "https://taskrouter.twilio.com/v1/Workspaces/{}/Workers/{}".format(
self.workspace_sid, self.worker_sid
)

Expand All @@ -322,13 +322,13 @@ def test_allow_reservation_updates(self):
self.assertEqual(len(policies), 8)

taskPolicy = policies[6]
tasksUrl = "https://taskrouter.twilio.com/v1/Workspaces/{0}/Tasks/**".format(
tasksUrl = "https://taskrouter.twilio.com/v1/Workspaces/{}/Tasks/**".format(
self.workspace_sid
)
self.check_policy("POST", tasksUrl, taskPolicy)

workerReservationsPolicy = policies[7]
reservationsUrl = "https://taskrouter.twilio.com/v1/Workspaces/{0}/Workers/{1}/Reservations/**".format(
reservationsUrl = "https://taskrouter.twilio.com/v1/Workspaces/{}/Workers/{}/Reservations/**".format(
self.workspace_sid, self.worker_sid
)
self.check_policy("POST", reservationsUrl, workerReservationsPolicy)
Expand All @@ -353,13 +353,13 @@ def test_pass_policies_in_constructor(self):
self.assertEqual(len(policies), 8)

taskPolicy = policies[6]
tasksUrl = "https://taskrouter.twilio.com/v1/Workspaces/{0}/Tasks/**".format(
tasksUrl = "https://taskrouter.twilio.com/v1/Workspaces/{}/Tasks/**".format(
self.workspace_sid
)
self.check_policy("POST", tasksUrl, taskPolicy)

workerReservationsPolicy = policies[7]
reservationsUrl = "https://taskrouter.twilio.com/v1/Workspaces/{0}/Workers/{1}/Reservations/**".format(
reservationsUrl = "https://taskrouter.twilio.com/v1/Workspaces/{}/Workers/{}/Reservations/**".format(
self.workspace_sid, self.worker_sid
)
self.check_policy("POST", reservationsUrl, workerReservationsPolicy)
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/rest/test_client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import unittest
import aiounittest

from mock import AsyncMock, Mock
from unittest.mock import AsyncMock, Mock
from twilio.http.response import Response
from twilio.rest import Client

Expand Down
1 change: 0 additions & 1 deletion tests/unit/test_request_validator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
import unittest

from django.conf import settings
Expand Down
1 change: 0 additions & 1 deletion tests/unit/twiml/test_voice_response.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from tests.unit.twiml import TwilioTest
from twilio.twiml.voice_response import VoiceResponse, Dial, Enqueue, Gather

Expand Down
8 changes: 4 additions & 4 deletions twilio/base/client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from twilio.http.response import Response


class ClientBase(object):
class ClientBase:
"""A client for accessing the Twilio API."""

def __init__(
Expand Down Expand Up @@ -179,8 +179,8 @@ def get_headers(
)
# Extensions
for extension in self.user_agent_extensions:
headers["User-Agent"] += " {}".format(extension)
headers["X-Twilio-Client"] = "python-{}".format(__version__)
headers["User-Agent"] += f" {extension}"
headers["X-Twilio-Client"] = f"python-{__version__}"

# Types, encodings, etc.
headers["Accept-Charset"] = "utf-8"
Expand Down Expand Up @@ -231,4 +231,4 @@ def __repr__(self) -> str:

:returns: Machine friendly representation
"""
return "<Twilio {}>".format(self.account_sid)
return f"<Twilio {self.account_sid}>"
2 changes: 1 addition & 1 deletion twilio/base/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from twilio.rest import Client


class Domain(object):
class Domain:
"""
This represents at Twilio API subdomain.

Expand Down
7 changes: 3 additions & 4 deletions twilio/base/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
import sys
from typing import Optional

Expand Down Expand Up @@ -51,7 +50,7 @@ def teal(words: str) -> str:
return "\033[36m\033[49m%s\033[0m" % words

def get_uri(code: int) -> str:
return "https://www.twilio.com/docs/errors/{0}".format(code)
return f"https://www.twilio.com/docs/errors/{code}"

# If it makes sense to print a human readable error message, try to
# do it. The one problem is that someone might catch this error and
Expand All @@ -62,7 +61,7 @@ def get_uri(code: int) -> str:
"\n\n{twilio_returned}\n\n{message}\n".format(
red_error=red("HTTP Error"),
request_was=white("Your request was:"),
http_line=teal("%s %s" % (self.method, self.uri)),
http_line=teal("{} {}".format(self.method, self.uri)),
twilio_returned=white("Twilio returned the following information:"),
message=blue(str(self.msg)),
)
Expand All @@ -79,4 +78,4 @@ def get_uri(code: int) -> str:
)
return msg
else:
return "HTTP {0} error: {1}".format(self.status, self.msg)
return f"HTTP {self.status} error: {self.msg}"
2 changes: 1 addition & 1 deletion twilio/base/instance_context.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from twilio.base.version import Version


class InstanceContext(object):
class InstanceContext:
def __init__(self, version: Version):
self._version = version
2 changes: 1 addition & 1 deletion twilio/base/instance_resource.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from twilio.base.version import Version


class InstanceResource(object):
class InstanceResource:
def __init__(self, version: Version):
self._version = version
2 changes: 1 addition & 1 deletion twilio/base/list_resource.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from twilio.base.version import Version


class ListResource(object):
class ListResource:
def __init__(self, version: Version):
self._version = version
4 changes: 2 additions & 2 deletions twilio/base/obsolete.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ def deprecated_method(new_func=None):
def deprecated_method_wrapper(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
msg = "Function method .{}() is deprecated".format(func.__name__)
msg = f"Function method .{func.__name__}() is deprecated"
msg += (
" in favor of .{}()".format(new_func)
f" in favor of .{new_func}()"
if isinstance(new_func, str)
else ""
)
Expand Down
Loading
Loading