diff options
Diffstat (limited to '')
-rw-r--r-- | .pylintrc | 55 | ||||
-rw-r--r-- | README.md | 24 | ||||
-rw-r--r-- | bin/mutual_friends.py | 6 | ||||
-rw-r--r-- | bin/online_sessions.py | 48 | ||||
-rw-r--r-- | bin/track_status.py | 18 | ||||
-rw-r--r-- | vk/last_seen.py | 30 | ||||
-rw-r--r-- | vk/platform.py | 20 | ||||
-rw-r--r-- | vk/tracking/db/record.py | 6 | ||||
-rw-r--r-- | vk/tracking/db/timestamp.py | 30 | ||||
-rw-r--r-- | vk/tracking/online_sessions.py | 24 | ||||
-rw-r--r-- | vk/tracking/status_tracker.py | 34 | ||||
-rw-r--r-- | vk/user.py | 32 |
12 files changed, 178 insertions, 149 deletions
@@ -1,31 +1,36 @@ [MESSAGES CONTROL] -disable=missing-docstring,too-many-public-methods,too-few-public-methods,multiple-imports,duplicate-code +#disable=old-ne-operator,filter-builtin-not-iterating,nonzero-method,long-builtin,unpacking-in-except,backtick,suppressed-message,setslice-method,round-builtin,coerce-builtin,input-builtin,raising-string,raw_input-builtin,apply-builtin,delslice-method,useless-suppression,hex-method,zip-builtin-not-iterating,range-builtin-not-iterating,intern-builtin,old-octal-literal,xrange-builtin,no-absolute-import,cmp-builtin,reduce-builtin,next-method-called,getslice-method,oct-method,reload-builtin,dict-view-method,file-builtin,long-suffix,parameter-unpacking,dict-iter-method,cmp-method,old-division,using-cmp-argument,buffer-builtin,old-raise-syntax,indexing-exception,unicode-builtin,unichr-builtin,coerce-method,basestring-builtin,map-builtin-not-iterating,metaclass-assignment,print-statement,import-star-module-level,standarderror-builtin,execfile-builtin +disable=duplicate-code,missing-docstring,multiple-imports,too-many-public-methods,too-few-public-methods [BASIC] +#bad-functions=map,filter bad-functions= -good-names=i,j,k -bad-names= -name-group= -include-naming-hint=no -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ -method-rgx=[a-z_][a-z0-9_]{2,30}$ -method-name-hint=[a-z_][a-z0-9_]{2,30}$ -class-rgx=[A-Z_][a-zA-Z0-9]+$ -class-name-hint=[A-Z_][a-zA-Z0-9]+$ -attr-rgx=[a-z_][a-z0-9_]{0,30}$ -attr-name-hint=[a-z_][a-z0-9_]{0,30}$ -function-rgx=[a-z_][a-z0-9_]{2,30}$ -function-name-hint=[a-z_][a-z0-9_]{2,30}$ -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{1,30}|(__.*__))$ -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{1,30}|(__.*__))$ -variable-rgx=[a-z_][a-z0-9_]{0,30}$ -variable-name-hint=[a-z_][a-z0-9_]{0,30}$ -argument-rgx=[a-z_][a-z0-9_]{0,30}$ -argument-name-hint=[a-z_][a-z0-9_]{0,30}$ -no-docstring-rgx=^_ -docstring-min-length=-1 +#good-names=i,j,k,ex,Run,_ +good-names=_,e,fd,i,n +#bad-names=foo,bar,baz,toto,tutu,tata +#name-group= +#include-naming-hint=no +#class-rgx=[A-Z_][a-zA-Z0-9]+$ +#class-name-hint=[A-Z_][a-zA-Z0-9]+$ +#module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +#module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +#inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ +#inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ +#variable-rgx=[a-z_][a-z0-9_]{2,30}$ +#variable-name-hint=[a-z_][a-z0-9_]{2,30}$ +#const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ +#const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ +#function-rgx=[a-z_][a-z0-9_]{2,30}$ +#function-name-hint=[a-z_][a-z0-9_]{2,30}$ +#attr-rgx=[a-z_][a-z0-9_]{2,30}$ +#attr-name-hint=[a-z_][a-z0-9_]{2,30}$ +#argument-rgx=[a-z_][a-z0-9_]{2,30}$ +#argument-name-hint=[a-z_][a-z0-9_]{2,30}$ +#method-rgx=[a-z_][a-z0-9_]{2,30}$ +#method-name-hint=[a-z_][a-z0-9_]{2,30}$ +#class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ +#class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ +#no-docstring-rgx=^_ +#docstring-min-length=-1 @@ -39,6 +39,30 @@ online. [track_status.py]: docs/track_status.md [online_sessions.py]: docs/online_sessions.md +Linting +------- + +Requires [PyLint]. + + > cd + D:\workspace\personal\vk-scripts + + > pylint vk + ... + + > set PYTHONPATH=%CD% + + > pylint bin\mutual_friends.py + ... + + > pylint bin\online_sessions.py + ... + + > pylint bin\track_status.py + ... + +[PyLint]: https://www.pylint.org/ + License ------- diff --git a/bin/mutual_friends.py b/bin/mutual_friends.py index 8e6e584..29f92d9 100644 --- a/bin/mutual_friends.py +++ b/bin/mutual_friends.py @@ -70,11 +70,11 @@ class OutputFormat(Enum): else: raise NotImplementedError('unsupported output format: ' + str(self)) -def _parse_output_format(s): +def _parse_output_format(src): try: - return OutputFormat(s) + return OutputFormat(src) except ValueError: - raise argparse.ArgumentTypeError('invalid output format: ' + s) + raise argparse.ArgumentTypeError('invalid output format: ' + src) def _parse_args(args=sys.argv): parser = argparse.ArgumentParser( diff --git a/bin/online_sessions.py b/bin/online_sessions.py index dc1a2ee..a42e0dd 100644 --- a/bin/online_sessions.py +++ b/bin/online_sessions.py @@ -145,17 +145,17 @@ class OutputWriterJSON: raise NotImplementedError('unsupported grouping: ' + str(group_by)) return OutputWriterJSON._CONVERT_KEY[group_by](key) - def _write(self, x): - self._fd.write(json.dumps(x, indent=3, ensure_ascii=False)) + def _write(self, entries): + self._fd.write(json.dumps(entries, indent=3, ensure_ascii=False)) self._fd.write('\n') def process_database(self, group_by, db_reader, time_from=None, time_to=None): - arr = [] + entries = [] for key, duration in group_by.group(db_reader, time_from, time_to).items(): - obj = self._key_to_object(group_by, key) - obj[self._DURATION_FIELD] = str(duration) - arr.append(obj) - self._write(arr) + entry = self._key_to_object(group_by, key) + entry[self._DURATION_FIELD] = str(duration) + entries.append(entry) + self._write(entries) class BarChartBuilder: _BAR_HEIGHT = 1. @@ -187,9 +187,9 @@ class BarChartBuilder: def get_value_labels(self): return self._get_value_axis().get_ticklabels() - def set_value_label_formatter(self, fn): + def set_value_label_formatter(self, handler): from matplotlib.ticker import FuncFormatter - self._get_value_axis().set_major_formatter(FuncFormatter(fn)) + self._get_value_axis().set_major_formatter(FuncFormatter(handler)) def set_integer_values_only(self): from matplotlib.ticker import MaxNLocator @@ -289,8 +289,8 @@ class OutputWriterPlot: return str(timedelta(seconds=seconds)) @staticmethod - def _duration_to_seconds(td): - return td.total_seconds() + def _duration_to_seconds(duration): + return duration.total_seconds() @staticmethod def _extract_labels(group_by, durations): @@ -350,34 +350,34 @@ class OutputFormat(Enum): def __str__(self): return self.value -def _parse_group_by(s): +def _parse_group_by(src): try: - return GroupBy(s) + return GroupBy(src) except ValueError: - raise argparse.ArgumentTypeError('invalid "group by" value: ' + s) + raise argparse.ArgumentTypeError('invalid "group by" value: ' + src) -def _parse_database_format(s): +def _parse_database_format(src): try: - return DatabaseFormat(s) + return DatabaseFormat(src) except ValueError: - raise argparse.ArgumentTypeError('invalid database format: ' + s) + raise argparse.ArgumentTypeError('invalid database format: ' + src) -def _parse_output_format(s): +def _parse_output_format(src): try: - return OutputFormat(s) + return OutputFormat(src) except ValueError: - raise argparse.ArgumentTypeError('invalid output format: ' + s) + raise argparse.ArgumentTypeError('invalid output format: ' + src) _DATE_RANGE_LIMIT_FORMAT = '%Y-%m-%dT%H:%M:%SZ' -def _parse_date_range_limit(s): +def _parse_date_range_limit(src): try: - dt = datetime.strptime(s, _DATE_RANGE_LIMIT_FORMAT) - return dt.replace(tzinfo=timezone.utc) + timestamp = datetime.strptime(src, _DATE_RANGE_LIMIT_FORMAT) + return timestamp.replace(tzinfo=timezone.utc) except ValueError: msg = 'invalid date range limit (must be in the \'{}\' format): {}' raise argparse.ArgumentTypeError( - msg.format(_DATE_RANGE_LIMIT_FORMAT, s)) + msg.format(_DATE_RANGE_LIMIT_FORMAT, src)) def _parse_args(args=sys.argv): parser = argparse.ArgumentParser( diff --git a/bin/track_status.py b/bin/track_status.py index 84495f9..e59b0e1 100644 --- a/bin/track_status.py +++ b/bin/track_status.py @@ -12,20 +12,20 @@ from vk.tracking.db import Format as DatabaseFormat DEFAULT_TIMEOUT = StatusTracker.DEFAULT_TIMEOUT DEFAULT_DB_FORMAT = DatabaseFormat.CSV -def _parse_positive_integer(s): +def _parse_positive_integer(src): try: - x = int(s) + n = int(src) except ValueError: - raise argparse.ArgumentTypeError('must be a positive integer: ' + s) - if x < 1: - raise argparse.ArgumentTypeError('must be a positive integer: ' + s) - return x + raise argparse.ArgumentTypeError('must be a positive integer: ' + src) + if n < 1: + raise argparse.ArgumentTypeError('must be a positive integer: ' + src) + return n -def _parse_database_format(s): +def _parse_database_format(src): try: - return DatabaseFormat(s) + return DatabaseFormat(src) except ValueError: - raise argparse.ArgumentTypeError('invalid database format: ' + s) + raise argparse.ArgumentTypeError('invalid database format: ' + src) def _parse_args(args=sys.argv): parser = argparse.ArgumentParser( diff --git a/vk/last_seen.py b/vk/last_seen.py index ac62d65..1753e12 100644 --- a/vk/last_seen.py +++ b/vk/last_seen.py @@ -11,23 +11,23 @@ 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) +def _parse_time(src): + if isinstance(src, datetime): + if src.tzinfo is None or src.tzinfo.utcoffset(src) is None: + src = src.replace(tzinfo=timezone.utc) + return src + elif isinstance(src, Real) or isinstance(src, Integral): + return datetime.fromtimestamp(src, 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) +def _parse_platform(src): + if src in Platform: + return src + if isinstance(src, str): + return Platform.from_string(src) else: - return Platform(x) + return Platform(src) class LastSeenField(Enum): TIME = 'time' @@ -85,8 +85,8 @@ class LastSeen(MutableMapping): def get_time(self): return self[LastSeenField.TIME] - def set_time(self, t): - self[LastSeenField.TIME] = t + def set_time(self, timestamp): + self[LastSeenField.TIME] = timestamp def has_platform(self): return LastSeenField.PLATFORM in self diff --git a/vk/platform.py b/vk/platform.py index fa1e665..26f20dc 100644 --- a/vk/platform.py +++ b/vk/platform.py @@ -16,26 +16,26 @@ class Platform(Enum): WEB = 7 @staticmethod - def from_string(s): - return Platform(int(s)) + def from_string(src): + return Platform(int(src)) 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 _uppercase_first_letter(text): + match = re.search(r'\w', text) + if match is None: + return text + return text[:match.start()] + match.group().upper() + text[match.end():] def get_descr_header(self): return self._uppercase_first_letter(_PLATFORM_DESCRIPTIONS[self]) def get_descr_text(self): - s = _PLATFORM_DESCRIPTIONS[self] - s = s.replace('unrecognized', 'an unrecognized') - return 'the ' + s + descr = _PLATFORM_DESCRIPTIONS[self] + descr = descr.replace('unrecognized', 'an unrecognized') + return 'the ' + descr def get_descr_text_capitalized(self): return self._uppercase_first_letter(self.get_descr_text()) diff --git a/vk/tracking/db/record.py b/vk/tracking/db/record.py index c03c3ca..6c000ab 100644 --- a/vk/tracking/db/record.py +++ b/vk/tracking/db/record.py @@ -38,9 +38,9 @@ class Record(MutableMapping): def __setitem__(self, field, value): if field is LastSeenField.TIME: if isinstance(value, str): - value = Timestamp.from_string(value).dt + value = Timestamp.from_string(value).impl elif isinstance(value, Timestamp): - value = value.dt + value = value.impl elif isinstance(value, datetime): pass else: @@ -78,7 +78,7 @@ class Record(MutableMapping): def _update_last_seen_field(self, last_seen, field): if field is LastSeenField.TIME: - last_seen[field] = self[field].dt + last_seen[field] = self[field].impl else: last_seen[field] = self[field] diff --git a/vk/tracking/db/timestamp.py b/vk/tracking/db/timestamp.py index b2219ca..0881fb3 100644 --- a/vk/tracking/db/timestamp.py +++ b/vk/tracking/db/timestamp.py @@ -11,25 +11,25 @@ class Timestamp: return datetime.utcnow() @staticmethod - def _is_timezone_aware(dt): - return dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None + def _is_timezone_aware(impl): + return impl.tzinfo is not None and impl.tzinfo.utcoffset(impl) is not None @staticmethod - def _lose_timezone(dt): - if Timestamp._is_timezone_aware(dt): - return dt.astimezone(timezone.utc).replace(tzinfo=None) - return dt + def _lose_timezone(impl): + if Timestamp._is_timezone_aware(impl): + return impl.astimezone(timezone.utc).replace(tzinfo=None) + return impl - def __init__(self, dt=None): - if dt is None: - dt = self._new() - dt = dt.replace(microsecond=0) - dt = self._lose_timezone(dt) - self.dt = dt + def __init__(self, impl=None): + if impl is None: + impl = self._new() + impl = impl.replace(microsecond=0) + impl = self._lose_timezone(impl) + self.impl = impl @staticmethod - def from_string(s): - return Timestamp(datetime.strptime(s, '%Y-%m-%dT%H:%M:%SZ')) + def from_string(src): + return Timestamp(datetime.strptime(src, '%Y-%m-%dT%H:%M:%SZ')) def __str__(self): - return self.dt.isoformat() + 'Z' + return self.impl.isoformat() + 'Z' diff --git a/vk/tracking/online_sessions.py b/vk/tracking/online_sessions.py index 204e1cc..11d3196 100644 --- a/vk/tracking/online_sessions.py +++ b/vk/tracking/online_sessions.py @@ -99,20 +99,20 @@ class OnlineSessionEnumerator(MutableMapping): return by_hour @staticmethod - def _split_into_days(a, b): - while a.date() != b.date(): - next_day = a.date() + timedelta(days=1) - yield a.date(), next_day - a - a = next_day - yield b.date(), b - a + def _split_into_days(time_from, time_to): + while time_from.date() != time_to.date(): + next_day = time_from.date() + timedelta(days=1) + yield time_from.date(), next_day - time_from + time_from = next_day + yield time_to.date(), time_to - time_from @staticmethod - def _split_into_hours(a, b): - while a.date() != b.date() or a.hour != b.hour: - next_hour = a.replace(minute=0, second=0) + timedelta(hours=1) - yield a.hour, next_hour - a - a = next_hour - yield b.hour, b - a + def _split_into_hours(time_from, time_to): + while time_from.date() != time_to.date() or time_from.hour != time_to.hour: + next_hour = time_from.replace(minute=0, second=0) + timedelta(hours=1) + yield time_from.hour, next_hour - time_from + time_from = next_hour + yield time_to.hour, time_to - time_from def _process_database_record(self, record): return self._close_user_session(record.to_user()) diff --git a/vk/tracking/status_tracker.py b/vk/tracking/status_tracker.py index d47de39..d52af6a 100644 --- a/vk/tracking/status_tracker.py +++ b/vk/tracking/status_tracker.py @@ -27,21 +27,21 @@ class StatusTracker: self.add_status_update_handler(writer.on_status_update) self.add_connection_error_handler(writer.on_connection_error) - def add_initial_status_handler(self, fn): - self._assert_is_callback(fn) - self._on_initial_status.append(fn) + def add_initial_status_handler(self, handler): + self._assert_is_callback(handler) + self._on_initial_status.append(handler) - def add_status_update_handler(self, fn): - self._assert_is_callback(fn) - self._on_status_update.append(fn) + def add_status_update_handler(self, handler): + self._assert_is_callback(handler) + self._on_status_update.append(handler) - def add_connection_error_handler(self, fn): - self._assert_is_callback(fn) - self._on_connection_error.append(fn) + def add_connection_error_handler(self, handler): + self._assert_is_callback(handler) + self._on_connection_error.append(handler) @staticmethod - def _assert_is_callback(fn): - if not isinstance(fn, Callable): + def _assert_is_callback(handler): + if not isinstance(handler, Callable): raise TypeError() _USER_FIELDS = UserField.DOMAIN, UserField.ONLINE, UserField.LAST_SEEN, @@ -50,16 +50,16 @@ class StatusTracker: return {user.get_uid(): user for user in self._api.users_get(uids, self._USER_FIELDS)} def _notify_status(self, user): - for fn in self._on_initial_status: - fn(user) + for handler in self._on_initial_status: + handler(user) def _notify_status_update(self, user): - for fn in self._on_status_update: - fn(user) + for handler in self._on_status_update: + handler(user) def _notify_connection_error(self, e): - for fn in self._on_connection_error: - fn(e) + for handler in self._on_connection_error: + handler(e) def _query_initial_status(self, uids): while True: @@ -9,30 +9,30 @@ from enum import Enum 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) +def _parse_last_seen(src): + if isinstance(src, LastSeen): + return src + elif isinstance(src, Mapping): + return LastSeen.from_api_response(src) else: raise TypeError() -def _parse_bool(x): - if isinstance(x, str): - if str(True) == x: +def _parse_bool(src): + if isinstance(src, str): + if str(True) == src: return True - elif str(False) == x: + elif str(False) == src: return False else: raise ValueError() else: - return bool(x) + return bool(src) -def _parse_hidden(x): - return _parse_bool(x) +def _parse_hidden(src): + return _parse_bool(src) -def _parse_online_flag(x): - return _parse_bool(x) +def _parse_online_flag(src): + return _parse_bool(src) class UserField(Enum): UID = 'uid' @@ -56,8 +56,8 @@ class DeactivationReason(Enum): def __str__(self): return self.value -def _parse_deactivated(s): - return DeactivationReason(s) +def _parse_deactivated(src): + return DeactivationReason(src) class User(Hashable, MutableMapping): @staticmethod |