From 4aaaabb306e869e814d36737d1123f77045ba02c Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Sun, 19 Jun 2016 00:15:04 +0300 Subject: factor things out of vk.user --- vk/last_seen.py | 97 +++++++++++++++++++++++ vk/platform.py | 50 ++++++++++++ vk/tracking/db/record.py | 3 +- vk/tracking/status_tracker.py | 2 +- vk/user.py | 174 ++++++------------------------------------ 5 files changed, 172 insertions(+), 154 deletions(-) create mode 100644 vk/last_seen.py create mode 100644 vk/platform.py diff --git a/vk/last_seen.py b/vk/last_seen.py new file mode 100644 index 0000000..9f0c650 --- /dev/null +++ b/vk/last_seen.py @@ -0,0 +1,97 @@ +# Copyright 2016 Egor Tensin +# This file is licensed under the terms of the MIT License. +# See LICENSE.txt for details. + +from collections import OrderedDict +from collections.abc import MutableMapping +from datetime import datetime, timezone +from enum import Enum +from numbers import Integral, Real + +from .platform import Platform + +def _parse_time(x): + if isinstance(x, datetime): + if x.tzinfo is None or x.tzinfo.utcoffset(x) is None: + x = x.replace(tzinfo=timezone.utc) + return x + elif isinstance(x, Real) or isinstance(x, Integral): + return datetime.fromtimestamp(x, tz=timezone.utc) + else: + raise TypeError() + +def _parse_platform(x): + if x in Platform: + return x + if isinstance(x, str): + return Platform.from_string(x) + else: + return Platform(x) + +class LastSeenField(Enum): + TIME = 'time' + PLATFORM = 'platform' + + def __str__(self): + return self.value + +class LastSeen(MutableMapping): + @staticmethod + def from_api_response(source): + instance = LastSeen() + for field in LastSeenField: + if str(field) in source: + instance[field] = source[str(field)] + return instance + + def __init__(self, fields=None): + if fields is None: + fields = OrderedDict() + self._fields = fields + + def __getitem__(self, field): + return self._fields[field] + + def __setitem__(self, field, value): + self._fields[field] = self.parse(field, value) + + def __delitem__(self, field): + del self._fields[field] + + def __iter__(self): + return iter(self._fields) + + def __len__(self): + return len(self._fields) + + @staticmethod + def parse(field, value): + if field in LastSeen._FIELD_PARSERS: + return LastSeen._FIELD_PARSERS[field](value) + else: + return LastSeen._DEFAULT_FIELD_PARSER(value) + + _FIELD_PARSERS = { + LastSeenField.TIME: _parse_time, + LastSeenField.PLATFORM: _parse_platform, + } + + _DEFAULT_FIELD_PARSER = str + + def has_time(self): + return LastSeenField.TIME in self + + def get_time(self): + return self[LastSeenField.TIME] + + def set_time(self, t): + self[LastSeenField.TIME] = t + + def has_platform(self): + return LastSeenField.PLATFORM in self + + def get_platform(self): + return self[LastSeenField.PLATFORM] + + def set_platform(self, platform): + self[LastSeenField.PLATFORM] = platform diff --git a/vk/platform.py b/vk/platform.py new file mode 100644 index 0000000..4a9d8b6 --- /dev/null +++ b/vk/platform.py @@ -0,0 +1,50 @@ +# Copyright 2016 Egor Tensin +# This file is licensed under the terms of the MIT License. +# See LICENSE.txt for details. + +from enum import Enum +import re + +class Platform(Enum): + MOBILE = 1 + IPHONE = 2 + IPAD = 3 + ANDROID = 4 + WINDOWS_PHONE = 5 + WINDOWS8 = 6 + WEB = 7 + + @staticmethod + def from_string(s): + return Platform(int(s)) + + def __str__(self): + return str(self.value) + + @staticmethod + def _uppercase_first_letter(s): + m = re.search(r'\w', s) + if m is None: + return s + return s[:m.start()] + m.group().upper() + s[m.end():] + + def get_description_for_header(self): + return self._uppercase_first_letter(_PLATFORM_DESCRIPTIONS[self]) + + def get_description_for_sentence(self): + s = _PLATFORM_DESCRIPTIONS[self] + s = s.replace('unrecognized', 'an unrecognized') + return 'the ' + s + + def get_description_for_sentence_beginning(self): + return self._uppercase_first_letter(self.get_description_for_sentence()) + +_PLATFORM_DESCRIPTIONS = { + Platform.MOBILE: '"mobile" web version (or unrecognized mobile app)', + Platform.IPHONE: 'official iPhone app', + Platform.IPAD: 'official iPad app', + Platform.ANDROID: 'official Android app', + Platform.WINDOWS_PHONE: 'official Windows Phone app', + Platform.WINDOWS8: 'official Windows 8 app', + Platform.WEB: 'web version (or unrecognized app)' +} diff --git a/vk/tracking/db/record.py b/vk/tracking/db/record.py index 93be97c..71dfde0 100644 --- a/vk/tracking/db/record.py +++ b/vk/tracking/db/record.py @@ -7,7 +7,8 @@ from collections.abc import MutableMapping from datetime import datetime from .timestamp import Timestamp -from vk.user import LastSeen, LastSeenField, User, UserField +from vk.last_seen import LastSeen, LastSeenField +from vk.user import User, UserField class Record(MutableMapping): FIELDS = ( diff --git a/vk/tracking/status_tracker.py b/vk/tracking/status_tracker.py index 3d1f032..8faea8e 100644 --- a/vk/tracking/status_tracker.py +++ b/vk/tracking/status_tracker.py @@ -2,7 +2,7 @@ # This file is licensed under the terms of the MIT License. # See LICENSE.txt for details. -from collections import Callable +from collections.abc import Callable import time import vk.error diff --git a/vk/user.py b/vk/user.py index 2ec82cc..736c4ba 100644 --- a/vk/user.py +++ b/vk/user.py @@ -4,10 +4,28 @@ from collections import OrderedDict from collections.abc import Hashable, Mapping, MutableMapping -from datetime import datetime, timezone from enum import Enum -from numbers import Real, Integral -import re + +from .last_seen import LastSeen + +def _parse_last_seen(x): + if isinstance(x, LastSeen): + return x + elif isinstance(x, Mapping): + return LastSeen.from_api_response(x) + else: + raise TypeError() + +def _parse_online_flag(x): + if isinstance(x, str): + if str(True) == x: + return True + elif str(False) == x: + return False + else: + raise ValueError() + else: + return bool(x) class UserField(Enum): UID = 'uid' @@ -20,135 +38,6 @@ class UserField(Enum): def __str__(self): return self.value -class LastSeenField(Enum): - TIME = 'time' - PLATFORM = 'platform' - - def __str__(self): - return self.value - -class Platform(Enum): - MOBILE = 1 - IPHONE = 2 - IPAD = 3 - ANDROID = 4 - WINDOWS_PHONE = 5 - WINDOWS8 = 6 - WEB = 7 - - def from_string(s): - return Platform(int(s)) - - def __str__(self): - return str(self.value) - - @staticmethod - def _uppercase_first_letter(s): - m = re.search(r'\w', s) - if m is None: - return s - return s[:m.start()] + m.group().upper() + s[m.end():] - - def get_description_for_header(self): - return self._uppercase_first_letter(_PLATFORM_DESCRIPTIONS[self]) - - def get_description_for_sentence(self): - s = _PLATFORM_DESCRIPTIONS[self] - s = s.replace('unrecognized', 'an unrecognized') - return 'the ' + s - - def get_description_for_sentence_beginning(self): - return self._uppercase_first_letter(self.get_description_for_sentence()) - -_PLATFORM_DESCRIPTIONS = { - Platform.MOBILE: '"mobile" web version (or unrecognized mobile app)', - Platform.IPHONE: 'official iPhone app', - Platform.IPAD: 'official iPad app', - Platform.ANDROID: 'official Android app', - Platform.WINDOWS_PHONE: 'official Windows Phone app', - Platform.WINDOWS8: 'official Windows 8 app', - Platform.WEB: 'web version (or unrecognized app)' -} - -class LastSeen(MutableMapping): - @staticmethod - def from_api_response(source): - instance = LastSeen() - for field in LastSeenField: - if str(field) in source: - instance[field] = source[str(field)] - return instance - - def __init__(self, fields=None): - if fields is None: - fields = OrderedDict() - self._fields = fields - - def __getitem__(self, field): - return self._fields[field] - - def __setitem__(self, field, value): - self._fields[field] = self.parse(field, value) - - def __delitem__(self, field): - del self._fields[field] - - def __iter__(self): - return iter(self._fields) - - def __len__(self): - return len(self._fields) - - @staticmethod - def parse(field, value): - if field in LastSeen._FIELD_PARSERS: - return LastSeen._FIELD_PARSERS[field](value) - else: - return LastSeen._DEFAULT_FIELD_PARSER(value) - - def _parse_time(x): - if isinstance(x, datetime): - if x.tzinfo is None or x.tzinfo.utcoffset(x) is None: - x = x.replace(tzinfo=timezone.utc) - return x - elif isinstance(x, Real) or isinstance(x, Integral): - return datetime.fromtimestamp(x, tz=timezone.utc) - else: - raise TypeError() - - def _parse_platform(x): - if x in Platform: - return x - if isinstance(x, str): - return Platform.from_string(x) - else: - return Platform(x) - - _FIELD_PARSERS = { - LastSeenField.TIME: _parse_time, - LastSeenField.PLATFORM: _parse_platform, - } - - _DEFAULT_FIELD_PARSER = str - - def has_time(self): - return LastSeenField.TIME in self - - def get_time(self): - return self[LastSeenField.TIME] - - def set_time(self, t): - self[LastSeenField.TIME] = t - - def has_platform(self): - return LastSeenField.PLATFORM in self - - def get_platform(self): - return self[LastSeenField.PLATFORM] - - def set_platform(self, platform): - self[LastSeenField.PLATFORM] = platform - class User(Hashable, MutableMapping): @staticmethod def from_api_response(source): @@ -192,28 +81,9 @@ class User(Hashable, MutableMapping): else: return User._DEFAULT_FIELD_PARSER(value) - def _parse_last_seen(x): - if isinstance(x, LastSeen): - return x - elif isinstance(x, Mapping): - return LastSeen.from_api_response(x) - else: - raise TypeError() - - def _parse_bool(x): - if isinstance(x, str): - if str(True) == x: - return True - elif str(False) == x: - return False - else: - raise ValueError() - else: - return bool(x) - _FIELD_PARSERS = { UserField.UID: int, - UserField.ONLINE: _parse_bool, + UserField.ONLINE: _parse_online_flag, UserField.LAST_SEEN: _parse_last_seen, } -- cgit v1.2.3