Skip to content

Commit

Permalink
SE-1356 Modify features endpoint to dynamically set requested feature…
Browse files Browse the repository at this point in the history
…s. (#92)

* SE-1356 Modify features endpoint to dynamically set requested features.

* SE-1356 Fix TypeError: 'type' object is not subscriptable error for Python < 3.9

* SE-1356 Simplify and improve type hints.

* SE-1356 Black formatting.

* SE-1356 Add notes on how to serialize search results and usage of .model_dump(exclude_none=True)

* SE-1356 README update
  • Loading branch information
medhatphq authored Jul 17, 2024
1 parent fd83d2d commit 5f57567
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 146 deletions.
45 changes: 43 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Please refer to our [Places endpoint documentation](https://docs.predicthq.com/r

### Features endpoint

The following example obtain features of events which are active between 2017-12-31 and 2018-01-02, with place_id 4671654.
The following example obtain features of events which are active between 2017-12-31 and 2018-01-02, with place_id 4671654.

Requested features:
* rank_levels for public_holidays
Expand Down Expand Up @@ -206,7 +206,48 @@ phq = Client(access_token="abc123")


suggested_radius = phq.radius.search(location__origin="45.5051,-122.6750")
print(suggested_radius.radius, suggested_radius.radius_unit, suggested_radius.location.to_dict())
print(suggested_radius.radius, suggested_radius.radius_unit, suggested_radius.location.model_dump(exclude_none=True))
```

### Serializing search results into a dictionary

All search results can be serialized into a dictionary using the `.model_dump()` method call.

To keep `None` values use `.model_dump()`

To remove `None` values use `.model_dump(exclude_none=True)`

Examples:

```Python
from predicthq import Client

phq = Client(access_token="abc123")


for event in phq.events.search(q="Katy Perry", rank_level=[4, 5], category="concerts"):
# Serialize event data into a dictionary and remove None values
print(event.model_dump(exclude_none=True))
```

```Python
from predicthq import Client

phq = Client(access_token="abc123")


for feature in phq.features.obtain_features(
active__gte="2017-12-31",
active__lte="2018-01-02",
location__place_id=["4671654"],
phq_rank_public_holidays=True,
phq_attendance_sports__stats=["count", "median"],
phq_attendance_sports__phq_rank={
"gt": 50
}
):
# Serialize feature data into a dictionary and remove None values
print(feature.model_dump(exclude_none=True))
```

### Config parameters
Expand Down
22 changes: 12 additions & 10 deletions predicthq/endpoints/v1/features/endpoint.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import inspect

from predicthq.endpoints.base import UserBaseEndpoint
from predicthq.endpoints.decorators import accepts, returns

from .schemas import FeatureResultSet


class FeaturesEndpoint(UserBaseEndpoint):

BASE_FEATURE_CRITERIA = {"stats": [["sum", "count"]], "phq_rank": [None]}
FIELDS_TO_MUTATE = frozenset([
"phq_attendance_",
"phq_viewership_sports",
"phq_impact_severe_weather_",
"phq_spend_"
])
FIELDS_TO_MUTATE = frozenset(
[
"phq_attendance_",
"phq_viewership_",
"phq_impact_",
"phq_spend_",
]
)

@classmethod
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
139 changes: 6 additions & 133 deletions predicthq/endpoints/v1/features/schemas.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from datetime import date
from typing import List
from typing import Dict, List, Optional, Union

from typing import Optional

from pydantic import BaseModel
from pydantic import BaseModel, RootModel

from predicthq.endpoints.schemas import ResultSet

Expand All @@ -26,136 +24,11 @@ class FeatureStat(BaseModel):
stats: FeatureStats


class Feature(BaseModel):
class Options:
serialize_when_none = False
class Feature(RootModel):
root: Dict[str, Union[date, FeatureStat, FeatureRankLevel]]

date: date
# Attendance based features
phq_attendance_academic_graduation: Optional[FeatureStat] = None
phq_attendance_academic_social: Optional[FeatureStat] = None
phq_attendance_community: Optional[FeatureStat] = None
phq_attendance_concerts: Optional[FeatureStat] = None
phq_attendance_conferences: Optional[FeatureStat] = None
phq_attendance_expos: Optional[FeatureStat] = None
phq_attendance_festivals: Optional[FeatureStat] = None
phq_attendance_performing_arts: Optional[FeatureStat] = None
phq_attendance_school_holidays: Optional[FeatureStat] = None
phq_attendance_sports: Optional[FeatureStat] = None
# Attendance based feature for accommodation vertical
phq_attendance_community_accommodation: Optional[FeatureStat] = None
phq_attendance_concerts_accommodation: Optional[FeatureStat] = None
phq_attendance_conferences_accommodation: Optional[FeatureStat] = None
phq_attendance_expos_accommodation: Optional[FeatureStat] = None
phq_attendance_festivals_accommodation: Optional[FeatureStat] = None
phq_attendance_performing_arts_accommodation: Optional[FeatureStat] = None
phq_attendance_sports_accommodation: Optional[FeatureStat] = None
# Attendance based feature for hospitality vertical
phq_attendance_community_hospitality: Optional[FeatureStat] = None
phq_attendance_concerts_hospitality: Optional[FeatureStat] = None
phq_attendance_conferences_hospitality: Optional[FeatureStat] = None
phq_attendance_expos_hospitality: Optional[FeatureStat] = None
phq_attendance_festivals_hospitality: Optional[FeatureStat] = None
phq_attendance_performing_arts_hospitality: Optional[FeatureStat] = None
phq_attendance_sports_hospitality: Optional[FeatureStat] = None
# Rank based features
phq_rank_daylight_savings: Optional[FeatureRankLevel] = None
phq_rank_health_warnings: Optional[FeatureRankLevel] = None
phq_rank_observances: Optional[FeatureRankLevel] = None
phq_rank_public_holidays: Optional[FeatureRankLevel] = None
phq_rank_school_holidays: Optional[FeatureRankLevel] = None
phq_rank_politics: Optional[FeatureRankLevel] = None
phq_rank_academic_session: Optional[FeatureRankLevel] = None
phq_rank_academic_exam: Optional[FeatureRankLevel] = None
phq_rank_academic_holiday: Optional[FeatureRankLevel] = None
# Impact based feature criteria
phq_impact_severe_weather_air_quality_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_blizzard_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_cold_wave_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_cold_wave_snow_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_cold_wave_storm_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_dust_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_dust_storm_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_flood_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_heat_wave_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_hurricane_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_thunderstorm_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_tornado_retail: Optional[FeatureStat] = None
phq_impact_severe_weather_tropical_storm_retail: Optional[FeatureStat] = None
# Viewership based features
phq_viewership_sports: Optional[FeatureStat] = None
phq_viewership_sports_american_football: Optional[FeatureStat] = None
phq_viewership_sports_american_football_ncaa_men: Optional[FeatureStat] = None
phq_viewership_sports_american_football_nfl: Optional[FeatureStat] = None
phq_viewership_sports_auto_racing: Optional[FeatureStat] = None
phq_viewership_sports_auto_racing_indy_car: Optional[FeatureStat] = None
phq_viewership_sports_auto_racing_nascar: Optional[FeatureStat] = None
phq_viewership_sports_baseball: Optional[FeatureStat] = None
phq_viewership_sports_baseball_mlb: Optional[FeatureStat] = None
phq_viewership_sports_baseball_ncaa_men: Optional[FeatureStat] = None
phq_viewership_sports_basketball: Optional[FeatureStat] = None
phq_viewership_sports_basketball_ncaa_women: Optional[FeatureStat] = None
phq_viewership_sports_basketball_ncaa_men: Optional[FeatureStat] = None
phq_viewership_sports_basketball_nba: Optional[FeatureStat] = None
phq_viewership_sports_boxing: Optional[FeatureStat] = None
phq_viewership_sports_golf: Optional[FeatureStat] = None
phq_viewership_sports_golf_masters: Optional[FeatureStat] = None
phq_viewership_sports_golf_pga_championship: Optional[FeatureStat] = None
phq_viewership_sports_golf_pga_tour: Optional[FeatureStat] = None
phq_viewership_sports_golf_us_open: Optional[FeatureStat] = None
phq_viewership_sports_horse_racing: Optional[FeatureStat] = None
phq_viewership_sports_horse_racing_belmont_stakes: Optional[FeatureStat] = None
phq_viewership_sports_horse_racing_kentucky_derby: Optional[FeatureStat] = None
phq_viewership_sports_horse_racing_preakness_stakes: Optional[FeatureStat] = None
phq_viewership_sports_ice_hockey: Optional[FeatureStat] = None
phq_viewership_sports_ice_hockey_nhl: Optional[FeatureStat] = None
phq_viewership_sports_mma: Optional[FeatureStat] = None
phq_viewership_sports_mma_ufc: Optional[FeatureStat] = None
phq_viewership_sports_soccer: Optional[FeatureStat] = None
phq_viewership_sports_soccer_concacaf_champions_league: Optional[FeatureStat] = None
phq_viewership_sports_soccer_concacaf_gold_cup: Optional[FeatureStat] = None
phq_viewership_sports_soccer_copa_america_men: Optional[FeatureStat] = None
phq_viewership_sports_soccer_fifa_world_cup_women: Optional[FeatureStat] = None
phq_viewership_sports_soccer_fifa_world_cup_men: Optional[FeatureStat] = None
phq_viewership_sports_soccer_mls: Optional[FeatureStat] = None
phq_viewership_sports_soccer_uefa_champions_league_men: Optional[FeatureStat] = None
phq_viewership_sports_softball: Optional[FeatureStat] = None
phq_viewership_sports_softball_ncaa_women: Optional[FeatureStat] = None
phq_viewership_sports_tennis: Optional[FeatureStat] = None
phq_viewership_sports_tennis_us_open: Optional[FeatureStat] = None
phq_viewership_sports_tennis_wimbledon: Optional[FeatureStat] = None
# PHQ spend based feature
phq_spend_conferences: Optional[FeatureStat] = None
phq_spend_expos: Optional[FeatureStat] = None
phq_spend_sports: Optional[FeatureStat] = None
phq_spend_community: Optional[FeatureStat] = None
phq_spend_concerts: Optional[FeatureStat] = None
phq_spend_festivals: Optional[FeatureStat] = None
phq_spend_performing_arts: Optional[FeatureStat] = None
# PHQ spend accommodation based feature
phq_spend_conferences_accommodation: Optional[FeatureStat] = None
phq_spend_expos_accommodation: Optional[FeatureStat] = None
phq_spend_sports_accommodation: Optional[FeatureStat] = None
phq_spend_community_accommodation: Optional[FeatureStat] = None
phq_spend_concerts_accommodation: Optional[FeatureStat] = None
phq_spend_festivals_accommodation: Optional[FeatureStat] = None
phq_spend_performing_arts_accommodation: Optional[FeatureStat] = None
# PHQ spend hospitality based feature
phq_spend_conferences_hospitality: Optional[FeatureStat] = None
phq_spend_expos_hospitality: Optional[FeatureStat] = None
phq_spend_sports_hospitality: Optional[FeatureStat] = None
phq_spend_community_hospitality: Optional[FeatureStat] = None
phq_spend_concerts_hospitality: Optional[FeatureStat] = None
phq_spend_festivals_hospitality: Optional[FeatureStat] = None
phq_spend_performing_arts_hospitality: Optional[FeatureStat] = None
# PHQ spend transportation based feature
phq_spend_conferences_transportation: Optional[FeatureStat] = None
phq_spend_expos_transportation: Optional[FeatureStat] = None
phq_spend_sports_transportation: Optional[FeatureStat] = None
phq_spend_community_transportation: Optional[FeatureStat] = None
phq_spend_concerts_transportation: Optional[FeatureStat] = None
phq_spend_festivals_transportation: Optional[FeatureStat] = None
phq_spend_performing_arts_transportation: Optional[FeatureStat] = None
def __getattr__(self, name: str) -> Union[date, FeatureStat, FeatureRankLevel]:
return self.root[name]


class FeatureResultSet(ResultSet):
Expand Down
2 changes: 1 addition & 1 deletion predicthq/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "3.4.0"
__version__ = "3.5.0"

0 comments on commit 5f57567

Please sign in to comment.