# -*- coding: utf-8 -*-
"""
smsc.responses module.
This module contains the responses objects wrapping SMSC.ru API answers.
:copyright: (c) 2017 by Alexey Shevchenko.
:license: MIT, see LICENSE for more details.
"""
from abc import ABCMeta
from collections import namedtuple
from typing import Any, Dict, Optional
from arrow import get as arrow_get
from dateutil.tz import tz
# noinspection PyUnresolvedReferences
[docs]class SMSCError(namedtuple("SMSCError", ["code", "error"])):
"""
Named tuple for error description with code.
:param int code: Code of error
:param str error: Description of error
"""
[docs]class Status:
"""
Message delivery status with identification.
:param dict obj: Dictionary from API JSON response
"""
def __init__(self, obj: Dict[str, Any]) -> None: # noqa: D102
self.__id = int(obj.get("status", 0))
self.__name = str(obj.get("status_name", ""))
for name in ["status", "status_name"]:
del obj[name]
def __str__(self) -> str:
"""Represent object as string."""
return "<%s status=%d name=%s>" % (self.__class__.__name__, self.__id, self.__name)
def __repr__(self) -> str:
"""Represent object for debug purposes."""
return str(self)
@property
def status_id(self) -> int:
"""Id of delivery status."""
return self.__id
@property
def name(self) -> str:
"""Delivery status description."""
return self.__name
[docs]class Response(metaclass=ABCMeta):
"""
Basic class for response wrappers.
:param dict obj: Dictionary from API JSON response
"""
def __init__(self, obj: Dict[str, Any]) -> None: # noqa: D102
self.__error = obj.get("error", None)
self.__code = int(obj.get("error_code", 0))
@property
def error(self) -> Optional[SMSCError]:
"""Error in response, if present."""
if not self.__error and not self.__code:
return None
# noinspection PyTypeChecker
return SMSCError(self.__code, self.__error)
[docs]class SendResponse(Response):
"""
Response for send API command.
:param dict obj: Dictionary from API JSON response
"""
def __init__(self, obj: Dict[str, Any]) -> None: # noqa: D102
super().__init__(obj)
self.__id = obj.get("id", None)
self.__cnt = int(obj.get("cnt", 0))
self.__cost = float(obj.get("cost", 0.0))
def __str__(self) -> str:
"""Represent object as string."""
return "<%s id=%s count=%d cost=%.2f>" % (
self.__class__.__name__, self.__id, self.__cnt, self.__cost)
def __repr__(self) -> str:
"""Represent object for debug purposes."""
return str(self)
@property
def message_id(self) -> str:
"""Id of sent message."""
return self.__id
@property
def count(self) -> int:
"""Count of billed message parts."""
return self.__cnt
@property
def cost(self) -> float:
"""Cost of sent message."""
return self.__cost
[docs]class CostResponse(Response):
"""
Response for get cost (send variation) API command.
:param dict obj: Dictionary from API JSON response
"""
def __init__(self, obj: Dict[str, Any]) -> None: # noqa: D102
super().__init__(obj)
self.__cnt = int(obj.get("cnt", 0))
self.__cost = float(obj.get("cost", 0.0))
def __str__(self):
"""Represent object as string."""
return "<%s count=%d cost=%.2f>" % (
self.__class__.__name__, self.__cnt, self.__cost)
def __repr__(self) -> str:
"""Represent object for debug purposes."""
return str(self)
@property
def count(self) -> int:
"""Count of billed message parts."""
return self.__cnt
@property
def cost(self) -> float:
"""Cost of message."""
return self.__cost
[docs]class StatusResponse(Response):
"""
Response for get status API command.
:param dict obj: Dictionary from API JSON response
"""
def __init__(self, obj: Dict[str, Any]) -> None: # noqa: D102
super().__init__(obj)
self.__status = Status(obj)
self.__data = {} # type: Dict[str, Any]
for name in obj.keys():
self.__data[name] = obj.get(name, None)
if self.__data["last_date"] is not None:
self.__data["last_date"] = arrow_get(self.__data["last_date"], "DD.MM.YYYY HH:mm:ss",
tzinfo=tz.gettz("Europe/Moscow")).datetime
if self.__data["send_date"] is not None:
self.__data["send_date"] = arrow_get(self.__data["send_date"], "DD.MM.YYYY HH:mm:ss",
tzinfo=tz.gettz("Europe/Moscow")).datetime
for name in ["send_timestamp", "last_timestamp"]:
del self.__data[name]
def __str__(self) -> str:
"""Represent object as string."""
return "<%s id=%d status= %s>" % (self.__class__.__name__, self.__data["id"], self.__status)
def __repr__(self) -> str:
"""Represent object for debug purposes."""
return str(self)
@property
def status(self) -> Status:
"""Message delivery status with identification."""
return self.__status
@property
def data(self) -> Dict[str, Any]:
"""Delivery status detailed data."""
return self.__data
[docs]class BalanceResponse(Response):
"""
Response for get account balance API command.
:param dict obj: Dictionary from API JSON response
"""
def __init__(self, obj: Dict[str, Any]) -> None: # noqa: D102
super().__init__(obj)
self.__balance = float(obj.get("balance", 0.0))
self.__credit = float(obj.get("credit", 0.0))
self.__currency = str(obj.get("currency", ""))
def __str__(self) -> str:
"""Represent object as string."""
return "<%s balance=%.2f credit=%.2f currency=%s>" % (
self.__class__.__name__, self.__balance, self.__credit, self.__currency)
def __repr__(self) -> str:
"""Represent object for debug purposes."""
return str(self)
@property
def balance(self) -> float:
"""Actual account balance."""
return self.__balance
@property
def credit(self) -> float:
"""Available credit of account (if applied)."""
return self.__credit
@property
def currency(self) -> str:
"""Currency for current account."""
return self.__currency