vk-scripts 1.2.0__tar.gz → 1.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/.github/workflows/ci.yml +33 -9
  2. {vk_scripts-1.2.0/vk_scripts.egg-info → vk_scripts-1.3.1}/PKG-INFO +2 -21
  3. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/README.md +0 -19
  4. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/docs/mutuals.md +2 -1
  5. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/docs/sessions.md +3 -2
  6. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/docs/status.md +2 -2
  7. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/pyproject.toml +7 -1
  8. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/test/lib/test.sh +3 -2
  9. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/test/tst-sessions.sh +0 -8
  10. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/api.py +6 -18
  11. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/last_seen.py +4 -7
  12. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/mutuals.py +8 -8
  13. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/platform.py +2 -5
  14. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/db/format.py +5 -8
  15. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/sessions.py +17 -23
  16. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/status.py +9 -2
  17. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/user.py +12 -18
  18. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/utils/bar_chart.py +39 -11
  19. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/version.py +4 -1
  20. {vk_scripts-1.2.0 → vk_scripts-1.3.1/vk_scripts.egg-info}/PKG-INFO +2 -21
  21. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk_scripts.egg-info/SOURCES.txt +0 -1
  22. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk_scripts.egg-info/scm_file_list.json +0 -1
  23. vk_scripts-1.3.1/vk_scripts.egg-info/scm_version.json +8 -0
  24. vk_scripts-1.2.0/.pylintrc +0 -8
  25. vk_scripts-1.2.0/vk_scripts.egg-info/scm_version.json +0 -8
  26. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/.git-blame-ignore-revs +0 -0
  27. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/.gitattributes +0 -0
  28. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/.github/dependabot.yml +0 -0
  29. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/.gitignore +0 -0
  30. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/LICENSE.txt +0 -0
  31. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/docs/images/date.png +0 -0
  32. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/docs/images/hour.png +0 -0
  33. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/docs/images/user.png +0 -0
  34. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/docs/images/weekday.png +0 -0
  35. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/setup.cfg +0 -0
  36. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/test/data/test_db.csv +0 -0
  37. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/test/lib/log.sh +0 -0
  38. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/test/main.sh +0 -0
  39. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/test/tst-mutuals.sh +0 -0
  40. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/test/tst-status-once.sh +0 -0
  41. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/test/tst-status.sh +0 -0
  42. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/__init__.py +0 -0
  43. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/error.py +0 -0
  44. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/__init__.py +0 -0
  45. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/db/__init__.py +0 -0
  46. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/db/backend/__init__.py +0 -0
  47. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/db/backend/csv.py +0 -0
  48. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/db/backend/log.py +0 -0
  49. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/db/backend/null.py +0 -0
  50. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/db/meta.py +0 -0
  51. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/db/record.py +0 -0
  52. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/tracking/db/timestamp.py +0 -0
  53. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/utils/__init__.py +0 -0
  54. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk/utils/io.py +0 -0
  55. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk_scripts.egg-info/dependency_links.txt +0 -0
  56. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk_scripts.egg-info/entry_points.txt +0 -0
  57. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk_scripts.egg-info/requires.txt +0 -0
  58. {vk_scripts-1.2.0 → vk_scripts-1.3.1}/vk_scripts.egg-info/top_level.txt +0 -0
@@ -22,8 +22,6 @@ jobs:
22
22
  steps:
23
23
  - name: Checkout
24
24
  uses: actions/checkout@v7
25
- with:
26
- fetch-depth: 0
27
25
  - name: Set up Python
28
26
  uses: actions/setup-python@v7
29
27
  with:
@@ -31,10 +29,14 @@ jobs:
31
29
  - name: Run black
32
30
  uses: psf/black@stable
33
31
 
34
- test:
32
+ test_python:
35
33
  strategy:
36
34
  matrix:
37
- python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
35
+ python-version:
36
+ - '3.11'
37
+ - '3.12'
38
+ - '3.13'
39
+ - '3.14'
38
40
  # Random number to prevent exceeding the request frequency limit.
