vk-scripts 1.1.1__tar.gz → 1.3.0__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.
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/.github/workflows/ci.yml +34 -10
- {vk_scripts-1.1.1/vk_scripts.egg-info → vk_scripts-1.3.0}/PKG-INFO +2 -2
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/pyproject.toml +7 -1
- vk_scripts-1.3.0/test/lib/log.sh +139 -0
- vk_scripts-1.3.0/test/lib/test.sh +26 -0
- vk_scripts-1.3.0/test/main.sh +77 -0
- vk_scripts-1.3.0/test/tst-mutuals.sh +38 -0
- vk_scripts-1.3.0/test/tst-sessions.sh +43 -0
- vk_scripts-1.3.0/test/tst-status-once.sh +25 -0
- vk_scripts-1.3.0/test/tst-status.sh +45 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/api.py +7 -19
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/error.py +1 -1
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/last_seen.py +5 -8
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/mutuals.py +9 -9
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/platform.py +3 -6
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/db/__init__.py +1 -1
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/db/backend/__init__.py +1 -1
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/db/backend/csv.py +1 -1
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/db/backend/log.py +1 -1
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/db/backend/null.py +1 -1
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/db/format.py +6 -9
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/db/meta.py +1 -1
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/db/record.py +1 -1
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/db/timestamp.py +1 -1
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/sessions.py +18 -24
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/status.py +10 -3
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/user.py +13 -19
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/utils/bar_chart.py +40 -12
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/utils/io.py +1 -1
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/version.py +4 -1
- {vk_scripts-1.1.1 → vk_scripts-1.3.0/vk_scripts.egg-info}/PKG-INFO +2 -2
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk_scripts.egg-info/SOURCES.txt +7 -7
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk_scripts.egg-info/scm_file_list.json +30 -30
- vk_scripts-1.3.0/vk_scripts.egg-info/scm_version.json +8 -0
- vk_scripts-1.1.1/.pylintrc +0 -8
- vk_scripts-1.1.1/test/bin/main.sh +0 -19
- vk_scripts-1.1.1/test/bin/mutuals.sh +0 -23
- vk_scripts-1.1.1/test/bin/sessions.sh +0 -69
- vk_scripts-1.1.1/test/bin/status.sh +0 -60
- vk_scripts-1.1.1/test/bin/status_once.sh +0 -22
- vk_scripts-1.1.1/test/lib/test.sh +0 -27
- vk_scripts-1.1.1/vk_scripts.egg-info/scm_version.json +0 -8
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/.git-blame-ignore-revs +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/.gitattributes +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/.github/dependabot.yml +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/.gitignore +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/LICENSE.txt +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/README.md +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/docs/images/date.png +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/docs/images/hour.png +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/docs/images/user.png +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/docs/images/weekday.png +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/docs/mutuals.md +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/docs/sessions.md +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/docs/status.md +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/setup.cfg +0 -0
- {vk_scripts-1.1.1/test/share → vk_scripts-1.3.0/test/data}/test_db.csv +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/__init__.py +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/tracking/__init__.py +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk/utils/__init__.py +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk_scripts.egg-info/dependency_links.txt +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk_scripts.egg-info/entry_points.txt +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/vk_scripts.egg-info/requires.txt +0 -0
- {vk_scripts-1.1.1 → vk_scripts-1.3.0}/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
|
-
|
|
32
|
+
test_python:
|
|
35
33
|
strategy:
|
|
36
34
|
matrix:
|
|
37
|
-
python-version:
|
|
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:
|
|
@@ -56,17 +56,41 @@ jobs:
|
|
|
56
56
|
vk-status --version
|
|
57
57
|
vk-sessions --version
|
|
58
58
|
- name: Run tests
|
|
59
|
-
run: ./test/
|
|
59
|
+
run: ./test/main.sh
|
|
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
|
|
60
83
|
|
|
61
84
|
publish_pypi:
|
|
62
|
-
needs:
|
|
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.
|
|
3
|
+
Version: 1.3.0
|
|
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.
|
|
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"
|
|
@@ -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.
|
|
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
|
+
]
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Copyright (c) 2026 Egor Tensin <egor@tensin.name>
|
|
2
|
+
# This file is part of the "VK scripts" project.
|
|
3
|
+
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
4
|
+
# Distributed under the MIT License.
|
|
5
|
+
|
|
6
|
+
log() {
|
|
7
|
+
local msg
|
|
8
|
+
for msg; do
|
|
9
|
+
echo -e "$test_file | $msg" >&2
|
|
10
|
+
done
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
log_run() {
|
|
14
|
+
if [ "$#" -lt 1 ]; then
|
|
15
|
+
log "usage: ${FUNCNAME[0]} ARGV0 [ARG...]"
|
|
16
|
+
return 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
local msg='Running:'
|
|
20
|
+
msg="$msg$( printf -- ' %q' "$@" )"
|
|
21
|
+
log "$msg"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
fail() {
|
|
25
|
+
local msg
|
|
26
|
+
for msg; do
|
|
27
|
+
log "FAIL: $msg"
|
|
28
|
+
done
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
fail_details() {
|
|
32
|
+
local msg
|
|
33
|
+
for msg; do
|
|
34
|
+
fail " $msg"
|
|
35
|
+
done
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
log_numof_tests_ok=0
|
|
39
|
+
log_numof_tests_failed=0
|
|
40
|
+
declare -a log_tests_failed=()
|
|
41
|
+
declare -A log_tests_should_fail=()
|
|
42
|
+
|
|
43
|
+
log_test_start() {
|
|
44
|
+
if [ "$#" -ne 1 ]; then
|
|
45
|
+
echo "usage: ${FUNCNAME[0]} TEST_FILE" >&2
|
|
46
|
+
return 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
local test_file="$1"
|
|
50
|
+
|
|
51
|
+
if [ -n "${test_should_fail:-}" ]; then
|
|
52
|
+
log_tests_should_fail["$test_file"]=1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
cat <<EOF >&2
|
|
56
|
+
|
|
57
|
+
======================================================================
|
|
58
|
+
TEST: $test_file
|
|
59
|
+
======================================================================
|
|
60
|
+
EOF
|
|
61
|
+
|
|
62
|
+
log "Should fail: ${test_should_fail:-No}"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
log_test_ok() {
|
|
66
|
+
if [ "$#" -ne 1 ]; then
|
|
67
|
+
echo "usage: ${FUNCNAME[0]} TEST_FILE" >&2
|
|
68
|
+
return 1
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
log_numof_tests_ok=$((log_numof_tests_ok + 1))
|
|
72
|
+
|
|
73
|
+
cat <<EOF >&2
|
|
74
|
+
----------------------------------------------------------------------
|
|
75
|
+
OK: $1
|
|
76
|
+
----------------------------------------------------------------------
|
|
77
|
+
EOF
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
log_test_fail() {
|
|
81
|
+
if [ "$#" -ne 1 ]; then
|
|
82
|
+
echo "usage: ${FUNCNAME[0]} TEST_FILE" >&2
|
|
83
|
+
return 1
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
log_numof_tests_failed=$((log_numof_tests_failed + 1))
|
|
87
|
+
log_tests_failed+=("$1")
|
|
88
|
+
|
|
89
|
+
cat <<EOF >&2
|
|
90
|
+
----------------------------------------------------------------------
|
|
91
|
+
FAIL: $1
|
|
92
|
+
----------------------------------------------------------------------
|
|
93
|
+
EOF
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
log_test_finish() {
|
|
97
|
+
if [ "$#" -ne 2 ]; then
|
|
98
|
+
echo "usage: ${FUNCNAME[0]} TEST_FILE EXIT_CODE" >&2
|
|
99
|
+
return 1
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
local test_file="$1"
|
|
103
|
+
local ret="$2"
|
|
104
|
+
local test_should_fail
|
|
105
|
+
test_should_fail="${log_tests_should_fail["$test_file"]:+x}"
|
|
106
|
+
|
|
107
|
+
if [ "$ret" -eq 0 ] || [ -n "$test_should_fail" ]; then
|
|
108
|
+
log_test_ok "$test_file"
|
|
109
|
+
else
|
|
110
|
+
log_test_fail "$test_file"
|
|
111
|
+
fi
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
log_tests_summary() {
|
|
115
|
+
cat <<EOF >&2
|
|
116
|
+
|
|
117
|
+
======================================================================
|
|
118
|
+
SUMMARY
|
|
119
|
+
======================================================================
|
|
120
|
+
OK: $log_numof_tests_ok
|
|
121
|
+
FAIL: $log_numof_tests_failed
|
|
122
|
+
EOF
|
|
123
|
+
|
|
124
|
+
local test_file
|
|
125
|
+
for test_file in ${log_tests_failed[@]+"${log_tests_failed[@]}"}; do
|
|
126
|
+
cat <<EOF >&2
|
|
127
|
+
FAIL: $test_file
|
|
128
|
+
EOF
|
|
129
|
+
done
|
|
130
|
+
|
|
131
|
+
cat <<EOF >&2
|
|
132
|
+
----------------------------------------------------------------------
|
|
133
|
+
EOF
|
|
134
|
+
|
|
135
|
+
local ret=0
|
|
136
|
+
[ "$log_numof_tests_failed" -gt 0 ] && ret=1
|
|
137
|
+
|
|
138
|
+
return "$ret"
|
|
139
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Copyright (c) 2020 Egor Tensin <egor@tensin.name>
|
|
2
|
+
# This file is part of the "VK scripts" project.
|
|
3
|
+
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
4
|
+
# Distributed under the MIT License.
|
|
5
|
+
|
|
6
|
+
test_should_fail=
|
|
7
|
+
test_root_dir=
|
|
8
|
+
|
|
9
|
+
test_setup() {
|
|
10
|
+
test_root_dir="$( mktemp -d )"
|
|
11
|
+
|
|
12
|
+
log "Root directory: $test_root_dir"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
test_cleanup_default() {
|
|
16
|
+
if [ -n "$test_root_dir" ]; then
|
|
17
|
+
log "Removing test's root directory: $test_root_dir"
|
|
18
|
+
rm -rf -- "$test_root_dir"
|
|
19
|
+
fi
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
test_run_module() {
|
|
23
|
+
local cmd=(python3 -m "$@")
|
|
24
|
+
log_run "${cmd[@]}"
|
|
25
|
+
PYTHONPATH="$script_dir/.." "${cmd[@]}"
|
|
26
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2026 Egor Tensin <egor@tensin.name>
|
|
4
|
+
# This file is part of the "VK scripts" project.
|
|
5
|
+
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
6
|
+
# Distributed under the MIT License.
|
|
7
|
+
|
|
8
|
+
set -o errexit -o nounset -o pipefail
|
|
9
|
+
shopt -s inherit_errexit lastpipe
|
|
10
|
+
|
|
11
|
+
script_dir="$( dirname -- "${BASH_SOURCE[0]}" )"
|
|
12
|
+
script_dir="$( cd -- "$script_dir" && pwd )"
|
|
13
|
+
readonly script_dir
|
|
14
|
+
script_name="$( basename -- "${BASH_SOURCE[0]}" )"
|
|
15
|
+
readonly script_name
|
|
16
|
+
|
|
17
|
+
source "$script_dir/lib/log.sh"
|
|
18
|
+
|
|
19
|
+
run_test_file() {
|
|
20
|
+
local test_file
|
|
21
|
+
for test_file; do
|
|
22
|
+
source "$script_dir/lib/test.sh"
|
|
23
|
+
source "$script_dir/$test_file"
|
|
24
|
+
|
|
25
|
+
log_test_start "$test_file"
|
|
26
|
+
|
|
27
|
+
set +e
|
|
28
|
+
(
|
|
29
|
+
set -o errexit -o nounset -o pipefail
|
|
30
|
+
shopt -s inherit_errexit lastpipe
|
|
31
|
+
|
|
32
|
+
if [ "$( type -t test_cleanup )" == function ]; then
|
|
33
|
+
trap test_cleanup EXIT
|
|
34
|
+
else
|
|
35
|
+
trap test_cleanup_default EXIT
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
test_run
|
|
39
|
+
)
|
|
40
|
+
local ret="$?"
|
|
41
|
+
set -e
|
|
42
|
+
|
|
43
|
+
log_test_finish "$test_file" "$ret"
|
|
44
|
+
done
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
main() {
|
|
48
|
+
if [ "$#" -gt 1 ]; then
|
|
49
|
+
echo "usage: $script_name [PATTERN]" >&2
|
|
50
|
+
return 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
local -a test_files=()
|
|
54
|
+
local test_file
|
|
55
|
+
|
|
56
|
+
local pattern='*'
|
|
57
|
+
[ "$#" -gt 0 ] && pattern="$1"
|
|
58
|
+
|
|
59
|
+
find "$script_dir" \
|
|
60
|
+
-mindepth 1 \
|
|
61
|
+
-maxdepth 1 \
|
|
62
|
+
-type f \
|
|
63
|
+
-regex '.*/tst-.*\.sh$' \
|
|
64
|
+
-regextype posix-basic \
|
|
65
|
+
-name "$pattern" \
|
|
66
|
+
-printf '%P\0' \
|
|
67
|
+
| sort -z \
|
|
68
|
+
| \
|
|
69
|
+
while IFS= read -d '' -r test_file; do
|
|
70
|
+
test_files+=("$test_file")
|
|
71
|
+
done
|
|
72
|
+
|
|
73
|
+
run_test_file ${test_files[@]+"${test_files[@]}"}
|
|
74
|
+
log_tests_summary
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
main "$@"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
test_run() {
|
|
2
|
+
test_setup
|
|
3
|
+
|
|
4
|
+
local users=(kreed58 korya_mc)
|
|
5
|
+
|
|
6
|
+
test_run_module vk.mutuals --format csv "${users[@]}" > "$test_root_dir/mutuals.csv"
|
|
7
|
+
test_run_module vk.mutuals --format json "${users[@]}" > "$test_root_dir/mutuals.json"
|
|
8
|
+
|
|
9
|
+
local expected=10
|
|
10
|
+
|
|
11
|
+
local actual_csv
|
|
12
|
+
actual_csv="$( cat -- "$test_root_dir/mutuals.csv" | wc -l )"
|
|
13
|
+
log "Mutuals in CSV: $actual_csv"
|
|
14
|
+
|
|
15
|
+
if [ "$actual_csv" -lt "$expected" ]; then
|
|
16
|
+
fail "Expected a lot more mutual friends in CSV output"
|
|
17
|
+
fail_details "Expected: $expected"
|
|
18
|
+
fail_details "Actual: $actual_csv"
|
|
19
|
+
return 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
local actual_json
|
|
23
|
+
actual_json="$( grep -F -- '"id":' "$test_root_dir/mutuals.json" | wc -l )"
|
|
24
|
+
log "Mutuals in JSON: $actual_json"
|
|
25
|
+
|
|
26
|
+
if [ "$actual_json" -lt "$expected" ]; then
|
|
27
|
+
fail "Expected a lot more mutual friends in JSON output"
|
|
28
|
+
fail_details "Expected: $expected"
|
|
29
|
+
fail_details "Actual: $actual_json"
|
|
30
|
+
return 1
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
if [ "$actual_csv" -ne "$actual_json" ]; then
|
|
34
|
+
fail "Number of mutuals in CSV unequal to that in JSON"
|
|
35
|
+
fail_details "Can technically happen, because it's kind of a race"
|
|
36
|
+
return 1
|
|
37
|
+
fi
|
|
38
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
test_db_path="$script_dir/data/test_db.csv"
|
|
2
|
+
readonly test_db_path
|
|
3
|
+
|
|
4
|
+
_test_format() {
|
|
5
|
+
local output_path
|
|
6
|
+
output_path="$( mktemp --tmpdir="$test_root_dir" )"
|
|
7
|
+
|
|
8
|
+
test_run_module vk.tracking.sessions "$@" "$test_db_path" "$output_path"
|
|
9
|
+
|
|
10
|
+
if [ ! -s "$output_path" ]; then
|
|
11
|
+
fail "Output file '$output_path' either doesn't exists or is empty"
|
|
12
|
+
return 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
if file --brief --dereference --mime -- "$output_path" | grep --quiet -- 'charset=binary$'; then
|
|
16
|
+
log 'Output is a binary file, not going to show that'
|
|
17
|
+
return 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
cat -- "$output_path" >&2
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
_test_group_by() {
|
|
24
|
+
local group_by
|
|
25
|
+
for group_by; do
|
|
26
|
+
local format
|
|
27
|
+
for format in csv json plot; do
|
|
28
|
+
_test_format --output-format "$format" --group-by "$group_by"
|
|
29
|
+
done
|
|
30
|
+
done
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_test_main() {
|
|
34
|
+
_test_group_by user
|
|
35
|
+
_test_group_by hour
|
|
36
|
+
_test_group_by date
|
|
37
|
+
_test_group_by weekday
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
test_run() {
|
|
41
|
+
test_setup
|
|
42
|
+
_test_main
|
|
43
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
test_run() {
|
|
2
|
+
test_setup
|
|
3
|
+
|
|
4
|
+
local users=(egor.tensin kreed58)
|
|
5
|
+
local db_path
|
|
6
|
+
db_path="$test_root_dir/db.csv"
|
|
7
|
+
|
|
8
|
+
test_run_module vk.tracking.status --only-once -o "$db_path" "${users[@]}"
|
|
9
|
+
|
|
10
|
+
if [ ! -s "$db_path" ]; then
|
|
11
|
+
fail "Database file '$db_path' either doesn't exists or is empty"
|
|
12
|
+
return 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
log "Database:"
|
|
16
|
+
cat -- "$db_path" >&2
|
|
17
|
+
|
|
18
|
+
local lines
|
|
19
|
+
lines="$( cat -- "$db_path" | wc -l )"
|
|
20
|
+
|
|
21
|
+
if [ "$lines" -ne 2 ]; then
|
|
22
|
+
fail "Database '$db_path' has the wrong number of entries"
|
|
23
|
+
return 1
|
|
24
|
+
fi
|
|
25
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
test_run() {
|
|
2
|
+
test_setup
|
|
3
|
+
|
|
4
|
+
local users=(egor.tensin)
|
|
5
|
+
|
|
6
|
+
local log_path
|
|
7
|
+
log_path="$test_root_dir/status.log"
|
|
8
|
+
local db_path
|
|
9
|
+
db_path="$test_root_dir/status.csv"
|
|
10
|
+
|
|
11
|
+
test_run_module vk.tracking.status \
|
|
12
|
+
--log "$log_path" \
|
|
13
|
+
--format csv \
|
|
14
|
+
--output "$db_path" \
|
|
15
|
+
"${users[@]}" &
|
|
16
|
+
local pid="$!"
|
|
17
|
+
|
|
18
|
+
sleep 3
|
|
19
|
+
log "Log file: $log_path"
|
|
20
|
+
log "Database file: $db_path"
|
|
21
|
+
log "PID: $pid"
|
|
22
|
+
|
|
23
|
+
local timeout=10
|
|
24
|
+
log "Sleeping for $timeout seconds..."
|
|
25
|
+
sleep "$timeout"
|
|
26
|
+
|
|
27
|
+
log 'Terminating track_status.py...'
|
|
28
|
+
kill "$pid"
|
|
29
|
+
log 'Waiting for track_status.py to terminate...'
|
|
30
|
+
wait "$pid" || true
|
|
31
|
+
|
|
32
|
+
if [ ! -s "$log_path" ]; then
|
|
33
|
+
fail "Log file '$log_path' either doesn't exists or is empty"
|
|
34
|
+
return 1
|
|
35
|
+
fi
|
|
36
|
+
log 'Log file:'
|
|
37
|
+
cat -- "$log_path" >&2
|
|
38
|
+
|
|
39
|
+
if [ ! -s "$db_path" ]; then
|
|
40
|
+
fail "Database file '$db_path' either doesn't exists or is empty"
|
|
41
|
+
return 1
|
|
42
|
+
fi
|
|
43
|
+
log 'Database:'
|
|
44
|
+
cat -- "$db_path" >&2
|
|
45
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Copyright (c) 2015 Egor Tensin <egor@tensin.name>
|
|
2
2
|
# This file is part of the "VK scripts" project.
|
|
3
|
-
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
3
|
+
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
4
4
|
# Distributed under the MIT License.
|
|
5
5
|
|
|
6
6
|
from collections.abc import Iterable, Mapping
|
|
7
|
-
from enum import
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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/"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Copyright (c) 2016 Egor Tensin <egor@tensin.name>
|
|
2
2
|
# This file is part of the "VK scripts" project.
|
|
3
|
-
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
3
|
+
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
4
4
|
# Distributed under the MIT License.
|
|
5
5
|
|
|
6
6
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Copyright (c) 2016 Egor Tensin <egor@tensin.name>
|
|
2
2
|
# This file is part of the "VK scripts" project.
|
|
3
|
-
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
3
|
+
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
4
4
|
# Distributed under the MIT License.
|
|
5
5
|
|
|
6
6
|
from collections import OrderedDict
|
|
7
7
|
from collections.abc import MutableMapping
|
|
8
8
|
from datetime import datetime, timezone
|
|
9
|
-
from enum import
|
|
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(
|
|
34
|
-
TIME =
|
|
35
|
-
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):
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Copyright (c) 2015 Egor Tensin <egor@tensin.name>
|
|
2
2
|
# This file is part of the "VK scripts" project.
|
|
3
|
-
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
3
|
+
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
4
4
|
# Distributed under the MIT License.
|
|
5
5
|
|
|
6
6
|
import abc
|
|
7
7
|
import argparse
|
|
8
8
|
from collections import OrderedDict
|
|
9
|
-
from enum import
|
|
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(
|
|
60
|
-
CSV =
|
|
61
|
-
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",
|
|
93
|
+
"uids",
|
|
94
|
+
metavar="UID",
|
|
95
|
+
nargs="+",
|
|
96
|
+
help='user IDs or "screen names"',
|
|
97
97
|
)
|
|
98
98
|
parser.add_argument(
|
|
99
99
|
"-f",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Copyright (c) 2016 Egor Tensin <egor@tensin.name>
|
|
2
2
|
# This file is part of the "VK scripts" project.
|
|
3
|
-
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
3
|
+
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
4
4
|
# Distributed under the MIT License.
|
|
5
5
|
|
|
6
|
-
from enum import
|
|
6
|
+
from enum import IntEnum
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class Platform(
|
|
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]}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Copyright (c) 2016 Egor Tensin <egor@tensin.name>
|
|
2
2
|
# This file is part of the "VK scripts" project.
|
|
3
|
-
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
3
|
+
# For details, see https://github.com/egor-tensin/vk-scripts
|
|
4
4
|
# Distributed under the MIT License.
|
|
5
5
|
|
|
6
6
|
from .format import Format
|