Skip to content

Commit

Permalink
start adding number insight
Browse files Browse the repository at this point in the history
  • Loading branch information
maxkahan committed Apr 24, 2024
1 parent b304344 commit 8c5b806
Show file tree
Hide file tree
Showing 18 changed files with 323 additions and 0 deletions.
16 changes: 16 additions & 0 deletions number_insight/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
resource(name='pyproject', source='pyproject.toml')
file(name='readme', source='README.md')

files(sources=['tests/data/*'])

python_distribution(
name='vonage-number-insight',
dependencies=[
':pyproject',
':readme',
'number_insight/src/vonage_number_insight',
],
provides=python_artifact(),
generate_setup=False,
repositories=['@pypi'],
)
2 changes: 2 additions & 0 deletions number_insight/CHANGES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# 1.0.0
- Initial upload
9 changes: 9 additions & 0 deletions number_insight/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Vonage Number Insight Package

This package contains the code to use [Vonage's Number Insight API](https://developer.vonage.com/en/number-insight/overview) in Python. This package includes methods to get information about phone numbers. It has 3 levels of insight, basic, standard, and advanced.

## Usage

It is recommended to use this as part of the main `vonage` package. The examples below assume you've created an instance of the `vonage.Vonage` class called `vonage_client`.

### Make a Basic Number Insight Request
29 changes: 29 additions & 0 deletions number_insight/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[project]
name = 'vonage-number-insight'
version = '1.0.0'
description = 'Vonage Number Insight package'
readme = "README.md"
authors = [{ name = "Vonage", email = "devrel@vonage.com" }]
requires-python = ">=3.8"
dependencies = [
"vonage-http-client>=1.3.0",
"vonage-utils>=1.1.0",
"pydantic>=2.6.1",
]
classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"License :: OSI Approved :: Apache Software License",
]

[project.urls]
homepage = "https://github.com/Vonage/vonage-python-sdk"

[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
1 change: 1 addition & 0 deletions number_insight/src/vonage_number_insight/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python_sources()
3 changes: 3 additions & 0 deletions number_insight/src/vonage_number_insight/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .number_insight import NumberInsight

__all__ = ['NumberInsight']
Empty file.
5 changes: 5 additions & 0 deletions number_insight/src/vonage_number_insight/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from vonage_utils.errors import VonageError


class NumberInsightError(VonageError):
"""Indicates an error when using the Vonage Number Insight API."""
139 changes: 139 additions & 0 deletions number_insight/src/vonage_number_insight/number_insight.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
from pydantic import validate_call
from vonage_http_client.http_client import HttpClient

from .errors import NumberInsightError
from .requests import (
AdvancedAsyncInsightRequest,
AdvancedSyncInsightRequest,
BasicInsightRequest,
StandardInsightRequest,
)
from .responses import (
AdvancedAsyncInsightResponse,
AdvancedSyncInsightResponse,
BasicInsightResponse,
StandardInsightResponse,
)


class NumberInsight:
"""Calls Vonage's Number Insight API."""

def __init__(self, http_client: HttpClient) -> None:
self._http_client = http_client
self._auth_type = 'body'

@property
def http_client(self) -> HttpClient:
"""The HTTP client used to make requests to the Verify V2 API.
Returns:
HttpClient: The HTTP client used to make requests to the Verify V2 API.
"""
return self._http_client

@validate_call
def basic_number_insight(self, options: BasicInsightRequest) -> BasicInsightResponse:
"""Get basic number insight information about a phone number.
Args:
Options (BasicInsightRequest): The options for the request. The `number` paramerter
is required, and the `country_code` parameter is optional.
Returns:
BasicInsightResponse: The response object containing the basic number insight
information about the phone number.
"""
response = self._http_client.get(
self._http_client.api_host,
'/ni/basic/json',
params=options.model_dump(exclude_none=True),
auth_type=self._auth_type,
)
self._check_for_error(response)

return BasicInsightResponse(**response)

@validate_call
def standard_number_insight(
self, options: StandardInsightRequest
) -> StandardInsightResponse:
"""Get standard number insight information about a phone number.
Args:
Options (StandardInsightRequest): The options for the request. The `number` paramerter
is required, and the `country_code` and `cnam` parameters are optional.
Returns:
StandardInsightResponse: The response object containing the standard number insight
information about the phone number.
"""
response = self._http_client.get(
self._http_client.api_host,
'/ni/standard/json',
params=options.model_dump(exclude_none=True),
auth_type=self._auth_type,
)
self._check_for_error(response)

return StandardInsightResponse(**response)

@validate_call
def advanced_async_number_insight(
self, options: AdvancedAsyncInsightRequest
) -> AdvancedAsyncInsightResponse:
"""Get advanced number insight information about a phone number asynchronously.
Args:
Options (AdvancedAsyncInsightRequest): The options for the request. You must provide values
for the `callback` and `number` parameters. The `country_code` and `cnam` parameters
are optional.
Returns:
AdvancedAsyncInsightResponse: The response object containing the advanced number insight
information about the phone number.
"""
response = self._http_client.get(
self._http_client.api_host,
'/ni/advanced/async/json',
params=options.model_dump(exclude_none=True),
auth_type=self._auth_type,
)

return AdvancedAsyncInsightResponse(**response)

@validate_call
def advanced_sync_number_insight(
self, options: AdvancedSyncInsightRequest
) -> AdvancedSyncInsightResponse:
"""Get advanced number insight information about a phone number synchronously.
Args:
Options (AdvancedSyncInsightRequest): The options for the request. The `number` parameter
is required, and the `country_code`, `cnam`, and `real_time_data` parameters are optional.
Returns:
AdvancedSyncInsightResponse: The response object containing the advanced number insight
information about the phone number.
"""
response = self._http_client.get(
self._http_client.api_host,
'/ni/advanced/json',
params=options.model_dump(exclude_none=True),
auth_type=self._auth_type,
)

return AdvancedSyncInsightResponse(**response)

def _check_for_error(self, response: dict) -> None:
"""Check for an error in the response from the Number Insight API.
Args:
response (dict): The response from the Number Insight API.
Raises:
NumberInsightError: If the response contains an error.
"""
if response['status'] != 0:
error_message = f'Error with the following details: {response}'
raise NumberInsightError(error_message)
21 changes: 21 additions & 0 deletions number_insight/src/vonage_number_insight/requests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from typing import Optional

from pydantic import BaseModel
from vonage_utils.types import PhoneNumber


class BasicInsightRequest(BaseModel):
number: PhoneNumber
country: Optional[str] = None


class StandardInsightRequest(BasicInsightRequest):
cnam: Optional[bool] = None


class AdvancedAsyncInsightRequest(StandardInsightRequest):
callback: str


class AdvancedSyncInsightRequest(StandardInsightRequest):
real_time_data: Optional[bool] = None
27 changes: 27 additions & 0 deletions number_insight/src/vonage_number_insight/responses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from typing import Optional

from pydantic import BaseModel


class BasicInsightResponse(BaseModel):
status: int = None
status_message: str = None
request_id: Optional[str] = None
international_format_number: Optional[str] = None
national_format_number: Optional[str] = None
country_code: Optional[str] = None
country_code_iso3: Optional[str] = None
country_name: Optional[str] = None
country_prefix: Optional[str] = None


class StandardInsightResponse(BasicInsightResponse):
...


class AdvancedAsyncInsightResponse(BaseModel):
...


class AdvancedSyncInsightResponse(BaseModel):
...
1 change: 1 addition & 0 deletions number_insight/tests/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python_tests(dependencies=['number_insight', 'testutils'])
11 changes: 11 additions & 0 deletions number_insight/tests/data/basic_insight.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"status": 0,
"status_message": "Success",
"request_id": "7f4a8a16-aa89-4078-b0ae-7743da34aca5",
"international_format_number": "12345678900",
"national_format_number": "(234) 567-8900",
"country_code": "US",
"country_code_iso3": "USA",
"country_name": "United States of America",
"country_prefix": "1"
}
4 changes: 4 additions & 0 deletions number_insight/tests/data/basic_insight_error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"status": 3,
"status_message": "Invalid request :: Not valid number format detected [ 145645562 ]"
}
50 changes: 50 additions & 0 deletions number_insight/tests/test_number_insight.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from os.path import abspath

import responses
from pytest import raises
from vonage_http_client.http_client import HttpClient
from vonage_number_insight.errors import NumberInsightError
from vonage_number_insight.number_insight import NumberInsight
from vonage_number_insight.requests import BasicInsightRequest

from testutils import build_response, get_mock_api_key_auth

path = abspath(__file__)


number_insight = NumberInsight(HttpClient(get_mock_api_key_auth()))


def test_http_client_property():
http_client = number_insight.http_client
assert isinstance(http_client, HttpClient)


@responses.activate
def test_basic_insight():
build_response(
path,
'GET',
'https://api.nexmo.com/ni/basic/json',
'basic_insight.json',
)
options = BasicInsightRequest(number='12345678900', country_code='US')
response = number_insight.basic_number_insight(options)
assert response.status == 0
assert response.status_message == 'Success'


@responses.activate
def test_basic_insight_error():
build_response(
path,
'GET',
'https://api.nexmo.com/ni/basic/json',
'basic_insight_error.json',
)

with raises(NumberInsightError) as e:
options = BasicInsightRequest(number='1234567890', country_code='US')
number_insight.basic_number_insight(options)
assert e.match('Invalid request :: Not valid number format detected')
assert 0
1 change: 1 addition & 0 deletions pants.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ filter = [
'vonage/src',
'http_client/src',
'messages/src',
'number_insight/src',
'number_insight_v2/src',
'sms/src',
'users/src',
Expand Down
2 changes: 2 additions & 0 deletions vonage/src/vonage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
Auth,
HttpClientOptions,
Messages,
NumberInsight,
NumberInsightV2,
Sms,
Users,
Expand All @@ -18,6 +19,7 @@
'Auth',
'HttpClientOptions',
'Messages',
'NumberInsight',
'NumberInsightV2',
'Sms',
'Users',
Expand Down
2 changes: 2 additions & 0 deletions vonage/src/vonage/vonage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from vonage_http_client import Auth, HttpClient, HttpClientOptions
from vonage_messages import Messages
from vonage_number_insight import NumberInsight
from vonage_number_insight_v2 import NumberInsightV2
from vonage_sms import Sms
from vonage_users import Users
Expand Down Expand Up @@ -31,6 +32,7 @@ def __init__(
self._http_client = HttpClient(auth, http_client_options, __version__)

self.messages = Messages(self._http_client)
self.number_insight = NumberInsight(self._http_client)
self.number_insight_v2 = NumberInsightV2(self._http_client)
self.sms = Sms(self._http_client)
self.users = Users(self._http_client)
Expand Down

0 comments on commit 8c5b806

Please sign in to comment.