39
41
  max-parallel: 3
40
42
  runs-on: ubuntu-latest
@@ -42,8 +44,6 @@ jobs:
42
44
  steps:
43
45
  - name: Checkout
44
46
  uses: actions/checkout@v7
45
- with:
46
- fetch-depth: 0
47
47
  - name: Set up Python
48
48
  uses: actions/setup-python@v7
49
49
  with:
@@ -58,15 +58,39 @@ jobs:
58
58
  - name: Run tests
59
59
  run: ./test/main.sh
60
60
 
61
+ test_ubuntu:
62
+ strategy:
63
+ matrix:
64
+ codename:
65
+ - noble
66
+ - resolute
67
+ runs-on: ubuntu-latest
68
+ container:
69
+ image: 'ubuntu:${{ matrix.codename }}'
70
+ name: 'Ubuntu: ${{ matrix.codename }}'
71
+ steps:
72
+ - name: Install dependencies
73
+ run: |
74
+ apt update
75
+ DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \
76
+ ca-certificates \
77
+ python3 \
78
+ python3-matplotlib
79
+ - name: Checkout
80
+ uses: actions/checkout@v7
81
+ - name: Run tests
82
+ run: ./test/main.sh
83
+
61
84
  publish_pypi:
62
- needs: [lint, test]
85
+ needs:
86
+ - lint
87
+ - test_python
88
+ - test_ubuntu
63
89
  runs-on: ubuntu-latest
64
90
  name: Publish
65
91
  steps:
66
92
  - name: Checkout
67
93
  uses: actions/checkout@v7
68
- with:
69
- fetch-depth: 0
70
94
  - name: Set up Python
71
95
  uses: actions/setup-python@v7
72
96
  with:
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vk_scripts
3
- Version: 1.2.0
3
+ Version: 1.3.1
4
4
  Summary: Scripts to stalk people on VK
5
5
  Author-email: Egor Tensin <egor@tensin.name>
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/egor-tensin/vk-scripts
8
8
  Project-URL: Bug Tracker, https://github.com/egor-tensin/vk-scripts/issues
9
9
  Classifier: Development Status :: 5 - Production/Stable
10
- Requires-Python: >=3.6
10
+ Requires-Python: >=3.11
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE.txt
13
13
  Requires-Dist: importlib-metadata~=4.0; python_version < "3.8"
@@ -42,25 +42,6 @@ with.
42
42
  [vk-status]: docs/status.md
43
43
  [vk-sessions]: docs/sessions.md
44
44
 
45
- Development
46
- -----------
47
-
48
- ### Linting
49
-
50
- Requires [Pylint].
51
-
52
- pylint vk
53
-
54
- [Pylint]: https://www.pylint.org/
55
-
56
- ### Releases
57
-
58
- Make a git tag:
59
-
60
- git tag "v$( python -m setuptools_scm --strip-dev )"
61
-
62
- You can then review that the tag is fine and push w/ `git push --tags`.
63
-
64
45
  License
65
46
  -------
66
47
 
@@ -26,25 +26,6 @@ with.
26
26
  [vk-status]: docs/status.md
27
27
  [vk-sessions]: docs/sessions.md
28
28
 
29
- Development
30
- -----------
31
-
32
- ### Linting
33
-
34
- Requires [Pylint].
35
-
36
- pylint vk
37
-
38
- [Pylint]: https://www.pylint.org/
39
-
40
- ### Releases
41
-
42
- Make a git tag:
43
-
44
- git tag "v$( python -m setuptools_scm --strip-dev )"
45
-
46
- You can then review that the tag is fine and push w/ `git push --tags`.
47
-
48
29
  License
49
30
  -------
50
31
 
@@ -7,7 +7,8 @@ Usage
7
7
  -----
8
8
 
9
9
  > vk-mutuals -h
