diff options
| -rw-r--r-- | vk/api.py | 34 | ||||
| -rw-r--r-- | vk/mutuals.py | 32 | ||||
| -rw-r--r-- | vk/platform.py | 2 | ||||
| -rw-r--r-- | vk/tracking/__init__.py | 5 | ||||
| -rw-r--r-- | vk/tracking/db/backend/__init__.py | 6 | ||||
| -rw-r--r-- | vk/tracking/db/backend/log.py | 16 | ||||
| -rw-r--r-- | vk/tracking/sessions.py | 120 | ||||
| -rw-r--r-- | vk/tracking/status.py | 82 | ||||
| -rw-r--r-- | vk/user.py | 2 | ||||
| -rw-r--r-- | vk/utils/bar_chart.py | 35 | ||||
| -rw-r--r-- | vk/utils/io.py | 6 | ||||
| -rw-r--r-- | vk/version.py | 5 |
12 files changed, 219 insertions, 126 deletions
@@ -26,9 +26,15 @@ def _filter_empty_params(params, empty_params=False): if empty_params: return params if isinstance(params, Mapping): - return {name: value for name, value in params.items() if not _is_empty_param_value(value)} + return { + name: value + for name, value in params.items() + if not _is_empty_param_value(value) + } if isinstance(params, Iterable): - return [(name, value) for name, value in params if not _is_empty_param_value(value)] + return [ + (name, value) for name, value in params if not _is_empty_param_value(value) + ] raise TypeError() @@ -116,11 +122,11 @@ class API: def _call_method(self, method, **params): url = self._build_method_url(method, **params) - #print(url) + # print(url) try: with urlopen(url) as response: response = json.loads(response.read().decode()) - #print(response) + # print(response) if 'response' not in response: raise vk.error.InvalidAPIResponseError(response) return response['response'] @@ -135,17 +141,19 @@ class API: return [user for user in user_list if not user.is_deactivated()] def users_get(self, user_ids, fields=(), deactivated_users=True): - return self._filter_response_with_users(self._call_method( - Method.USERS_GET, - user_ids=_join_param_values(user_ids), - fields=_join_param_values(fields)), deactivated_users) + return self._filter_response_with_users( + self._call_method( + Method.USERS_GET, + user_ids=_join_param_values(user_ids), + fields=_join_param_values(fields), + ), + deactivated_users, + ) def friends_get(self, user_id, fields=(), deactivated_users=True): response = self._call_method( - Method.FRIENDS_GET, - user_id=user_id, - fields=_join_param_values(fields)) + Method.FRIENDS_GET, user_id=user_id, fields=_join_param_values(fields) + ) if 'items' not in response: raise vk.error.InvalidAPIResponseError(response) - return self._filter_response_with_users(response['items'], - deactivated_users) + return self._filter_response_with_users(response['items'], deactivated_users) diff --git a/vk/mutuals.py b/vk/mutuals.py index 10dcc2e..047029e 100644 --- a/vk/mutuals.py +++ b/vk/mutuals.py @@ -14,7 +14,6 @@ from vk.user import UserField from vk.utils import io import vk.version - _OUTPUT_USER_FIELDS = UserField.UID, UserField.FIRST_NAME, UserField.LAST_NAME @@ -83,19 +82,30 @@ def _parse_args(args=None): args = sys.argv[1:] parser = argparse.ArgumentParser( - description='Learn who your ex and her new boyfriend are both friends with.') + description='Learn who your ex and her new boyfriend are both friends with.' + ) vk.version.add_to_arg_parser(parser) - parser.add_argument('uids', metavar='UID', nargs='+', - help='user IDs or "screen names"') - parser.add_argument('-f', '--format', dest='out_fmt', - type=_parse_output_format, - default=OutputFormat.CSV, - choices=OutputFormat, - help='specify output format') - parser.add_argument('-o', '--output', metavar='PATH', dest='out_path', - help='set output file path (standard output by default)') + parser.add_argument( + 'uids', metavar='UID', nargs='+', help='user IDs or "screen names"' + ) + parser.add_argument( + '-f', + '--format', + dest='out_fmt', + type=_parse_output_format, + default=OutputFormat.CSV, + choices=OutputFormat, + help='specify output format', + ) + parser.add_argument( + '-o', + '--output', + metavar='PATH', + dest='out_path', + help='set output file path (standard output by default)', + ) return parser.parse_args(args) diff --git a/vk/platform.py b/vk/platform.py index 5cd78b8..c922983 100644 --- a/vk/platform.py +++ b/vk/platform.py @@ -29,7 +29,7 @@ class Platform(Enum): m = re.search(r'\w', s) if m is None: return s - return s[:m.start()] + m.group().upper() + s[m.end():] + return s[: m.start()] + m.group().upper() + s[m.end() :] def get_descr_header(self): return self._capitalize_first_letter(_PLATFORM_DESCRIPTIONS[self]) diff --git a/vk/tracking/__init__.py b/vk/tracking/__init__.py index 73133d8..51c35cd 100644 --- a/vk/tracking/__init__.py +++ b/vk/tracking/__init__.py @@ -2,4 +2,7 @@ # This file is licensed under the terms of the MIT License. # See LICENSE.txt for details. -__all__ = 'sessions', 'status', +__all__ = ( + 'sessions', + 'status', +) diff --git a/vk/tracking/db/backend/__init__.py b/vk/tracking/db/backend/__init__.py index 58b5a9a..5b2398b 100644 --- a/vk/tracking/db/backend/__init__.py +++ b/vk/tracking/db/backend/__init__.py @@ -5,4 +5,8 @@ from . import csv, log, null -__all__ = 'csv', 'log', 'null', +__all__ = ( + 'csv', + 'log', + 'null', +) diff --git a/vk/tracking/db/backend/log.py b/vk/tracking/db/backend/log.py index efdc664..11fc328 100644 --- a/vk/tracking/db/backend/log.py +++ b/vk/tracking/db/backend/log.py @@ -13,9 +13,11 @@ class Writer(meta.Writer): self._logger = logging.getLogger(__file__) self._logger.setLevel(logging.INFO) handler = logging.StreamHandler(fd) - handler.setFormatter(logging.Formatter( - fmt='[%(asctime)s] %(message)s', - datefmt='%Y-%m-%d %H:%M:%S%z')) + handler.setFormatter( + logging.Formatter( + fmt='[%(asctime)s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S%z' + ) + ) self._logger.addHandler(handler) self._reset_last_notification() @@ -86,7 +88,8 @@ class Writer(meta.Writer): return '{} was last seen at {} using {}.'.format( Writer._format_user(user), user.get_last_seen_time_local(), - user.get_last_seen_platform().get_descr_text()) + user.get_last_seen_platform().get_descr_text(), + ) @staticmethod def _format_user_went_online(user): @@ -98,4 +101,7 @@ class Writer(meta.Writer): @staticmethod def _format_another_connection_error(e): - return 'Encountered a connection error which looks like the previous one: ' + str(e) + return ( + 'Encountered a connection error which looks like the previous one: ' + + str(e) + ) diff --git a/vk/tracking/sessions.py b/vk/tracking/sessions.py index 4b6fd66..4622c2e 100644 --- a/vk/tracking/sessions.py +++ b/vk/tracking/sessions.py @@ -339,10 +339,12 @@ class OutputSinkPlot(OutputSinkOnlineSessions): @staticmethod def _extract_values(durations): - return (OutputSinkPlot._duration_to_seconds(duration) for duration in durations.values()) + return ( + OutputSinkPlot._duration_to_seconds(duration) + for duration in durations.values() + ) - def process_database( - self, group_by, db_reader, time_from=None, time_to=None): + def process_database(self, group_by, db_reader, time_from=None, time_to=None): durations = group_by.group(db_reader, time_from, time_to) @@ -350,8 +352,9 @@ class OutputSinkPlot(OutputSinkOnlineSessions): bar_chart.set_title(OutputSinkPlot.TITLE) bar_chart.enable_grid_for_values() bar_chart.only_integer_values() - bar_chart.set_property(bar_chart.get_values_labels(), - fontsize='small', rotation=30) + bar_chart.set_property( + bar_chart.get_values_labels(), fontsize='small', rotation=30 + ) bar_chart.set_value_label_formatter(self._format_duration) labels = tuple(self._extract_labels(group_by, durations)) @@ -363,9 +366,8 @@ class OutputSinkPlot(OutputSinkOnlineSessions): else: bar_height = bar_chart.THICK_BAR_HEIGHT - bars = bar_chart.plot_bars( - labels, durations, bar_height=bar_height) - bar_chart.set_property(bars, alpha=.33) + bars = bar_chart.plot_bars(labels, durations, bar_height=bar_height) + bar_chart.set_property(bars, alpha=0.33) if self._fd is sys.stdout: bar_chart.show() @@ -426,8 +428,7 @@ def _parse_date_range_limit(s): return dt.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)) + raise argparse.ArgumentTypeError(msg.format(_DATE_RANGE_LIMIT_FORMAT, s)) def _parse_args(args=None): @@ -435,44 +436,78 @@ def _parse_args(args=None): args = sys.argv[1:] parser = argparse.ArgumentParser( - description='View/visualize the amount of time people spend online.') + description='View/visualize the amount of time people spend online.' + ) vk.version.add_to_arg_parser(parser) - parser.add_argument('db_path', metavar='input', nargs='?', - help='database file path (standard input by default)') - parser.add_argument('out_path', metavar='output', nargs='?', - help='output file path (standard output by default)') - parser.add_argument('-g', '--group-by', - type=_parse_group_by, - choices=GroupBy, - default=GroupBy.USER, - help='group online sessions by user/date/etc.') - parser.add_argument('-i', '--input-format', dest='db_fmt', - type=_parse_database_format, - default=DatabaseFormat.CSV, - choices=DatabaseFormat, - help='specify database format') - parser.add_argument('-o', '--output-format', dest='out_fmt', - type=_parse_output_format, - choices=OutputFormat, - default=OutputFormat.CSV, - help='specify output format') - parser.add_argument('-a', '--from', dest='time_from', - type=_parse_date_range_limit, default=None, - help='discard online activity prior to this moment') - parser.add_argument('-b', '--to', dest='time_to', - type=_parse_date_range_limit, default=None, - help='discard online activity after this moment') + parser.add_argument( + 'db_path', + metavar='input', + nargs='?', + help='database file path (standard input by default)', + ) + parser.add_argument( + 'out_path', + metavar='output', + nargs='?', + help='output file path (standard output by default)', + ) + parser.add_argument( + '-g', + '--group-by', + type=_parse_group_by, + choices=GroupBy, + default=GroupBy.USER, + help='group online sessions by user/date/etc.', + ) + parser.add_argument( + '-i', + '--input-format', + dest='db_fmt', + type=_parse_database_format, + default=DatabaseFormat.CSV, + choices=DatabaseFormat, + help='specify database format', + ) + parser.add_argument( + '-o', + '--output-format', + dest='out_fmt', + type=_parse_output_format, + choices=OutputFormat, + default=OutputFormat.CSV, + help='specify output format', + ) + parser.add_argument( + '-a', + '--from', + dest='time_from', + type=_parse_date_range_limit, + default=None, + help='discard online activity prior to this moment', + ) + parser.add_argument( + '-b', + '--to', + dest='time_to', + type=_parse_date_range_limit, + default=None, + help='discard online activity after this moment', + ) return parser.parse_args(args) def process_online_sessions( - db_path=None, db_fmt=DatabaseFormat.CSV, - out_path=None, out_fmt=OutputFormat.CSV, - group_by=GroupBy.USER, - time_from=None, time_to=None): + db_path=None, + db_fmt=DatabaseFormat.CSV, + out_path=None, + out_fmt=OutputFormat.CSV, + group_by=GroupBy.USER, + time_from=None, + time_to=None, +): if time_from is not None and time_to is not None: if time_from > time_to: @@ -483,9 +518,8 @@ def process_online_sessions( with out_fmt.open_file(out_path) as out_fd: out_sink = out_fmt.create_sink(out_fd) out_sink.process_database( - group_by, db_reader, - time_from=time_from, - time_to=time_to) + group_by, db_reader, time_from=time_from, time_to=time_to + ) def main(args=None): diff --git a/vk/tracking/status.py b/vk/tracking/status.py index 0dd5e42..42f0adb 100644 --- a/vk/tracking/status.py +++ b/vk/tracking/status.py @@ -52,11 +52,16 @@ class StatusTracker: if not isinstance(fn, Callable): raise TypeError() - _USER_FIELDS = UserField.DOMAIN, UserField.ONLINE, UserField.LAST_SEEN, + _USER_FIELDS = ( + UserField.DOMAIN, + UserField.ONLINE, + UserField.LAST_SEEN, + ) def _query_status(self, uids): - user_list = self._api.users_get(uids, self._USER_FIELDS, - deactivated_users=False) + user_list = self._api.users_get( + uids, self._USER_FIELDS, deactivated_users=False + ) return {user.get_uid(): user for user in user_list} def _notify_status(self, user): @@ -128,13 +133,11 @@ class StatusTracker: def _handle_sigint(): # Python doesn't raise KeyboardInterrupt in case a real SIGINT is sent # from outside, surprisingly. - return StatusTracker._handle_signal(signal.SIGINT, - StatusTracker._stop_looping) + return StatusTracker._handle_signal(signal.SIGINT, StatusTracker._stop_looping) @staticmethod def _handle_sigterm(): - return StatusTracker._handle_signal(signal.SIGTERM, - StatusTracker._stop_looping) + return StatusTracker._handle_signal(signal.SIGTERM, StatusTracker._stop_looping) def loop(self, uids): with self._handle_sigint(), self._handle_sigterm(): @@ -169,35 +172,58 @@ def _parse_args(args=None): if args is None: args = sys.argv[1:] - parser = argparse.ArgumentParser( - description='Track when people go online/offline.') + parser = argparse.ArgumentParser(description='Track when people go online/offline.') vk.version.add_to_arg_parser(parser) - parser.add_argument('uids', metavar='UID', nargs='+', - help='user IDs or "screen names"') - parser.add_argument('-t', '--timeout', metavar='SECONDS', - type=_parse_positive_integer, - default=DEFAULT_TIMEOUT, - help='set refresh interval') - parser.add_argument('-O', '--only-once', action='store_true', - help='query the status only once and exit') - parser.add_argument('-l', '--log', metavar='PATH', dest='log_path', - help='set log file path (standard output by default)') - parser.add_argument('-f', '--format', dest='db_fmt', - type=_parse_database_format, - choices=DatabaseFormat, - default=DEFAULT_DB_FORMAT, - help='specify database format') - parser.add_argument('-o', '--output', metavar='PATH', dest='db_path', - help='set database file path') + parser.add_argument( + 'uids', metavar='UID', nargs='+', help='user IDs or "screen names"' + ) + parser.add_argument( + '-t', + '--timeout', + metavar='SECONDS', + type=_parse_positive_integer, + default=DEFAULT_TIMEOUT, + help='set refresh interval', + ) + parser.add_argument( + '-O', + '--only-once', + action='store_true', + help='query the status only once and exit', + ) + parser.add_argument( + '-l', + '--log', + metavar='PATH', + dest='log_path', + help='set log file path (standard output by default)', + ) + parser.add_argument( + '-f', + '--format', + dest='db_fmt', + type=_parse_database_format, + choices=DatabaseFormat, + default=DEFAULT_DB_FORMAT, + help='specify database format', + ) + parser.add_argument( + '-o', '--output', metavar='PATH', dest='db_path', help='set database file path' + ) return parser.parse_args(args) def track_status( - uids, timeout=DEFAULT_TIMEOUT, log_path=None, - db_path=None, db_fmt=DEFAULT_DB_FORMAT, only_once=False): + uids, + timeout=DEFAULT_TIMEOUT, + log_path=None, + db_path=None, + db_fmt=DEFAULT_DB_FORMAT, + only_once=False, +): api = API() tracker = StatusTracker(api, timeout) @@ -79,7 +79,7 @@ class User(Hashable, MutableMapping): def __eq__(self, other): return self.get_uid() == other.get_uid() - #return self._fields == other._fields + # return self._fields == other._fields def __hash__(self): return hash(self.get_uid()) diff --git a/vk/utils/bar_chart.py b/vk/utils/bar_chart.py index f051efc..a2970f2 100644 --- a/vk/utils/bar_chart.py +++ b/vk/utils/bar_chart.py @@ -9,7 +9,7 @@ import numpy as np class BarChartBuilder: - _BAR_HEIGHT = .5 + _BAR_HEIGHT = 0.5 THICK_BAR_HEIGHT = _BAR_HEIGHT THIN_BAR_HEIGHT = THICK_BAR_HEIGHT / 2 @@ -112,12 +112,11 @@ class BarChartBuilder: self._get_categories_axis().set_ticklabels(categories) - bars = self._ax.barh(bar_offsets, values, align='center', - height=bar_height) + bars = self._ax.barh(bar_offsets, values, align='center', height=bar_height) if min(values) >= 0: self.set_values_axis_limits(start=0) - if np.isclose(max(values), 0.): + if np.isclose(max(values), 0.0): self.set_values_axis_limits(end=self._DEFAULT_VALUES_AXIS_MAX) elif max(values) < 0: self.set_values_axis_limits(end=0) @@ -134,23 +133,27 @@ class BarChartBuilder: if __name__ == '__main__': import argparse + parser = argparse.ArgumentParser() - parser.add_argument('--categories', nargs='*', metavar='LABEL', - default=[]) - parser.add_argument('--values', nargs='*', metavar='N', - default=[], type=float) + parser.add_argument('--categories', nargs='*', metavar='LABEL', default=[]) + parser.add_argument('--values', nargs='*', metavar='N', default=[], type=float) parser.add_argument('--output', '-o', help='set output file path') - parser.add_argument('--align-middle', action='store_true', - dest='labels_align_middle', - help='align labels to the middle of the bars') + parser.add_argument( + '--align-middle', + action='store_true', + dest='labels_align_middle', + help='align labels to the middle of the bars', + ) - parser.add_argument('--integer-values', action='store_true', - dest='only_integer_values') - parser.add_argument('--any-values', action='store_false', - dest='only_integer_values') + parser.add_argument( + '--integer-values', action='store_true', dest='only_integer_values' + ) + parser.add_argument( + '--any-values', action='store_false', dest='only_integer_values' + ) parser.add_argument('--grid-categories', action='store_true') parser.add_argument('--grid-values', action='store_true') @@ -160,7 +163,7 @@ if __name__ == '__main__': if len(args.categories) < len(args.values): parser.error('too many bar values') if len(args.categories) > len(args.values): - args.values.extend([0.] * (len(args.categories) - len(args.values))) + args.values.extend([0.0] * (len(args.categories) - len(args.values))) builder = BarChartBuilder(labels_align_middle=args.labels_align_middle) diff --git a/vk/utils/io.py b/vk/utils/io.py index eccb726..700fcbf 100644 --- a/vk/utils/io.py +++ b/vk/utils/io.py @@ -59,13 +59,11 @@ _DEFAULT_ENCODING = 'utf-8' def open_input_text_file(path=None): - return _open_file(path, default=sys.stdin, mode='r', - encoding=_DEFAULT_ENCODING) + return _open_file(path, default=sys.stdin, mode='r', encoding=_DEFAULT_ENCODING) def open_output_text_file(path=None, mode='w'): - return _open_file(path, default=sys.stdout, mode=mode, - encoding=_DEFAULT_ENCODING) + return _open_file(path, default=sys.stdout, mode=mode, encoding=_DEFAULT_ENCODING) def open_output_binary_file(path=None): diff --git a/vk/version.py b/vk/version.py index 6843bf4..0f611aa 100644 --- a/vk/version.py +++ b/vk/version.py @@ -11,5 +11,6 @@ except Exception: def add_to_arg_parser(parser): - parser.add_argument('--version', '-V', action='version', - version=f'%(prog)s {__version__}') + parser.add_argument( + '--version', '-V', action='version', version=f'%(prog)s {__version__}' + ) |
