from __future__ import annotations
from enum import IntEnum, Enum
from ppc_robot_lib.utils.transformation import Transformation
from ppc_robot_lib.utils.types import LabeledEnum
class CategoryEnum(Enum):
@classmethod
def transform(cls, value):
if value is None:
return None
try:
return cls(value)
except ValueError:
item = getattr(cls, value)
if item is not None:
return item
else:
return None
@classmethod
def get_transformation(cls):
if not hasattr(cls, '_transformation'):
class CategoryEnumTransformation(Transformation):
@staticmethod
def to_internal_value(value):
return cls.transform(value)
@staticmethod
def from_internal_value(value):
if isinstance(value, str):
return value
elif isinstance(value, cls):
return value.name
elif value is None:
return None
else:
return str(value)
cls._transformation = CategoryEnumTransformation
return cls._transformation
def __gt__(self, other):
if self.__class__ is other.__class__:
return self.value > other.value
raise NotImplemented
def __ge__(self, other):
if self.__class__ is other.__class__:
return self.value >= other.value
raise NotImplemented
def __lt__(self, other):
if self.__class__ is other.__class__:
return self.value < other.value
raise NotImplemented
def __le__(self, other):
if self.__class__ is other.__class__:
return self.value <= other.value
raise NotImplemented
[docs]
class Granularity(IntEnum):
TOTAL = 0
"""Sum for the whole date-range."""
YEARLY = 1
"""Per-year granularity."""
QUARTERLY = 2
"""Per year-quarter granularity."""
MONTHLY = 3
"""Per month granularity."""
WEEKLY = 4
"""Per-week granularity."""
DAILY = 5
"""Per-day granularity."""
def combine(self, other: Granularity | None):
if other and self != other:
if (other == Granularity.WEEKLY and self > Granularity.TOTAL) or (
self == Granularity.WEEKLY and other > Granularity.TOTAL
):
return self.DAILY
elif other > self:
return other
return self
@property
def api_value(self):
return self.name.lower()
class StatusEnum(LabeledEnum, CategoryEnum):
ACTIVE = 'active'
NOACTIVE = 'noactive'
SUSPEND = 'suspend'
def get_labels(self):
return {
StatusEnum.ACTIVE: 'Active',
StatusEnum.NOACTIVE: 'Not Active',
StatusEnum.SUSPEND: 'Suspended',
}
class GroupMixedStatus(LabeledEnum, CategoryEnum):
ACTIVE = 'active'
NOACTIVE = 'noactive'
SUSPEND = 'suspend'
DELETED = 'deleted'
def get_labels(self):
return {
GroupMixedStatus.ACTIVE: 'Active',
GroupMixedStatus.NOACTIVE: 'Not Active',
GroupMixedStatus.SUSPEND: 'Suspended',
GroupMixedStatus.DELETED: 'Deleted',
}
class CampaignMixedStatus(LabeledEnum, CategoryEnum):
ACTIVE = 'active'
ACTIVE_EXHAUSTED_DAY_BUDGET = 'active-exhausted_day_budget'
ACTIVE_EXPIRED_BUDGET = 'active-expired_budget'
ACTIVE_EXPIRED_CLICKS = 'active-expired_clicks'
ACTIVE_EXPIRED_TIME = 'active-expired_time'
ACTIVE_LOW_BUDGET = 'active-low_budget'
ACTIVE_WAITING = 'active-waiting'
SUSPENDED = 'suspended'
DELETED = 'deleted'
def get_labels(self):
return {
CampaignMixedStatus.ACTIVE: 'Active',
CampaignMixedStatus.ACTIVE_EXHAUSTED_DAY_BUDGET: 'Active - Exhausted Daily Budget',
CampaignMixedStatus.ACTIVE_EXPIRED_BUDGET: 'Active - Expired Budget',
CampaignMixedStatus.ACTIVE_EXPIRED_CLICKS: 'Active - Expired Clicks',
CampaignMixedStatus.ACTIVE_EXPIRED_TIME: 'Active - Expired Time',
CampaignMixedStatus.ACTIVE_LOW_BUDGET: 'Active - Low Budget',
CampaignMixedStatus.ACTIVE_WAITING: 'Active - Waiting',
CampaignMixedStatus.SUSPENDED: 'Suspended',
CampaignMixedStatus.DELETED: 'Deleted',
}
class DeviceType(LabeledEnum, CategoryEnum):
PHONE = 'devicePhone'
DESKTOP = 'deviceDesktop'
TABLET = 'deviceTablet'
OTHER = 'deviceOther'
def get_labels(self):
return {
DeviceType.PHONE: 'Phone',
DeviceType.DESKTOP: 'Desktop',
DeviceType.TABLET: 'Tablet',
DeviceType.OTHER: 'Other',
}
class CampaignAdSelection(LabeledEnum, CategoryEnum):
COS = 'cos'
CPA = 'cpa'
RANDOM = 'random'
WEIGHTED = 'weighted'
def get_labels(self):
return {
CampaignAdSelection.COS: 'COS',
CampaignAdSelection.CPA: 'CPA',
CampaignAdSelection.RANDOM: 'Random',
CampaignAdSelection.WEIGHTED: 'Weighted',
}
class NetworkFilter(LabeledEnum, CategoryEnum):
FULLTEXT_ONLY = 'fulltext_only'
CONTEXT_ONLY = 'context_only'
CONTEXT_AND_FULLTEXT = 'context_and_fulltext'
def get_labels(self):
return {
NetworkFilter.FULLTEXT_ONLY: 'Fulltext Only',
NetworkFilter.CONTEXT_ONLY: 'Context Only',
NetworkFilter.CONTEXT_AND_FULLTEXT: 'Both Context and Fulltext',
}
class MatchType(LabeledEnum, CategoryEnum):
BROAD = 'broad'
PHRASE = 'phrase'
EXACT = 'exact'
def get_labels(self):
return {
MatchType.BROAD: 'Broad',
MatchType.PHRASE: 'Phrase',
MatchType.EXACT: 'Exact',
}
class KeywordMixedStatus(LabeledEnum, CategoryEnum):
ACTIVE = 'active'
ACTIVE_NOACTIVE = 'active-noactive'
ACTIVE_NEVER = 'active-never'
ACTIVE_DISABLED = 'active-disabled'
SUSPENDED = 'suspended'
DELETED = 'deleted'
def get_labels(self):
return {
KeywordMixedStatus.ACTIVE: 'Active',
KeywordMixedStatus.ACTIVE_NOACTIVE: 'Suspended by system - change CPC',
KeywordMixedStatus.ACTIVE_NEVER: 'Suspended by system - cannot be triggered',
KeywordMixedStatus.ACTIVE_DISABLED: 'Suspended by system - prohibited keyword',
KeywordMixedStatus.SUSPENDED: 'Suspended',
KeywordMixedStatus.DELETED: 'Deleted',
}
class EroticSensitivity(CategoryEnum):
HARMLESS = 'harmless'
EROTIC = 'erotic'
PORN = 'porn'
class AdStatusEnum(CategoryEnum):
NEW = 'new'
WAITING = 'waiting'
ALLOW = 'allow'
DENY = 'deny'
NOACTIVE = 'noactive'
DENY_EXCESS_PUNCTUATION = 'deny_excess_punctuation'
DENY_BAD_UPPERCASE_USAGE = 'deny_bad_uppercase_usage'
DENY_EXCLAMATION_MARK_IN_TITLE = 'deny_exclamation_mark_in_title'
DENY_EXCESS_WORDS_DUPLICATION = 'deny_excess_words_duplication'
DENY_DISALLOWED_LANGUAGE = 'deny_disallowed_language'
DENY_NONSENSICAL_TEXT = 'deny_nonsensical_text'
DENY_SUPERLATIVE_IN_TEXT = 'deny_superlative_in_text'
DENY_GENERAL_PHRASE = 'deny_general_phrase'
DENY_UNMATCHED_DOMAIN = 'deny_unmatched_domain'
DENY_NONEXISTENT_DOMAIN = 'deny_nonexistent_domain'
DENY_INVALID_URL = 'deny_invalid_url'
DENY_URL_UNDER_CONSTRUCTION = 'deny_url_under_construction'
DENY_UNSUITABLE_URL = 'deny_unsuitable_url'
DENY_FALSE_ADVERTISING = 'deny_false_advertising'
DENY_MENTION_OF_COMPETITION = 'deny_mention_of_competition'
DENY_NOT_CONJOINT_WITH_TARGET_PAGE = 'deny_not_conjoint_with_target_page'
DENY_NOT_CONJOINT_WITH_KEYWORDS = 'deny_not_conjoint_with_keywords'
DENY_UNVERIFIABLE_PRICES = 'deny_unverifiable_prices'
DENY_EROTIC_CONTENT = 'deny_erotic_content'
DENY_DISALLOWED_CONTENT = 'deny_disallowed_content'
DENY_TRADEMARK = 'deny_trademark'
DENY_NOT_DIACRITICAL_TEXT = 'deny_not_diacritical_text'
DENY_MISSING_SPACE = 'deny_missing_space'
DENY_AVERMENT_OF_UNIQUENESS = 'deny_averment_of_uniqueness'
DENY_DISCOUNT_WITH_REFFERED_VALUE = 'deny_discount_with_reffered_value'
DENY_UNTYPICAL_ABBREVIATION = 'deny_untypical_abbreviation'
DENY_TYPING_OR_GRAMMATICAL_ERROR = 'deny_typing_or_grammatical_error'
DENY_IMPENETRABLE_WORDS_DIVIDING = 'deny_impenetrable_words_dividing'
DENY_PROBLEM_WITH_PUNCTUATION = 'deny_problem_with_punctuation'
NOACTIVE_UNSUPPORTED_SIZE = 'noactive_unsupported_size'
class AdTypeEnum(LabeledEnum, CategoryEnum):
STA = 'sta'
ETA = 'eta'
COMBINED = 'combined'
BRANDING = 'branding'
VIDEO = 'video'
BUMPER = 'bumper'
UNKNOWN = 'unknown'
def get_labels(self):
return {
AdTypeEnum.STA: 'Standard Text Ad',
AdTypeEnum.ETA: 'Extended Text Ad',
AdTypeEnum.COMBINED: 'Combined Ad',
AdTypeEnum.BRANDING: 'Branding Ad',
AdTypeEnum.VIDEO: 'Video',
AdTypeEnum.BUMPER: 'Bumper',
AdTypeEnum.UNKNOWN: 'Unknown',
}
@classmethod
def transform(cls, value):
if value == 'text':
return cls.STA
try:
return super().transform(value)
except (KeyError, AttributeError):
return cls.UNKNOWN
class AdMixedStatus(CategoryEnum):
ACTIVE = 'active'
WAITING = 'waiting'
ACTIVE_EROTIC = 'active-erotic'
ACTIVE_PORN = 'active-porn'
DENY = 'deny'
SUSPENDED = 'suspended'
DELETED = 'deleted'
class SitelinkType(LabeledEnum, CategoryEnum):
NULL = 'null'
GROUP = 'group'
CAMPAIGN = 'campaign'
def get_labels(self):
return {
SitelinkType.NULL: 'Not Assigned',
SitelinkType.GROUP: 'Ad Group',
SitelinkType.CAMPAIGN: 'Campaign',
}
class SitelinkStatus(CategoryEnum):
NEW = 'new'
WAITING = 'waiting'
ALLOW = 'allow'
DENY = 'deny'
NOACTIVE = 'noactive'
DENY_EXCESS_PUNCTUATION = 'deny_excess_punctuation'
DENY_BAD_UPPERCASE_USAGE = 'deny_bad_uppercase_usage'
DENY_EXCLAMATION_MARK_IN_TITLE = 'deny_exclamation_mark_in_title'
DENY_EXCESS_WORDS_DUPLICATION = 'deny_excess_words_duplication'
DENY_DISALLOWED_LANGUAGE = 'deny_disallowed_language'
DENY_NONSENSICAL_TEXT = 'deny_nonsensical_text'
DENY_SUPERLATIVE_IN_TEXT = 'deny_superlative_in_text'
DENY_GENERAL_PHRASE = 'deny_general_phrase'
DENY_UNMATCHED_DOMAIN = 'deny_unmatched_domain'
DENY_NONEXISTENT_DOMAIN = 'deny_nonexistent_domain'
DENY_INVALID_URL = 'deny_invalid_url'
DENY_URL_UNDER_CONSTRUCTION = 'deny_url_under_construction'
DENY_UNSUITABLE_URL = 'deny_unsuitable_url'
DENY_FALSE_ADVERTISING = 'deny_false_advertising'
DENY_MENTION_OF_COMPETITION = 'deny_mention_of_competition'
DENY_NOT_CONJOINT_WITH_TARGET_PAGE = 'deny_not_conjoint_with_target_page'
DENY_NOT_CONJOINT_WITH_KEYWORDS = 'deny_not_conjoint_with_keywords'
DENY_UNVERIFIABLE_PRICES = 'deny_unverifiable_prices'
DENY_EROTIC_CONTENT = 'deny_erotic_content'
DENY_DISALLOWED_CONTENT = 'deny_disallowed_content'
DENY_TRADEMARK = 'deny_trademark'
DENY_NOT_DIACRITICAL_TEXT = 'deny_not_diacritical_text'
DENY_MISSING_SPACE = 'deny_missing_space'
DENY_AVERMENT_OF_UNIQUENESS = 'deny_averment_of_uniqueness'
DENY_DISCOUNT_WITH_REFFERED_VALUE = 'deny_discount_with_reffered_value'
DENY_UNTYPICAL_ABBREVIATION = 'deny_untypical_abbreviation'
DENY_TYPING_OR_GRAMMATICAL_ERROR = 'deny_typing_or_grammatical_error'
DENY_IMPENETRABLE_WORDS_DIVIDING = 'deny_impenetrable_words_dividing'
DENY_PROBLEM_WITH_PUNCTUATION = 'deny_problem_with_punctuation'
NOACTIVE_UNSUPPORTED_SIZE = 'noactive_unsupported_size'
class NegativeMatchType(LabeledEnum, CategoryEnum):
NEGATIVE_BROAD = 'negative_broad'
NEGATIVE_PHRASE = 'negative_phrase'
NEGATIVE_EXACT = 'negative_exact'
def get_labels(self):
return {
NegativeMatchType.NEGATIVE_BROAD: 'Negative Broad',
NegativeMatchType.NEGATIVE_PHRASE: 'Negative Phrase',
NegativeMatchType.NEGATIVE_EXACT: 'Negative Exact',
}