10
- usage: vk-mutuals [-h] [-f {csv,json}] [-o PATH] UID [UID ...]
10
+ usage: vk-mutuals [-h] [--version] [-f {csv,json}] [-o PATH]
11
+ UID [UID ...]
11
12
  ...
12
13
 
13
14
  For example (using made up user IDs/"screen names"),
@@ -8,8 +8,9 @@ Usage
8
8
 
9
9
  ```
10
10
  > vk-sessions -h
11
- usage: vk-sessions [-h] [-g {user,date,weekday,hour}] [-i {csv,log,null}]
12
- [-o {csv,json,plot}] [-a TIME_FROM] [-b TIME_TO]
11
+ usage: vk-sessions [-h] [--version] [-g {user,date,weekday,hour}]
12
+ [-i {csv,log,null}] [-o {csv,json,plot}]
13
+ [-a TIME_FROM] [-b TIME_TO]
13
14
  [input] [output]
14
15
  ```
15
16
 
@@ -7,8 +7,8 @@ Usage
7
7
  -----
8
8
 
9
9
  > vk-status -h
10
- usage: vk-status [-h] [-t SECONDS] [-O] [-l PATH] [-f {csv,log,null}]
11
- [-o PATH]
10
+ usage: vk-status [-h] [--version] [-t SECONDS] [-O] [-l PATH]
11
+ [-f {csv,log,null}] [-o PATH]
12
12
  UID [UID ...]
13
13
  ...
14
14
 
@@ -12,7 +12,8 @@ license-files = ["LICENSE.txt"]
12
12
  dynamic = ["version"]
13
13
  authors = [{name = "Egor Tensin", email = "egor@tensin.name"}]
14
14
  readme = "README.md"
15
- requires-python = ">=3.6"
15
+ requires-python = ">=3.11"
16
+ # ^^^ For enum.StrEnum, at least?
16
17
 
