Skip to content
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion twilio/http/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,22 @@


class Match(Enum):
"""
Special enumeration used to represent a wildcard match.

The value ANY ("*") is used to indicate that any value
for a given attribute should be considered a match.
"""
ANY = "*"


class Request(object):
"""
An HTTP request.
Represents an HTTP request definition.

This class is mainly used to describe or compare HTTP requests
based on attributes such as method, URL, parameters, headers,
authentication, and request body data.
"""

def __init__(
Expand All @@ -22,27 +32,52 @@ def __init__(
headers: Union[Dict[str, str], Match] = Match.ANY,
**kwargs: Any
):
# HTTP method (GET, POST, etc.) or Match.ANY as a wildcard
self.method = method

# Normalize the HTTP method to uppercase if provided
if method and method is not Match.ANY:
self.method = method.upper()

# Request URL or wildcard
self.url = url

# Authentication tuple (username, password) or wildcard
self.auth = auth

# Query parameters sent with the request
self.params = params

# Request body data
self.data = data

# HTTP headers included in the request
self.headers = headers

@classmethod
def attribute_equal(cls, lhs, rhs) -> bool:
"""
Compares two request attributes, supporting wildcard matching.

If either side is Match.ANY, the attributes are considered equal.
"""
if lhs == Match.ANY or rhs == Match.ANY:
# ANY matches everything
return True

# Normalize falsy values to None before comparison
lhs = lhs or None
rhs = rhs or None

return lhs == rhs

def __eq__(self, other) -> bool:
"""
Compares two Request objects for equality.

Each attribute is compared individually using attribute_equal
to allow wildcard matching.
"""
if not isinstance(other, Request):
return False

Expand All @@ -56,20 +91,31 @@ def __eq__(self, other) -> bool:
)

def __str__(self) -> str:
"""
Returns a human-readable representation of the request.

The format resembles a curl-like representation including
parameters, headers, and request body.
"""
params = ""
if self.params and self.params != Match.ANY:
# Encode query parameters for URL usage
params = "?{}".format(urlencode(self.params, doseq=True))

data = ""
if self.data and self.data != Match.ANY:
# If the request is GET, mimic curl's -G option
if self.method == "GET":
data = "\n -G"

# Format request body parameters
data += "\n{}".format(
"\n".join(' -d "{}={}"'.format(k, v) for k, v in self.data.items())
)

headers = ""
if self.headers and self.headers != Match.ANY:
# Format headers, excluding authorization for security reasons
headers = "\n{}".format(
"\n".join(
' -H "{}: {}"'.format(k, v)
Expand All @@ -87,4 +133,9 @@ def __str__(self) -> str:
)

def __repr__(self) -> str:
"""
Returns the string representation of the Request object.

Used mainly for debugging or logging.
"""
return str(self)
17 changes: 17 additions & 0 deletions twilio/http/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@


class Response(object):
"""
Represents a simplified HTTP response.

This class stores the HTTP status code, response body content,
and optional HTTP headers returned by a request.
"""
def __init__(
self,
status_code: int,
Expand All @@ -16,7 +22,18 @@ def __init__(

@property
def text(self) -> str:
"""
Returns the response body as text.

This property provides a clearer way to access the response
content stored in `self.content`.
"""
return self.content

def __repr__(self) -> str:
"""
Returns a string representation of the Response object.

Mainly used for debugging purposes.
"""
return "HTTP {} {}".format(self.status_code, self.content)
Loading