Skip to content
Merged
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
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ If you are migrating to version 5.0.0 or above from an earlier version, please c

We support all the endpoints available in our API.

* `oauth2`
* `accounts`
* `oauth2` (deprecated, use `access_token` instead)
* `accounts` (deprecated)
* `broadcasts`
* `events`
* `features`
* `places`
* `radius`
* `beam`
* `saved_locations`

Please refer to our [API Documentation](https://docs.predicthq.com/) for a description of each endpoint.

Expand Down Expand Up @@ -316,6 +317,27 @@ for event in phq.events.search(config={"verify_ssl": False}):
```


### Saved_Locations endpoints

Additional examples are available in [usecases/saved_locations.py](https://github.com/predicthq/sdk-py/tree/master/usecases/places.py) file.

The following example searches for the saved_locations according to the parameters defined:

```Python
from predicthq import Client

phq = Client(access_token="abc123")


for saved_location in phq.saved_locations.search(
labels=["test", "retail"],
q="London",
sort="-created",
):
print(saved_location.location_id, saved_location.create_dt, saved_location.status)
```


## Running Tests

```Shell
Expand Down
1 change: 1 addition & 0 deletions predicthq/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def initialize_endpoints(self):
self.places = endpoints.PlacesEndpoint(proxy(self))
self.radius = endpoints.SuggestedRadiusEndpoint(proxy(self))
self.beam = endpoints.BeamEndpoint(proxy(self))
self.saved_locations = endpoints.SavedLocationsEndpoint(proxy(self))

def get_headers(self, headers):
_headers = {
Expand Down
1 change: 0 additions & 1 deletion predicthq/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@


class Config(object):

_config_sections = (
"endpoint",
"oauth2",
Expand Down
2 changes: 2 additions & 0 deletions predicthq/endpoints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .v1.places import PlacesEndpoint
from .v1.radius import SuggestedRadiusEndpoint
from .v1.beam import BeamEndpoint
from .v1.saved_locations import SavedLocationsEndpoint


__all__ = [
Expand All @@ -17,4 +18,5 @@
"PlacesEndpoint",
"SuggestedRadiusEndpoint",
"BeamEndpoint",
"SavedLocationsEndpoint",
]
2 changes: 1 addition & 1 deletion predicthq/endpoints/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ def __new__(mcs, name, bases, data):
if "Meta" not in data:

class Meta:
""" Used by decorators when overriding schema classes """
"""Used by decorators when overriding schema classes"""

pass

Expand Down
15 changes: 15 additions & 0 deletions predicthq/endpoints/oauth2/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@
from predicthq.endpoints.decorators import accepts, returns
from .decorators import preload_config_defaults
from .schemas import AccessToken
from deprecated import deprecated


class OAuth2Endpoint(BaseEndpoint):
@deprecated(
reason=(
"OAuth2 endpoints in the SDK are deprecated and will be removed in future releases. "
"Use TokenAuth (API Access Token) with Client(..., access_token=...)."
),
category=FutureWarning,
)
@accepts()
@preload_config_defaults(["client_id", "client_secret", "scope", "grant_type"])
@returns(AccessToken)
Expand All @@ -22,6 +30,13 @@ def get_token(self, client_id, client_secret, scope, grant_type, **kwargs):
verify=verify_ssl,
)

@deprecated(
reason=(
"OAuth2 endpoints in the SDK are deprecated and will be removed in future releases. "
"Use TokenAuth (API Access Token) with Client(..., access_token=...)."
),
category=FutureWarning,
)
@accepts()
@preload_config_defaults(["client_id", "client_secret", "token_type_hint"])
def revoke_token(self, client_id, client_secret, token, token_type_hint, **kwargs):
Expand Down
8 changes: 8 additions & 0 deletions predicthq/endpoints/v1/accounts/endpoint.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
from predicthq.endpoints.base import BaseEndpoint
from predicthq.endpoints.decorators import returns
from .schemas import Account
from deprecated import deprecated


class AccountsEndpoint(BaseEndpoint):
@deprecated(
reason=(
"The Accounts endpoint in the SDK is deprecated and will be removed in future releases. "
"Account information can be managed via the PredictHQ dashboard."
),
category=FutureWarning,
)
@returns(Account)
def self(self):
return self.client.get(self.build_url("v1", "accounts/self"))
6 changes: 3 additions & 3 deletions predicthq/endpoints/v1/beam/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
AnalysisGroup,
AnalysisGroupResultSet,
GeoJson,
Place
Place,
)
from predicthq.endpoints.decorators import accepts, returns
from typing import overload, List, Optional, TextIO, Union
Expand Down Expand Up @@ -185,8 +185,8 @@ def upload_demand(
self,
analysis_id: str,
json: Optional[Union[str, TextIO]] = None,
ndjson: Optional[Union[str, TextIO]] = None,
csv: Optional[Union[str, TextIO]] = None,
ndjson: Optional[Union[str, TextIO]] = None,
csv: Optional[Union[str, TextIO]] = None,
**params,
): ...
def upload_demand(self, analysis_id: str, **params):
Expand Down
11 changes: 6 additions & 5 deletions predicthq/endpoints/v1/beam/schemas.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from pydantic import BaseModel, Field, ConfigDict
from datetime import datetime
from predicthq.endpoints.schemas import ArgKwargResultSet
from typing import Optional, List
from typing import Optional, List, Union

# Python < 3.11 does not have StrEnum in the enum module
import sys

if sys.version_info < (3, 11):
import enum

Expand Down Expand Up @@ -38,7 +39,6 @@ def get_next(self):
return self._more(**self._kwargs)



class CreateAnalysisResponse(BaseModel):
model_config: ConfigDict = ConfigDict(extra="allow")

Expand All @@ -55,10 +55,11 @@ class GeoPoint(BaseModel):
class Location(BaseModel):
model_config: ConfigDict = ConfigDict(extra="allow")

geopoint: GeoPoint
radius: float
unit: str
geopoint: Optional[GeoPoint] = None
radius: Optional[float] = None
unit: Optional[str] = None
google_place_id: Optional[str] = None
saved_location_id: Optional[str] = None


class RankLevel(BaseModel):
Expand Down
4 changes: 1 addition & 3 deletions predicthq/endpoints/v1/features/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ class FeaturesEndpoint(UserBaseEndpoint):
def mutate_bool_to_default_for_type(cls, user_request_spec):
for key, val in user_request_spec.items():
if any(key.startswith(x) for x in cls.FIELDS_TO_MUTATE):
user_request_spec[key] = [
cls.BASE_FEATURE_CRITERIA if isinstance(v, bool) else v for v in val
]
user_request_spec[key] = [cls.BASE_FEATURE_CRITERIA if isinstance(v, bool) else v for v in val]

@accepts(query_string=False)
@returns(FeatureResultSet)
Expand Down
4 changes: 1 addition & 3 deletions predicthq/endpoints/v1/features/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ def __flatten_json(d: dict, pk: str = "") -> dict:
flat_json = {}
for k, v in d.items():
if isinstance(v, dict):
flat_json.update(
__flatten_json(v, f"{pk}{separator}{k}" if pk else k)
)
flat_json.update(__flatten_json(v, f"{pk}{separator}{k}" if pk else k))
continue
flat_json.update({f"{pk}{separator}{k}" if pk else k: v})
return flat_json
Expand Down
5 changes: 5 additions & 0 deletions predicthq/endpoints/v1/saved_locations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .endpoint import SavedLocationsEndpoint
from .schemas import SavedLocation


__all__ = ["SavedLocationsEndpoint", "SavedLocation"]
168 changes: 168 additions & 0 deletions predicthq/endpoints/v1/saved_locations/endpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
from predicthq.endpoints.base import UserBaseEndpoint, BaseEndpoint
from predicthq.endpoints.decorators import accepts, returns
Comment thread
medhatphq marked this conversation as resolved.
from typing import overload, List, Optional
from .schemas import (
SavedLocation,
SavedLocationResultSet,
CreateSavedLocationResponse,
PostSharingEnableResponse,
SuggestedRadiusResponse,
Location,
)
from ..events.schemas import EventResultSet


class SavedLocationsEndpoint(UserBaseEndpoint):
@overload
def search(
self,
location_id: Optional[List[str]] = None,
location_code: Optional[List[str]] = None,
labels: Optional[List[str]] = None,
user_id: Optional[List[str]] = None,
subscription_valid_types: Optional[List[str]] = None,
q: Optional[str] = None,
sort: Optional[List[str]] = None,
offset: Optional[int] = None,
limit: Optional[int] = None,
**params,
): ...
@accepts()
@returns(SavedLocationResultSet)
def search(self, **params):
verify_ssl = params.pop("config.verify_ssl", True)
result = self.client.get(
self.build_url("v1", "saved-locations"),
params=params,
verify=verify_ssl,
)
return result

@overload
def create(
self,
name: str,
geojson: dict,
labels: Optional[List[str]] = None,
location_code: Optional[str] = None,
formatted_address: Optional[str] = None,
description: Optional[str] = None,
place_ids: Optional[List[str]] = None,
**params,
): ...
@accepts(query_string=False)
@returns(CreateSavedLocationResponse)
def create(self, **params):
verify_ssl = params.pop("config.verify_ssl", True)

result = self.client.post(
f"{self.build_url('v1', 'saved-locations')}",
json=params,
verify=verify_ssl,
)
return result

@accepts()
@returns(SavedLocation)
def get(self, location_id, **params):
verify_ssl = params.pop("config.verify_ssl", True)
return self.client.get(
f"{self.build_url('v1', 'saved-locations')}{location_id}",
params=params,
verify=verify_ssl,
)

@overload
def search_event_result_set(
location_id: str,
date_range_type: Optional[str] = None,
offset: Optional[int] = None,
limit: Optional[int] = None,
**params,
): ...
@returns(EventResultSet)
def search_event_result_set(self, location_id, **params):
verify_ssl = params.pop("config.verify_ssl", True)
url = f"{self.build_url('v1', 'saved-locations')}{location_id}/insights/events"
response = self.client.get(
url,
params=params,
verify=verify_ssl,
)
return response

@accepts()
def refresh_location_insights(self, location_id: str, **params):
verify_ssl = params.pop("config.verify_ssl", True)
return self.client.post(
f"{self.build_url('v1', 'saved-locations')}{location_id}/insights/refresh",
params=params,
verify=verify_ssl,
)

@overload
def replace_location_data(
self,
location_id: str,
name: str,
geojson: dict,
labels: Optional[List[str]] = None,
location_code: Optional[str] = None,
formatted_address: Optional[str] = None,
description: Optional[str] = None,
place_ids: Optional[List[str]] = None,
external_id: Optional[str] = None,
**params,
): ...
@accepts(query_string=False)
def replace_location_data(self, location_id: str, **params):
verify_ssl = params.pop("config.verify_ssl", True)
params.pop("location_id", None) # Remove location_id from payload
response = self.client.put(
f"{self.build_url('v1', 'saved-locations')}{location_id}",
json=params,
verify=verify_ssl,
)
return response

@accepts()
def delete_location(self, location_id: str, **params):
verify_ssl = params.pop("config.verify_ssl", True)
return self.client.delete(
f"{self.build_url('v1', 'saved-locations')}{location_id}",
params=params,
verify=verify_ssl,
)

@accepts()
@returns(PostSharingEnableResponse)
def sharing_enable(self, location_id: str, **params):
verify_ssl = params.pop("config.verify_ssl", True)
return self.client.post(
f"{self.build_url('v1', 'saved-locations')}{location_id}/sharing/enable",
params=params,
verify=verify_ssl,
)

@overload
def suggested_radius(
self,
location_origin: Location,
radius_unit: str,
industry: str,
**params,
): ...
@accepts(query_string=False)
@returns(SuggestedRadiusResponse)
def suggested_radius(self, **params):
verify_ssl = params.pop("config.verify_ssl", True)
loc = params.pop("location_origin", None)
if isinstance(loc, Location):
params["location.origin"] = loc.as_geopoint()
elif isinstance(loc, str):
params["location.origin"] = loc
return self.client.get(
f"{self.build_url('v1', 'suggested-radius')}",
params=params,
verify=verify_ssl,
)
Loading