17
18
  dependencies = [
18
19
  'importlib-metadata ~= 4.0 ; python_version < "3.8"',
@@ -33,3 +34,8 @@ vk-status = "vk.tracking.status:main"
33
34
  vk-mutuals = "vk.mutuals:main"
34
35
 
35
36
  [tool.setuptools_scm]
37
+
38
+ [tool.pylint."messages control"]
39
+ disable = [
40
+ "missing-docstring",
41
+ ]
@@ -20,6 +20,7 @@ test_cleanup_default() {
20
20
  }
21
21
 
22
22
  test_run_module() {
23
- log_run python -m "$@"
24
- PYTHONPATH="$script_dir/.." python -m "$@"
23
+ local cmd=(python3 -m "$@")
24
+ log_run "${cmd[@]}"
25
+ PYTHONPATH="$script_dir/.." "${cmd[@]}"
25
26
  }
@@ -37,15 +37,7 @@ _test_main() {
37
37
  _test_group_by weekday
38
38
  }
39
39
 
40
- _fix_matplotlib() {
41
- # Get rid of:
42
- # tkinter.TclError: no display name and no $DISPLAY environment variable
43
- mkdir -p -- ~/.config/matplotlib
44
- echo 'backend: Agg' > ~/.config/matplotlib/matplotlibrc
45
- }
46
-
47
40
  test_run() {
48
41
  test_setup
49
- _fix_matplotlib
50
42
  _test_main
51
43
  }
@@ -4,7 +4,7 @@
4
4
  # Distributed under the MIT License.
5
5
 
6
6
  from collections.abc import Iterable, Mapping
7
- from enum import Enum
7
+ from enum import auto, StrEnum
8
8
  import json
9
9
  from urllib.error import URLError
10
10
  import urllib.parse
@@ -69,39 +69,27 @@ def _join_path(base, url):
69
69
  ACCESS_TOKEN = "3d242bac3d242bac3d242bacd03e66eae033d243d242bac5755894cf6163d769859232d"
70
70
 
71
71
 
72
- class Version(Enum):
72
+ class Version(StrEnum):
73
73
  # https://dev.vk.com/en/reference/versions
74
74
  V5_199 = "5.199"
75
75
  DEFAULT = V5_199
76
76
 
77
- def __str__(self):
78
- return self.value
79
77
 
80
-
81
- class Language(Enum):
82
- EN = "en"
78
+ class Language(StrEnum):
79
+ EN = auto()
83
80
  DEFAULT = EN
84
81
 
85
- def __str__(self):
86
- return self.value
87
-
88
82
 
89
- class Method(Enum):
83
+ class Method(StrEnum):
90
84
  USERS_GET = "users.get"
91
85
  FRIENDS_GET = "friends.get"
92
86
 
93
- def __str__(self):
94
- return self.value
95
87
 
96
-
97
- class CommonParameters(Enum):
88
+ class CommonParameters(StrEnum):
98
89
  ACCESS_TOKEN = "access_token"
99
90
  VERSION = "v"
100
91
  LANGUAGE = "lang"
101
92
 
102
- def __str__(self):
103
- return self.value
104
-
105
93
 
106
94
  class API:
107
95
  _ROOT_URL = "https://api.vk.com/method/"
@@ -6,7 +6,7 @@
6
6
  from collections import OrderedDict
7
7
  from collections.abc import MutableMapping
8
8
  from datetime import datetime, timezone
9
- from enum import Enum
9
+ from enum import auto, StrEnum
10
10
  from numbers import Integral, Real
11
11
 
12
12
  from .platform import Platform
@@ -30,12 +30,9 @@ def _parse_platform(x):
30
30
  return Platform(x)
31
31
 
32
32
 
33
- class LastSeenField(Enum):
34
- TIME = "time"
35
- PLATFORM = "platform"
36
-
37
- def __str__(self):
38
- return self.value
33
+ class LastSeenField(StrEnum):
34
+ TIME = auto()
35
+ PLATFORM = auto()
39
36
 
40
37
 
41
38
  class LastSeen(MutableMapping):
@@ -6,7 +6,7 @@
6
6
  import abc
7
7
  import argparse
8
8
  from collections import OrderedDict
9
- from enum import Enum
9
+ from enum import auto, StrEnum
10
10
  import sys
11
11
 
12
12
  from vk.api import API
@@ -56,12 +56,9 @@ class OutputSinkJSON(OutputSinkMutualFriends):
56
56
  self._writer.write(friend_list)
57
57
 
58
58
 
59
- class OutputFormat(Enum):
60
- CSV = "csv"
61
- JSON = "json"
62
-
63
- def __str__(self):
64
- return self.value
59
+ class OutputFormat(StrEnum):
60
+ CSV = auto()
61
+ JSON = auto()
65
62
 
66
63
  @staticmethod
67
64
  def open_file(path=None):
@@ -93,7 +90,10 @@ def _parse_args(args=None):
93
90
  vk.version.add_to_arg_parser(parser)
94
91
 
95
92
  parser.add_argument(
96
- "uids", metavar="UID", nargs="+", help='user IDs or "screen names"'
93
+ "uids",
94
+ metavar="UID",
95
+ nargs="+",
96
+ help='user IDs or "screen names"',
97
97
  )
98
98
  parser.add_argument(
99
99
  "-f",
@@ -3,10 +3,10 @@
3
3
  # For details, see https://github.com/egor-tensin/vk-scripts
4
4
  # Distributed under the MIT License.
5
5
 
6
- from enum import Enum
6
+ from enum import IntEnum
7
7
 
8
8
 
9
- class Platform(Enum):
9
+ class Platform(IntEnum):
10
10
  # https://dev.vk.com/en/reference/objects/user#last_seen
11
11
  MOBILE = 1
12
12
  IPHONE = 2
@@ -20,9 +20,6 @@ class Platform(Enum):
20
20
  def from_string(s):
21
21
  return Platform(int(s))
22
22
 
23
- def __str__(self):
24
- return str(self.value)
25
-
26
23
  @property
27
24
  def descr(self):
28
25
  return f"the {_PLATFORM_DESCRIPTIONS[self]}"
@@ -3,7 +3,7 @@
3
3
  # For details, see https://github.com/egor-tensin/vk-scripts
4
4
  # Distributed under the MIT License.
5
5
 
6
- from enum import Enum
6
+ from enum import auto, StrEnum
7
7
  import sys
8
8
 
9
9
  from vk.utils import io
@@ -11,13 +11,10 @@ from vk.utils import io
11
11
  from . import backend
12
12
 
13
13
 
14
- class Format(Enum):
15
- CSV = "csv"
16
- LOG = "log"
17
- NULL = "null"
18
-
19
- def __str__(self):
20
- return self.value
14
+ class Format(StrEnum):
15
+ CSV = auto()
16
+ LOG = auto()
17
+ NULL = auto()
21
18
 
22
19
  def create_writer(self, fd=sys.stdout):
23
20
  if self is Format.CSV:
@@ -8,7 +8,7 @@ import argparse
8
8
  from collections import OrderedDict
9
9
  from collections.abc import MutableMapping
10
10
  from datetime import datetime, timedelta, timezone
11
- from enum import Enum
11
+ from enum import auto, IntEnum, StrEnum
12
12
  import sys
13
13
 
14
14
  from vk.tracking.db import Format as DatabaseFormat
@@ -18,14 +18,14 @@ from vk.utils import io
18
18
  import vk.version
19
19
 
20
20
 
21
- class Weekday(Enum):
21
+ class Weekday(IntEnum):
22
22
  MONDAY = 0
23
- TUESDAY = 1
24
- WEDNESDAY = 2
25
- THURSDAY = 3
26
- FRIDAY = 4
27
- SATURDAY = 5
28
- SUNDAY = 6
23
+ TUESDAY = auto()
24
+ WEDNESDAY = auto()
25
+ THURSDAY = auto()
26
+ FRIDAY = auto()
27
+ SATURDAY = auto()
28
+ SUNDAY = auto()
29
29
 
30
30
  def __str__(self):
31
31
  return self.name[0] + self.name[1:].lower()
@@ -143,14 +143,11 @@ class OnlineSessionEnumerator(MutableMapping):
143
143
  return session
144
144
 
145
145
 
146
- class GroupBy(Enum):
147
- USER = "user"
148
- DATE = "date"
149
- WEEKDAY = "weekday"
150
- HOUR = "hour"
151
-
152
- def __str__(self):
153
- return self.value
146
+ class GroupBy(StrEnum):
147
+ USER = auto()
148
+ DATE = auto()
149
+ WEEKDAY = auto()
150
+ HOUR = auto()
154
151
 
155
152
  def group(self, db_reader, time_from=None, time_to=None):
156
153
  online_streaks = OnlineSessionEnumerator(time_from, time_to)
@@ -373,13 +370,10 @@ class OutputSinkPlot(OutputSinkOnlineSessions):
373
370
  bar_chart.save(self._fd)
374
371
 
375
372
 
376
- class OutputFormat(Enum):
377
- CSV = "csv"
378
- JSON = "json"
379
- PLOT = "plot"
380
-
381
- def __str__(self):
382
- return self.value
373
+ class OutputFormat(StrEnum):
374
+ CSV = auto()
375
+ JSON = auto()
376
+ PLOT = auto()
383
377
 
384
378
  def create_sink(self, fd=sys.stdout):
385
379
  if self is OutputFormat.CSV:
@@ -177,7 +177,10 @@ def _parse_args(args=None):
177
177
  vk.version.add_to_arg_parser(parser)
178
178
 
179
179
  parser.add_argument(
180
- "uids", metavar="UID", nargs="+", help='user IDs or "screen names"'
180
+ "uids",
181
+ metavar="UID",
182
+ nargs="+",
183
+ help='user IDs or "screen names"',
181
184
  )
182
185
  parser.add_argument(
183
186
  "-t",
@@ -210,7 +213,11 @@ def _parse_args(args=None):
210
213
  help="specify database format",
211
214
  )
212
215
  parser.add_argument(
213
- "-o", "--output", metavar="PATH", dest="db_path", help="set database file path"
216
+ "-o",
217
+ "--output",
218
+ metavar="PATH",
219
+ dest="db_path",
220
+ help="set database file path",
214
221
  )
215
222
 
216
223
  return parser.parse_args(args)
@@ -5,7 +5,7 @@
5
5
 
6
6
  from collections import OrderedDict
7
7
  from collections.abc import Hashable, Mapping, MutableMapping
8
- from enum import Enum
8
+ from enum import auto, StrEnum
9
9
 
10
10
  from .last_seen import LastSeen
11
11
 
@@ -36,27 +36,21 @@ def _parse_online_flag(x):
36
36
  return _parse_bool(x)
37
37
 
38
38
 
39
- class UserField(Enum):
39
+ class UserField(StrEnum):
40
40
  UID = "id"
41
- FIRST_NAME = "first_name"
42
- LAST_NAME = "last_name"
43
- DEACTIVATED = "deactivated"
44
- HIDDEN = "hidden"
41
+ FIRST_NAME = auto()
42
+ LAST_NAME = auto()
43
+ DEACTIVATED = auto()
44
+ HIDDEN = auto()
45
45
 
46
- DOMAIN = "domain"
47
- ONLINE = "online"
48
- LAST_SEEN = "last_seen"
46
+ DOMAIN = auto()
47
+ ONLINE = auto()
48
+ LAST_SEEN = auto()
49
49
 
50
- def __str__(self):
51
- return self.value
52
50
 
53
-
54
- class DeactivationReason(Enum):
55
- DELETED = "deleted"
56
- BANNED = "banned"
57
-
58
- def __str__(self):
59
- return self.value
51
+ class DeactivationReason(StrEnum):
52
+ DELETED = auto()
53
+ BANNED = auto()
60
54
 
61
55
 
62
56
  def _parse_deactivated(s):
@@ -3,6 +3,9 @@
3
3
  # For details, see https://github.com/egor-tensin/vk-scripts
4
4
  # Distributed under the MIT License.
5
5
 
6
+ import argparse
7
+ import sys
8
+
6
9
  import matplotlib.pyplot as plt
7
10
  from matplotlib import ticker
8
11
  import numpy as np
@@ -131,30 +134,46 @@ class BarChartBuilder:
131
134
  self._fig.savefig(path, bbox_inches="tight")
132
135
 
133
136
 
134
- if __name__ == "__main__":
135
- import argparse
137
+ def _parse_args(argv=None):
138
+ if argv is None:
139
+ argv = sys.argv[1:]
136
140
 
137
141
  parser = argparse.ArgumentParser()
138
142
 
139
- parser.add_argument("--categories", nargs="*", metavar="LABEL", default=[])
140
- parser.add_argument("--values", nargs="*", metavar="N", default=[], type=float)
141
-
142
- parser.add_argument("--output", "-o", help="set output file path")
143
-
143
+ parser.add_argument(
144
+ "--categories",
145
+ nargs="*",
146
+ metavar="LABEL",
147
+ default=[],
148
+ )
149
+ parser.add_argument(
150
+ "--values",
151
+ nargs="*",
152
+ metavar="N",
153
+ default=[],
154
+ type=float,
155
+ )
156
+ parser.add_argument(
157
+ "--output",
158
+ "-o",
159
+ help="set output file path",
160
+ )
144
161
  parser.add_argument(
145
162
  "--align-middle",
146
163
  action="store_true",
147
164
  dest="labels_align_middle",
148
165
  help="align labels to the middle of the bars",
149
166
  )
150
-
151
167
  parser.add_argument(
152
- "--integer-values", action="store_true", dest="only_integer_values"
168
+ "--integer-values",
169
+ action="store_true",
170
+ dest="only_integer_values",
153
171
  )
154
172
  parser.add_argument(
155
- "--any-values", action="store_false", dest="only_integer_values"
173
+ "--any-values",
174
+ action="store_false",
175
+ dest="only_integer_values",
156
176
  )
157
-
158
177
  parser.add_argument("--grid-categories", action="store_true")
159
178
  parser.add_argument("--grid-values", action="store_true")
160
179
 
@@ -165,6 +184,11 @@ if __name__ == "__main__":
165
184
  if len(args.categories) > len(args.values):
166
185
  args.values.extend([0.0] * (len(args.categories) - len(args.values)))
167
186
 
187
+ return args
188
+
189
+
190
+ def _main(argv=None):
191
+ args = _parse_args(argv)
168
192
  builder = BarChartBuilder(labels_align_middle=args.labels_align_middle)
169
193
 
170
194
  if args.only_integer_values:
@@ -183,3 +207,7 @@ if __name__ == "__main__":
183
207
  builder.show()
184
208
  else:
185
209
  builder.save(args.output)
210
+
211
+
212
+ if __name__ == "__main__":
213
+ _main()
@@ -12,5 +12,8 @@ except Exception:
12
12
 
13
13
  def add_to_arg_parser(parser):
14
14
  parser.add_argument(
15
- "--version", "-V", action="version", version=f"%(prog)s {__version__}"
15
+ "--version",
16
+ "-V",
17
+ action="version",
18
+ version=f"%(prog)s {__version__}",
16
19
  )
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vk_scripts
3
- Version: 1.2.0
3
+ Version: 1.3.1
4
4
  Summary: Scripts to stalk people on VK
5
5
  Author-email: Egor Tensin <egor@tensin.name>
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/egor-tensin/vk-scripts
8
8
  Project-URL: Bug Tracker, https://github.com/egor-tensin/vk-scripts/issues
9
9
  Classifier: Development Status :: 5 - Production/Stable
10
- Requires-Python: >=3.6
10
+ Requires-Python: >=3.11
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE.txt
13
13
  Requires-Dist: importlib-metadata~=4.0; python_version < "3.8"
@@ -42,25 +42,6 @@ with.
42
42
  [vk-status]: docs/status.md
43
43
  [vk-sessions]: docs/sessions.md
44
44
 
45
- Development
46
- -----------
47
-
48
- ### Linting
49
-
50
- Requires [Pylint].
51
-
52
- pylint vk
53
-
54
- [Pylint]: https://www.pylint.org/
55
-
56
- ### Releases
57
-
58
- Make a git tag:
59
-
60
- git tag "v$( python -m setuptools_scm --strip-dev )"
61
-
62
- You can then review that the tag is fine and push w/ `git push --tags`.
63
-
64
45
  License
65
46
  -------
66
47
 
@@ -1,7 +1,6 @@
1
1
  .git-blame-ignore-revs
2
2
  .gitattributes
3
3
  .gitignore
4
- .pylintrc
5
4
  LICENSE.txt
6
5
  README.md
7
6
  pyproject.toml
@@ -5,7 +5,6 @@
5
5
  ".github/dependabot.yml",
6
6
  ".github/workflows/ci.yml",
7
7
  ".gitignore",
8
- ".pylintrc",
9
8
  "LICENSE.txt",
10
9
  "README.md",
11
10
  "docs/images/date.png",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "1.3.1",
3
+ "distance": 0,
4
+ "node": "ga1687194ed78d3c98b589e94553c3d9ef68f4ecf",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-12"
8
+ }
@@ -1,8 +0,0 @@
1
- [MESSAGES CONTROL]
2
-
3
- disable=
4
- invalid-name,
5
- missing-docstring,
6
- multiple-imports,
7
- too-few-public-methods,
8
- too-many-public-methods,
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "1.2.0",
3
- "distance": 0,
4
- "node": "geec673b5c0122e359bf00b0136783a32e8a77df9",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-09-29"
8
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes