Compare commits

...

270 Commits
v0.7 ... v4.0.0

Author SHA1 Message Date
a38b55d270 Merge pull request 'v4.0.0' (#169) from dev into main
Some checks failed
Analysis / SonarCloud (push) Successful in 42s
Tests / Build and Test (3.10) (push) Failing after 57s
Tests / Build and Test (3.11) (push) Successful in 1m4s
Tests / Build and Test (3.12) (push) Successful in 1m13s
Tests / Build and Test (3.9) (push) Failing after 57s
Reviewed-on: #169
2024-12-26 19:59:34 +02:00
a13ef83e82 Merge pull request '4.0.0' (#168) from overhaul-v4 into dev
Some checks failed
Analysis / SonarCloud (push) Successful in 40s
Analysis / SonarCloud (pull_request) Successful in 52s
Tests / Build and Test (3.10) (pull_request) Failing after 58s
Tests / Build and Test (3.11) (pull_request) Successful in 1m5s
Tests / Build and Test (3.12) (pull_request) Successful in 1m16s
Tests / Build and Test (3.9) (pull_request) Failing after 58s
Reviewed-on: #168
2024-12-26 19:44:56 +02:00
0ce4ddcf7c Fixed two broken references
Some checks failed
Analysis / SonarCloud (pull_request) Successful in 42s
Tests / Build and Test (3.10) (pull_request) Failing after 57s
Tests / Build and Test (3.11) (pull_request) Successful in 1m2s
Tests / Build and Test (3.12) (pull_request) Successful in 1m11s
Tests / Build and Test (3.9) (pull_request) Has been cancelled
2024-12-26 18:37:55 +01:00
aa2c778a6a Removed legacy usage of Union[] 2024-12-26 18:36:57 +01:00
a47a508ecf Update dependency pylint to v3.3.3
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 34s
Tests / Build and Test (3.10) (pull_request) Successful in 1m2s
Tests / Build and Test (3.11) (pull_request) Successful in 1m1s
Tests / Build and Test (3.12) (pull_request) Successful in 1m14s
Tests / Build and Test (3.9) (pull_request) Successful in 1m3s
Analysis / SonarCloud (push) Successful in 39s
2024-12-24 05:27:30 +02:00
bdd649bdbe Update dependency types-aiofiles to v24.1.0.20241221
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 38s
Tests / Build and Test (3.10) (pull_request) Successful in 1m4s
Tests / Build and Test (3.11) (pull_request) Successful in 1m2s
Tests / Build and Test (3.12) (pull_request) Successful in 1m9s
Tests / Build and Test (3.9) (pull_request) Successful in 1m6s
Analysis / SonarCloud (push) Successful in 44s
2024-12-21 05:18:48 +02:00
e6d9beec81 Update dependency mypy to v1.14.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 35s
Tests / Build and Test (3.10) (pull_request) Successful in 3m26s
Tests / Build and Test (3.11) (pull_request) Successful in 1m15s
Tests / Build and Test (3.12) (pull_request) Successful in 1m7s
Tests / Build and Test (3.9) (pull_request) Successful in 1m5s
Analysis / SonarCloud (push) Successful in 46s
2024-12-20 17:47:59 +02:00
kku
95d04308bd WIP: Overhaul for 4.0.0 2024-12-18 14:16:37 +01:00
kku
5e479ddc79 Closes #161
All checks were successful
Analysis / SonarCloud (push) Successful in 48s
2024-12-18 13:53:09 +01:00
9907cc50f1 Merge pull request 'v3.3.1' (#160) from dev into main
All checks were successful
Analysis / SonarCloud (push) Successful in 46s
Tests / Build and Test (3.10) (push) Successful in 1m3s
Tests / Build and Test (3.11) (push) Successful in 1m1s
Tests / Build and Test (3.12) (push) Successful in 1m8s
Tests / Build and Test (3.9) (push) Successful in 1m3s
Reviewed-on: #160
2024-12-16 23:57:08 +02:00
40827e70a1 Bump version to fix metadata
All checks were successful
Analysis / SonarCloud (push) Successful in 42s
Analysis / SonarCloud (pull_request) Successful in 38s
Tests / Build and Test (3.10) (pull_request) Successful in 1m4s
Tests / Build and Test (3.11) (pull_request) Successful in 1m2s
Tests / Build and Test (3.12) (pull_request) Successful in 1m13s
Tests / Build and Test (3.9) (pull_request) Successful in 1m8s
2024-12-16 22:54:41 +01:00
1b60257bc5 Merge pull request 'v3.3.0' (#159) from dev into main
All checks were successful
Analysis / SonarCloud (push) Successful in 43s
Tests / Build and Test (3.10) (push) Successful in 1m2s
Tests / Build and Test (3.11) (push) Successful in 1m2s
Tests / Build and Test (3.12) (push) Successful in 1m8s
Tests / Build and Test (3.9) (push) Successful in 1m4s
Reviewed-on: #159
2024-12-16 23:48:07 +02:00
7e03a0c779 Update dependency pytest-asyncio to v0.25.0
All checks were successful
Analysis / SonarCloud (push) Successful in 48s
Analysis / SonarCloud (pull_request) Successful in 46s
Tests / Build and Test (3.10) (pull_request) Successful in 1m6s
Tests / Build and Test (3.11) (pull_request) Successful in 1m2s
Tests / Build and Test (3.12) (pull_request) Successful in 1m10s
Tests / Build and Test (3.9) (pull_request) Successful in 1m6s
2024-12-13 08:58:25 +02:00
5f4d0b09f9 Update dependency pylint to v3.3.2
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 35s
Tests / Build and Test (3.10) (pull_request) Successful in 1m4s
Tests / Build and Test (3.11) (pull_request) Successful in 1m6s
Tests / Build and Test (3.12) (pull_request) Successful in 1m13s
Tests / Build and Test (3.9) (pull_request) Successful in 1m5s
Analysis / SonarCloud (push) Successful in 40s
2024-12-01 21:32:47 +02:00
f6596d1db6 Update dependency pytest to v8.3.4
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 38s
Tests / Build and Test (3.10) (pull_request) Successful in 1m2s
Tests / Build and Test (3.11) (pull_request) Successful in 1m1s
Tests / Build and Test (3.12) (pull_request) Successful in 1m11s
Tests / Build and Test (3.9) (pull_request) Successful in 1m5s
Analysis / SonarCloud (push) Successful in 41s
2024-12-01 15:17:19 +02:00
cbc4fc36a1 Update dependency apscheduler to ~=3.11.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 57s
Tests / Build and Test (3.10) (pull_request) Successful in 1m11s
Tests / Build and Test (3.11) (pull_request) Successful in 1m11s
Tests / Build and Test (3.12) (pull_request) Successful in 1m16s
Tests / Build and Test (3.9) (pull_request) Successful in 1m10s
Analysis / SonarCloud (push) Successful in 47s
2024-11-24 21:56:08 +02:00
d20d07bb6a Fixed a few things mentioned in SonarCloud
All checks were successful
Analysis / SonarCloud (push) Successful in 40s
2024-10-29 23:19:52 +01:00
4ee704b41e Merge pull request 'Removed explicit action host' (#154) from profitroll/actions-fix into dev
All checks were successful
Analysis / SonarCloud (push) Successful in 40s
Reviewed-on: #154
2024-10-29 23:57:43 +02:00
02cfc42f60 Separated SonarCloud from normal tests
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 40s
Tests / Build and Test (3.10) (pull_request) Successful in 1m4s
Tests / Build and Test (3.11) (pull_request) Successful in 1m2s
Tests / Build and Test (3.12) (pull_request) Successful in 1m8s
Tests / Build and Test (3.9) (pull_request) Successful in 1m8s
2024-10-29 22:55:01 +01:00
2757bd6b72 Removed explicit action host
All checks were successful
Tests / Build and Test (3.10) (pull_request) Successful in 1m4s
Tests / Build and Test (3.11) (pull_request) Successful in 1m1s
Tests / Build and Test (3.12) (pull_request) Successful in 1m7s
Tests / Build and Test (3.9) (pull_request) Successful in 1m4s
Tests / SonarCloud (pull_request) Successful in 37s
2024-10-29 23:42:07 +02:00
fe71860faa Merge pull request 'Test PR' (#152) from profitroll/python-3.12 into dev
Reviewed-on: #152
2024-10-29 23:40:19 +02:00
8fc5a18fab Merge pull request 'Update dependency pytest-cov to v6' (#153) from renovate/pytest-cov-6.x into dev
Reviewed-on: #153
2024-10-29 23:40:10 +02:00
54d98df7b7 Fixed Gitea Act container 2024-10-29 23:39:57 +02:00
c9e4b3b916 Update dependency pytest-cov to v6
Some checks failed
Tests / Build and Test (3.10) (pull_request) Successful in 1m6s
Tests / Build and Test (3.11) (pull_request) Successful in 1m4s
Tests / Build and Test (3.12) (pull_request) Successful in 1m15s
Tests / Build and Test (3.9) (pull_request) Successful in 1m4s
Tests / SonarCloud (pull_request) Failing after 0s
2024-10-29 22:25:05 +02:00
acb77049d1 Changed the sonarcloud action link
Some checks failed
Tests / Build and Test (3.10) (pull_request) Successful in 1m7s
Tests / Build and Test (3.11) (pull_request) Successful in 1m2s
Tests / Build and Test (3.12) (pull_request) Successful in 1m9s
Tests / Build and Test (3.9) (pull_request) Successful in 1m3s
Tests / SonarCloud (pull_request) Failing after 0s
2024-10-29 17:55:02 +02:00
d41eb742e5 Add sonar-project.properties
Some checks failed
Tests / Build and Test (3.10) (pull_request) Successful in 1m13s
Tests / Build and Test (3.11) (pull_request) Successful in 1m5s
Tests / Build and Test (3.12) (pull_request) Successful in 1m11s
Tests / Build and Test (3.9) (pull_request) Successful in 1m8s
Tests / SonarCloud (pull_request) Failing after 0s
2024-10-29 17:38:41 +02:00
377ba928ba Added sonarcloud job 2024-10-29 17:37:16 +02:00
b9ae1c2149 Merge pull request 'Update dependency mypy to v1.13.0' (#151) from renovate/mypy-1.x into dev
Reviewed-on: #151
2024-10-23 02:12:25 +03:00
c670521bb2 Update dependency mypy to v1.13.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m3s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.12) (pull_request) Successful in 1m8s
Tests / test (3.9) (pull_request) Successful in 1m4s
2024-10-23 01:28:30 +03:00
c175b4634c Update dependency tox to v4.23.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.12) (pull_request) Successful in 1m10s
Tests / test (3.9) (pull_request) Successful in 1m6s
2024-10-22 18:11:45 +03:00
54feb5ff5b Update dependency tox to v4.23.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.12) (pull_request) Successful in 1m9s
Tests / test (3.9) (pull_request) Successful in 1m4s
2024-10-22 08:50:37 +03:00
1d32c5e1c3 Update dependency mypy to v1.12.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.12) (pull_request) Successful in 1m9s
Tests / test (3.9) (pull_request) Successful in 1m5s
2024-10-20 04:00:40 +03:00
eeaa71606b Update dependency tox to v4.23.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m3s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.12) (pull_request) Successful in 1m9s
Tests / test (3.9) (pull_request) Successful in 1m4s
2024-10-17 07:39:43 +03:00
e130633017 Update dependency tox to v4.22.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m3s
Tests / test (3.11) (pull_request) Successful in 1m2s
Tests / test (3.12) (pull_request) Successful in 1m10s
Tests / test (3.9) (pull_request) Successful in 1m6s
2024-10-15 22:29:37 +03:00
c71b07695f Update dependency mypy to v1.12.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m5s
Tests / test (3.11) (pull_request) Successful in 1m2s
Tests / test (3.12) (pull_request) Successful in 1m8s
Tests / test (3.9) (pull_request) Successful in 1m4s
2024-10-14 15:21:36 +03:00
03ad8e2144 Update dependency black to v24.10.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m6s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.12) (pull_request) Successful in 1m10s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-10-07 22:45:07 +03:00
c7d0d2793b Update dependency build to v1.2.2.post1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m3s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.12) (pull_request) Successful in 1m8s
Tests / test (3.9) (pull_request) Successful in 1m4s
2024-10-06 21:19:35 +03:00
41c8a6989b Update dependency tox to v4.21.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m2s
Tests / test (3.11) (pull_request) Successful in 1m0s
Tests / test (3.12) (pull_request) Successful in 1m9s
Tests / test (3.9) (pull_request) Successful in 1m2s
2024-10-03 19:11:48 +03:00
b8f5d59a4f Update dependency tox to v4.21.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m2s
Tests / test (3.11) (pull_request) Successful in 1m0s
Tests / test (3.12) (pull_request) Successful in 1m8s
Tests / test (3.9) (pull_request) Successful in 1m2s
2024-10-03 00:23:12 +03:00
67befe6bdb Update dependency tox to v4.21.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m1s
Tests / test (3.11) (pull_request) Successful in 1m0s
Tests / test (3.12) (pull_request) Successful in 1m6s
Tests / test (3.9) (pull_request) Successful in 1m1s
2024-10-01 07:39:37 +03:00
63cecf7ab8 Update dependency pylint to v3.3.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m3s
Tests / test (3.11) (pull_request) Successful in 1m4s
Tests / test (3.12) (pull_request) Successful in 1m19s
Tests / test (3.9) (pull_request) Successful in 1m2s
2024-09-24 15:11:18 +03:00
6652e8aff7 Merge pull request 'Update dependency pylint to v3.3.0' (#138) from renovate/pylint-3.x into dev
Reviewed-on: #138
2024-09-21 01:13:18 +03:00
a341ffd41d Dropped Python 3.8 support and added 3.12 support instead 2024-09-21 00:11:13 +02:00
60cc3f22d8 Update dependency pylint to v3.3.0
Some checks failed
Tests / test (3.10) (pull_request) Successful in 1m10s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.8) (pull_request) Failing after 14s
Tests / test (3.9) (pull_request) Successful in 1m6s
2024-09-20 16:22:35 +03:00
78a5fb886f Update dependency tox to v4.20.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m2s
Tests / test (3.11) (pull_request) Successful in 59s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m2s
2024-09-19 06:56:21 +03:00
f8ebaff82d Update dependency tox to v4.19.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m0s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-09-17 22:31:53 +03:00
8c15d20dc6 Update dependency pytest to v8.3.3
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m7s
Tests / test (3.9) (pull_request) Successful in 1m4s
2024-09-10 14:28:30 +03:00
8587030c23 Update dependency tox to v4.18.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m1s
Tests / test (3.11) (pull_request) Successful in 59s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-09-07 19:48:32 +03:00
b00d4c0281 Update dependency build to v1.2.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m2s
Tests / test (3.11) (pull_request) Successful in 59s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-09-07 00:00:20 +03:00
dcf5a24d2a Update dependency pylint to v3.2.7
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m1s
Tests / test (3.11) (pull_request) Successful in 59s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m2s
2024-08-31 18:05:42 +03:00
ca989b1e82 Update dependency mypy to v1.11.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m1s
Tests / test (3.11) (pull_request) Successful in 1m0s
Tests / test (3.8) (pull_request) Successful in 1m6s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-08-25 02:15:07 +03:00
36698b105c Update dependency pytest-asyncio to v0.24.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m7s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m6s
Tests / test (3.9) (pull_request) Successful in 1m4s
2024-08-22 11:53:29 +03:00
b366bb5c6f Update dependency tox to v4.18.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m0s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-08-13 20:32:44 +03:00
7a67c48ad6 Update dependency tox to v4.17.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m5s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.8) (pull_request) Successful in 1m3s
Tests / test (3.9) (pull_request) Successful in 1m4s
2024-08-07 21:22:32 +03:00
8b18449e23 Update dependency tox to v4.17.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m5s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-08-05 23:46:38 +03:00
fcb08adc59 Update dependency black to v24.8.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m5s
Tests / test (3.9) (pull_request) Successful in 1m10s
2024-08-02 21:37:29 +03:00
300df5b828 Update dependency mypy to v1.11.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m6s
Tests / test (3.11) (pull_request) Successful in 1m0s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-07-31 01:54:06 +03:00
3d9489eb0e Fixed incorrect test declaration 2024-07-26 19:58:26 +02:00
b00e188859 Update dependency pytest to v8.3.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m17s
Tests / test (3.8) (pull_request) Successful in 1m34s
Tests / test (3.9) (pull_request) Successful in 1m5s
2024-07-25 13:43:06 +03:00
a5edaa035e Update dependency pylint to v3.2.6
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m24s
Tests / test (3.11) (pull_request) Successful in 1m2s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-07-21 23:08:20 +03:00
891d8e416b Update dependency pytest to v8.3.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-07-20 19:39:38 +03:00
1e3e6cc7d0 Update dependency pytest to v8.3.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m1s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.8) (pull_request) Successful in 1m23s
Tests / test (3.9) (pull_request) Successful in 1m4s
2024-07-20 18:35:48 +03:00
4c003de0d3 Merge pull request 'Update dependency mypy to v1.11.0' (#120) from renovate/mypy-1.x into dev
Reviewed-on: #120
2024-07-19 21:54:20 +03:00
80fd18d101 Update dependency mypy to v1.11.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.8) (pull_request) Successful in 2m37s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-07-19 21:29:57 +03:00
35a85c8cab Update dependency pytest-asyncio to v0.23.8
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m23s
Tests / test (3.11) (pull_request) Successful in 1m0s
Tests / test (3.8) (pull_request) Successful in 1m3s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-07-17 21:02:27 +03:00
171e36a491 Merge pull request 'v3.2.3' (#118) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m2s
Tests / test (3.11) (push) Successful in 58s
Tests / test (3.8) (push) Successful in 1m4s
Tests / test (3.9) (push) Successful in 1m1s
Reviewed-on: #118
2024-07-10 00:07:54 +03:00
8f89d93fdc Bump version to 3.2.3
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m3s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m2s
2024-07-09 22:44:35 +02:00
8dc389d1b3 Bump pyrofork to ~=2.3.32 2024-07-09 22:43:19 +02:00
70b5994ecb Update dependency py-cord to ~=2.6.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m0s
Tests / test (3.11) (pull_request) Successful in 59s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m2s
2024-07-09 21:34:58 +03:00
ea45ccbad6 Update dependency tox to v4.16.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m0s
Tests / test (3.11) (pull_request) Successful in 57s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m0s
2024-07-03 07:05:32 +03:00
7d287ec46c Update dependency pylint to v3.2.5
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m0s
Tests / test (3.11) (pull_request) Successful in 58s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m2s
2024-06-28 17:03:25 +03:00
d317443960 Merge pull request 'Update dependency pylint to v3.2.4' (#114) from renovate/pylint-3.x into dev
Reviewed-on: #114
2024-06-26 11:54:38 +03:00
4daf6a5a5e Update dependency pylint to v3.2.4
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m0s
Tests / test (3.11) (pull_request) Successful in 58s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m0s
2024-06-26 11:26:23 +03:00
b81700da77 Update dependency types-aiofiles to v24
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m0s
Tests / test (3.11) (pull_request) Successful in 58s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m1s
2024-06-26 06:07:50 +03:00
910efda16c Update dependency mypy to v1.10.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 59s
Tests / test (3.11) (pull_request) Successful in 56s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 59s
2024-06-25 03:40:01 +03:00
c91591468b Update dependency types-aiofiles to v23.2.0.20240623
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m5s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m6s
Tests / test (3.9) (pull_request) Successful in 1m4s
2024-06-23 05:50:47 +03:00
dad6717706 Update dependency pylint to v3.2.3
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m3s
Tests / test (3.11) (pull_request) Successful in 1m10s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m5s
2024-06-06 18:02:20 +03:00
263522690f Update dependency tox to v4.15.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m18s
Tests / test (3.11) (pull_request) Successful in 1m2s
Tests / test (3.8) (pull_request) Successful in 1m6s
Tests / test (3.9) (pull_request) Successful in 1m7s
2024-06-06 04:18:39 +03:00
1bd4b6afe9 Update dependency pytest to v8.2.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m5s
Tests / test (3.11) (pull_request) Successful in 1m4s
Tests / test (3.8) (pull_request) Successful in 1m6s
Tests / test (3.9) (pull_request) Successful in 1m6s
2024-06-04 17:26:07 +03:00
c419c684aa Merge pull request 'v3.2.2' (#107) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m10s
Tests / test (3.11) (push) Successful in 1m4s
Tests / test (3.8) (push) Successful in 1m6s
Tests / test (3.9) (push) Successful in 1m7s
Reviewed-on: #107
2024-05-26 22:44:18 +03:00
bd3fbd7c2c Bump version to 3.2.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m6s
Tests / test (3.11) (pull_request) Successful in 1m30s
Tests / test (3.8) (pull_request) Successful in 1m5s
Tests / test (3.9) (pull_request) Successful in 1m6s
2024-05-26 21:40:28 +02:00
64ba9efa34 Replaced hasattr in dumps with supports_argument 2024-05-26 21:39:55 +02:00
748b2b2abb Merge pull request 'v3.2.1' (#106) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m3s
Tests / test (3.11) (push) Successful in 1m23s
Tests / test (3.8) (push) Successful in 1m7s
Tests / test (3.9) (push) Successful in 1m7s
Reviewed-on: #106
2024-05-26 17:53:00 +03:00
15f9274050 Bump version to 3.2.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m18s
Tests / test (3.8) (pull_request) Successful in 1m30s
Tests / test (3.9) (pull_request) Successful in 1m26s
2024-05-26 16:50:42 +02:00
6d3c20479d Added optional missing_ok to config_delete 2024-05-26 16:50:14 +02:00
52c2e5cc13 Merge pull request 'v3.2.0' (#105) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m4s
Tests / test (3.11) (push) Successful in 1m2s
Tests / test (3.8) (push) Successful in 1m29s
Tests / test (3.9) (push) Successful in 1m4s
Reviewed-on: #105
2024-05-26 17:29:44 +03:00
dfaadfd769 upload-artifact@v3 instead of upload-artifact@v4
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m28s
Tests / test (3.11) (pull_request) Successful in 1m2s
Tests / test (3.8) (pull_request) Successful in 1m5s
Tests / test (3.9) (pull_request) Successful in 1m6s
2024-05-26 16:21:53 +02:00
66ede3d60f Added build task
Some checks failed
Tests / test (3.10) (pull_request) Failing after 1m5s
Tests / test (3.11) (pull_request) Failing after 1m3s
Tests / test (3.8) (pull_request) Failing after 1m5s
Tests / test (3.9) (pull_request) Failing after 1m29s
2024-05-26 15:48:19 +02:00
3c3de1436e Added artifacts upload
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m32s
Tests / test (3.11) (pull_request) Successful in 54s
Tests / test (3.8) (pull_request) Successful in 1m24s
Tests / test (3.9) (pull_request) Successful in 58s
2024-05-26 15:43:53 +02:00
cfeadfdd32 Bumped version to 3.2.0 2024-05-26 15:40:54 +02:00
7032bef956 Added nested_delete and config_delete 2024-05-26 15:40:29 +02:00
ce691b2eda Update dependency pylint to v3.2.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 57s
Tests / test (3.11) (pull_request) Successful in 57s
Tests / test (3.8) (pull_request) Successful in 58s
Tests / test (3.9) (pull_request) Successful in 1m3s
2024-05-20 11:10:24 +03:00
a383959c9f Update dependency pytest to v8.2.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 55s
Tests / test (3.11) (pull_request) Successful in 53s
Tests / test (3.8) (pull_request) Successful in 1m24s
Tests / test (3.9) (pull_request) Successful in 1m24s
2024-05-19 22:27:08 +03:00
55c61e3fce Merge pull request 'v3.1.0' (#102) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 55s
Tests / test (3.11) (push) Successful in 55s
Tests / test (3.8) (push) Successful in 57s
Tests / test (3.9) (push) Successful in 1m27s
Reviewed-on: #102
2024-05-19 16:22:17 +03:00
7068e7f194 PycordBot.debug_guilds is now only set when debug is on
All checks were successful
Tests / test (3.10) (pull_request) Successful in 56s
Tests / test (3.11) (pull_request) Successful in 54s
Tests / test (3.8) (pull_request) Successful in 1m25s
Tests / test (3.9) (pull_request) Successful in 57s
2024-05-19 15:03:01 +02:00
5b16419f20 Merge pull request 'Update dependency pytest-asyncio to v0.23.7' (#101) from renovate/pytest-asyncio-0.x into dev
Reviewed-on: #101
2024-05-19 15:48:32 +03:00
2ed348933b Separated examples for Pyrogram and Pycord 2024-05-19 14:48:16 +02:00
c3d3e43216 Added errors and fixed pycord's bot 2024-05-19 14:48:01 +02:00
1f464ef624 Improved metadata and readme 2024-05-19 14:47:07 +02:00
10c7ecbfd0 Update dependency pytest-asyncio to v0.23.7
All checks were successful
Tests / test (3.10) (pull_request) Successful in 57s
Tests / test (3.11) (pull_request) Successful in 1m35s
Tests / test (3.8) (pull_request) Successful in 56s
Tests / test (3.9) (pull_request) Successful in 58s
2024-05-19 15:07:08 +03:00
e8769e8aeb Update dependency pylint to v3.2.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 55s
Tests / test (3.11) (pull_request) Successful in 1m19s
Tests / test (3.8) (pull_request) Successful in 55s
Tests / test (3.9) (pull_request) Successful in 55s
2024-05-18 20:18:16 +03:00
f101105d41 Update dependency types-ujson to v5.10.0.20240515
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m10s
Tests / test (3.11) (pull_request) Successful in 1m14s
Tests / test (3.8) (pull_request) Successful in 55s
Tests / test (3.9) (pull_request) Successful in 56s
2024-05-15 05:41:51 +03:00
b9550032ba Merge pull request 'Update to 3.0.1' (#98) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 57s
Tests / test (3.11) (push) Successful in 54s
Tests / test (3.8) (push) Successful in 1m8s
Tests / test (3.9) (push) Successful in 55s
Reviewed-on: #98
2024-05-15 00:19:03 +03:00
6b44a5852e Bump own version to 3.0.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 55s
Tests / test (3.11) (pull_request) Successful in 57s
Tests / test (3.8) (pull_request) Successful in 57s
Tests / test (3.9) (pull_request) Successful in 56s
2024-05-14 23:07:55 +02:00
7af4ad9655 Bump pyrofork to ~=2.3.21.post3 2024-05-14 23:04:16 +02:00
cb09910123 Update dependency pylint to v3.2.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 55s
Tests / test (3.11) (pull_request) Successful in 53s
Tests / test (3.8) (pull_request) Successful in 57s
Tests / test (3.9) (pull_request) Successful in 57s
2024-05-14 15:03:36 +03:00
d1da6a1d8b Update dependency ujson to ~=5.10.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 56s
Tests / test (3.11) (pull_request) Successful in 52s
Tests / test (3.8) (pull_request) Successful in 56s
Tests / test (3.9) (pull_request) Successful in 56s
2024-05-14 05:38:09 +03:00
787fc8c590 Update dependency pylint to v3.1.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 55s
Tests / test (3.11) (pull_request) Successful in 54s
Tests / test (3.8) (pull_request) Successful in 56s
Tests / test (3.9) (pull_request) Successful in 56s
2024-05-13 18:08:25 +03:00
b690725a47 Update dependency pytest to v8.2.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 54s
Tests / test (3.11) (pull_request) Successful in 51s
Tests / test (3.8) (pull_request) Successful in 54s
Tests / test (3.9) (pull_request) Successful in 55s
2024-04-28 03:27:28 +03:00
8719a44720 Update dependency tox to v4.15.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 55s
Tests / test (3.11) (pull_request) Successful in 52s
Tests / test (3.8) (pull_request) Successful in 1m18s
Tests / test (3.9) (pull_request) Successful in 55s
2024-04-26 22:20:26 +03:00
2fa65e7c76 Update dependency pytest to v8.1.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 55s
Tests / test (3.11) (pull_request) Successful in 54s
Tests / test (3.8) (pull_request) Successful in 55s
Tests / test (3.9) (pull_request) Successful in 57s
2024-04-26 21:17:23 +03:00
d3502bd935 Update dependency black to v24.4.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 55s
Tests / test (3.11) (pull_request) Successful in 53s
Tests / test (3.8) (pull_request) Successful in 55s
Tests / test (3.9) (pull_request) Successful in 57s
2024-04-26 03:37:21 +03:00
de3183d4ed Update dependency black to v24.4.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m15s
Tests / test (3.11) (pull_request) Successful in 1m19s
Tests / test (3.8) (pull_request) Successful in 59s
Tests / test (3.9) (pull_request) Successful in 56s
2024-04-24 18:20:20 +03:00
19f8383fb4 Update dependency mypy to v1.10.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m1s
Tests / test (3.11) (pull_request) Successful in 53s
Tests / test (3.8) (pull_request) Successful in 56s
Tests / test (3.9) (pull_request) Successful in 57s
2024-04-24 17:17:08 +03:00
9e957b7533 Update dependency black to v24.4.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 55s
Tests / test (3.11) (pull_request) Successful in 58s
Tests / test (3.8) (pull_request) Successful in 54s
Tests / test (3.9) (pull_request) Successful in 55s
2024-04-12 23:30:09 +03:00
5de6fac3dd Update dependency types-aiofiles to v23.2.0.20240403
All checks were successful
Tests / test (3.10) (pull_request) Successful in 54s
Tests / test (3.11) (pull_request) Successful in 52s
Tests / test (3.8) (pull_request) Successful in 54s
Tests / test (3.9) (pull_request) Successful in 55s
2024-04-03 05:59:16 +03:00
de2524921e Update dependency types-aiofiles to v23.2.0.20240331
All checks were successful
Tests / test (3.10) (pull_request) Successful in 53s
Tests / test (3.11) (pull_request) Successful in 52s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 54s
2024-03-31 06:10:03 +03:00
28001f3288 Update dependency build to v1.2.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m17s
Tests / test (3.11) (pull_request) Successful in 1m13s
Tests / test (3.8) (pull_request) Successful in 1m15s
Tests / test (3.9) (pull_request) Successful in 1m15s
2024-03-28 17:33:39 +02:00
af82545980 Update dependency pytest-cov to v5
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m21s
Tests / test (3.11) (pull_request) Successful in 1m11s
Tests / test (3.8) (pull_request) Successful in 1m14s
Tests / test (3.9) (pull_request) Successful in 1m17s
2024-03-24 23:11:11 +02:00
8308ed0c9d Update dependency tox to v4.14.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m28s
Tests / test (3.11) (pull_request) Successful in 1m14s
Tests / test (3.8) (pull_request) Successful in 1m16s
Tests / test (3.9) (pull_request) Successful in 1m16s
2024-03-22 18:15:34 +02:00
bf9f19321a Update dependency pytest-asyncio to v0.23.6
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m27s
Tests / test (3.11) (pull_request) Successful in 1m12s
Tests / test (3.8) (pull_request) Successful in 1m18s
Tests / test (3.9) (pull_request) Successful in 1m17s
2024-03-19 09:21:03 +02:00
6284d6e631 Update dependency black to v24.3.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 2m4s
Tests / test (3.11) (pull_request) Successful in 1m16s
Tests / test (3.8) (pull_request) Successful in 1m16s
Tests / test (3.9) (pull_request) Successful in 1m15s
2024-03-15 22:19:32 +02:00
63a6542293 Update dependency types-aiofiles to v23.2.0.20240311
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m23s
Tests / test (3.11) (pull_request) Successful in 1m13s
Tests / test (3.8) (pull_request) Successful in 1m16s
Tests / test (3.9) (pull_request) Successful in 1m16s
2024-03-11 04:32:55 +02:00
6521a9a510 Update dependency types-aiofiles to v23.2.0.20240310
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m24s
Tests / test (3.11) (pull_request) Successful in 1m13s
Tests / test (3.8) (pull_request) Successful in 1m17s
Tests / test (3.9) (pull_request) Successful in 1m17s
2024-03-10 04:39:55 +02:00
1d22188bfc Update dependency pytest to v8.1.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m28s
Tests / test (3.11) (pull_request) Successful in 1m20s
Tests / test (3.8) (pull_request) Successful in 1m16s
Tests / test (3.9) (pull_request) Successful in 1m17s
2024-03-09 14:08:36 +02:00
3a718caacf Update dependency mypy to v1.9.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m20s
Tests / test (3.11) (pull_request) Successful in 1m37s
Tests / test (3.8) (pull_request) Successful in 1m49s
Tests / test (3.9) (pull_request) Successful in 1m18s
2024-03-08 18:26:10 +02:00
06c4b9f845 Update dependency pytest-asyncio to v0.23.5.post1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m27s
Tests / test (3.11) (pull_request) Successful in 1m15s
Tests / test (3.8) (pull_request) Successful in 1m37s
Tests / test (3.9) (pull_request) Successful in 1m16s
2024-03-08 17:23:39 +02:00
00a835442c Update dependency tox to v4.14.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m23s
Tests / test (3.11) (pull_request) Successful in 1m15s
Tests / test (3.8) (pull_request) Successful in 1m17s
Tests / test (3.9) (pull_request) Successful in 1m16s
2024-03-06 21:50:35 +02:00
4349dcf4d7 Update dependency tox to v4.14.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m26s
Tests / test (3.11) (pull_request) Successful in 1m13s
Tests / test (3.8) (pull_request) Successful in 1m15s
Tests / test (3.9) (pull_request) Successful in 1m15s
2024-03-06 02:10:43 +02:00
c5c07bd75d Update dependency pytest to v8.1.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m21s
Tests / test (3.11) (pull_request) Successful in 1m13s
Tests / test (3.8) (pull_request) Successful in 1m16s
Tests / test (3.9) (pull_request) Successful in 1m15s
2024-03-03 23:26:11 +02:00
52f2630fda Update dependency py-cord to ~=2.5.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m15s
Tests / test (3.11) (pull_request) Successful in 1m14s
Tests / test (3.8) (pull_request) Successful in 1m15s
Tests / test (3.9) (pull_request) Successful in 1m16s
2024-03-02 11:02:32 +02:00
80e861800c Update dependency build to v1.1.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m24s
Tests / test (3.11) (pull_request) Successful in 1m13s
Tests / test (3.8) (pull_request) Successful in 1m16s
Tests / test (3.9) (pull_request) Successful in 1m17s
2024-02-29 23:31:18 +02:00
874892924f Update dependency build to v1.1.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m29s
Tests / test (3.11) (pull_request) Successful in 1m20s
Tests / test (3.8) (pull_request) Successful in 1m17s
Tests / test (3.9) (pull_request) Successful in 1m19s
2024-02-29 19:19:45 +02:00
fd113f861b Update dependency pylint to v3.1.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m31s
Tests / test (3.11) (pull_request) Successful in 1m19s
Tests / test (3.8) (pull_request) Successful in 1m17s
Tests / test (3.9) (pull_request) Successful in 1m17s
2024-02-25 19:04:33 +02:00
de7a9ef181 Update dependency pytest to v8.0.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m42s
Tests / test (3.11) (pull_request) Successful in 1m22s
Tests / test (3.8) (pull_request) Successful in 1m22s
Tests / test (3.9) (pull_request) Successful in 1m27s
2024-02-25 01:11:12 +02:00
cde0393baf Update dependency pylint to v3.0.4
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m31s
Tests / test (3.11) (pull_request) Successful in 1m15s
Tests / test (3.8) (pull_request) Successful in 1m15s
Tests / test (3.9) (pull_request) Successful in 1m16s
2024-02-23 23:53:57 +02:00
70073bf68e Merge pull request 'Update dependency black to v24.2.0' (#63) from renovate/black-24.x into dev
Reviewed-on: #63
2024-02-17 17:20:33 +02:00
d4ad6609d6 Merge pull request 'Update dependency tox to v4.13.0' (#65) from renovate/tox-4.x into dev
Reviewed-on: #65
2024-02-17 17:20:09 +02:00
1e6b2ccaca Update dependency tox to v4.13.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m17s
Tests / test (3.11) (pull_request) Successful in 1m14s
Tests / test (3.8) (pull_request) Successful in 1m15s
Tests / test (3.9) (pull_request) Successful in 1m16s
2024-02-17 16:39:25 +02:00
abd4f035ad Update dependency black to v24.2.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m23s
Tests / test (3.11) (pull_request) Successful in 1m13s
Tests / test (3.8) (pull_request) Successful in 1m15s
Tests / test (3.9) (pull_request) Successful in 1m15s
2024-02-17 16:39:21 +02:00
0408cd676f Update dependency pytest-asyncio to v0.23.5
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m24s
Tests / test (3.11) (pull_request) Successful in 1m15s
Tests / test (3.8) (pull_request) Successful in 1m15s
Tests / test (3.9) (pull_request) Successful in 1m15s
2024-02-17 15:35:45 +02:00
b1c61f0a5b Update dependency pytest to v8.0.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m26s
Tests / test (3.11) (pull_request) Successful in 1m13s
Tests / test (3.8) (pull_request) Successful in 1m17s
Tests / test (3.9) (pull_request) Successful in 1m14s
2024-02-17 14:32:14 +02:00
6e7d3c5e6f Update requirements/pyrogram.txt 2024-02-17 14:30:20 +02:00
458c2ef615 Update dependency pyrofork to ~=2.4.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m43s
Tests / test (3.11) (pull_request) Successful in 1m25s
Tests / test (3.8) (pull_request) Successful in 1m19s
Tests / test (3.9) (pull_request) Successful in 1m21s
2024-02-06 21:01:19 +02:00
dc9c83dc68 Update dependency black to v24.1.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m32s
Tests / test (3.11) (pull_request) Successful in 1m16s
Tests / test (3.8) (pull_request) Successful in 1m14s
Tests / test (3.9) (pull_request) Successful in 1m16s
2024-01-28 08:24:05 +02:00
48d1d9291a Update dependency pytest to v8
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m42s
Tests / test (3.11) (pull_request) Successful in 1m18s
Tests / test (3.8) (pull_request) Successful in 1m15s
Tests / test (3.9) (pull_request) Successful in 1m17s
2024-01-27 23:58:41 +02:00
451b0c5135 Update dependency black to v24
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m34s
Tests / test (3.11) (pull_request) Successful in 1m15s
Tests / test (3.8) (pull_request) Successful in 1m13s
Tests / test (3.9) (pull_request) Successful in 1m15s
2024-01-26 08:05:08 +02:00
f950eaa339 Update dependency tox to v4.12.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m28s
Tests / test (3.11) (pull_request) Successful in 1m14s
Tests / test (3.8) (pull_request) Successful in 1m13s
Tests / test (3.9) (pull_request) Successful in 1m16s
2024-01-17 06:57:41 +02:00
bd3c62fed8 Bump pyrofork to 2.3.16.post5 2024-01-15 22:40:45 +01:00
16658efb17 Bump pyrofork to 2.3.16.post4 2024-01-15 00:54:05 +01:00
eb0a43e360 Update dependency tox to v4.12.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m26s
Tests / test (3.11) (pull_request) Successful in 1m15s
Tests / test (3.8) (pull_request) Successful in 1m15s
Tests / test (3.9) (pull_request) Successful in 1m15s
2024-01-12 04:32:16 +02:00
d3a423a560 Update dependency types-aiofiles to v23.2.0.20240106
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m14s
Tests / test (3.11) (pull_request) Successful in 1m15s
Tests / test (3.8) (pull_request) Successful in 1m18s
Tests / test (3.9) (pull_request) Successful in 1m19s
2024-01-06 04:22:14 +02:00
20cc754a2a Fixed wrong variable being used in PyroClient.start() 2024-01-03 23:56:34 +01:00
fc14cad3ff owner, scoped_commands and i18n_bot_info can be provided in Client's kwargs now 2024-01-03 23:16:26 +01:00
5ba763246b Merge pull request 'Update to 3.0.0' (#52) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m15s
Tests / test (3.11) (push) Successful in 1m14s
Tests / test (3.8) (push) Successful in 1m14s
Tests / test (3.9) (push) Successful in 1m22s
Reviewed-on: #52
2024-01-04 00:06:50 +02:00
327b161b41 Added a few JSON examples 2024-01-03 22:45:39 +01:00
c756c6b1dc Closes #33
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m21s
Tests / test (3.11) (pull_request) Successful in 1m17s
Tests / test (3.8) (pull_request) Successful in 1m15s
Tests / test (3.9) (pull_request) Successful in 1m16s
2024-01-03 22:37:04 +01:00
9e9c90fce1 Pyrofork has replaced the vanilla Pyrogram (#51) 2024-01-03 22:35:46 +01:00
91cc03f921 Update dependency pytest to v7.4.4
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m28s
Tests / test (3.11) (pull_request) Successful in 1m13s
Tests / test (3.8) (pull_request) Successful in 1m14s
Tests / test (3.9) (pull_request) Successful in 1m13s
2024-01-01 18:09:34 +02:00
a0538625e2 Update dependency pytest-asyncio to v0.23.3
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m13s
Tests / test (3.11) (pull_request) Successful in 1m13s
Tests / test (3.8) (pull_request) Successful in 1m15s
Tests / test (3.9) (pull_request) Successful in 1m13s
2024-01-01 17:06:07 +02:00
f0ffdf096d Merge pull request 'Pycord support initial release' (#48) from dev into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m8s
Tests / test (3.11) (push) Successful in 1m5s
Tests / test (3.8) (push) Successful in 1m43s
Tests / test (3.9) (push) Successful in 1m3s
Reviewed-on: #48
2023-12-27 15:00:41 +02:00
e7555d3de1 Bump version to 2.1.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m8s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m8s
2023-12-27 13:46:10 +01:00
17f15aca5b Initial Pycord addition 2023-12-27 13:45:40 +01:00
73c3a1ff13 Update dependency black to v23.12.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m10s
Tests / test (3.11) (pull_request) Successful in 1m6s
Tests / test (3.8) (pull_request) Successful in 1m8s
Tests / test (3.9) (pull_request) Successful in 1m10s
2023-12-23 01:39:45 +02:00
bfa3d4f6e9 Update dependency mypy to v1.8.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m11s
Tests / test (3.11) (pull_request) Successful in 1m6s
Tests / test (3.8) (pull_request) Successful in 1m5s
Tests / test (3.9) (pull_request) Successful in 1m42s
2023-12-21 19:03:19 +02:00
3d10cbcb2f Update dependency isort to v5.13.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m15s
Tests / test (3.11) (pull_request) Successful in 1m11s
Tests / test (3.8) (pull_request) Successful in 1m5s
Tests / test (3.9) (pull_request) Successful in 1m7s
2023-12-13 23:11:44 +02:00
88f77e8494 Update dependency black to v23.12.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m5s
Tests / test (3.11) (pull_request) Successful in 1m4s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m3s
2023-12-12 08:44:33 +02:00
f5f62f20cc Update dependency types-ujson to v5.9.0.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m5s
Tests / test (3.11) (pull_request) Successful in 1m4s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m4s
2023-12-12 04:27:38 +02:00
45743bdb7e Update dependency pylint to v3.0.3
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m6s
Tests / test (3.11) (pull_request) Successful in 1m9s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m2s
2023-12-11 23:04:59 +02:00
8e1f746309 Update dependency isort to v5.13.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m9s
Tests / test (3.11) (pull_request) Successful in 1m6s
Tests / test (3.8) (pull_request) Successful in 1m7s
Tests / test (3.9) (pull_request) Successful in 1m3s
2023-12-11 22:00:00 +02:00
c4df7c6106 Update dependency ujson to ~=5.9.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m11s
Tests / test (3.11) (pull_request) Successful in 1m9s
Tests / test (3.8) (pull_request) Successful in 1m10s
Tests / test (3.9) (pull_request) Successful in 1m10s
2023-12-11 01:36:51 +02:00
5103333920 Renovate's main branch is now "dev"
All checks were successful
Tests / test (3.10) (push) Successful in 1m9s
Tests / test (3.11) (push) Successful in 1m8s
Tests / test (3.8) (push) Successful in 1m6s
Tests / test (3.9) (push) Successful in 1m7s
2023-12-10 11:58:21 +01:00
df09a21aee Update dependency isort to v5.13.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m14s
Tests / test (3.11) (pull_request) Successful in 1m9s
Tests / test (3.8) (pull_request) Successful in 1m8s
Tests / test (3.9) (pull_request) Successful in 1m7s
Tests / test (3.10) (push) Successful in 1m11s
Tests / test (3.11) (push) Successful in 1m10s
Tests / test (3.8) (push) Successful in 1m5s
Tests / test (3.9) (push) Successful in 1m8s
2023-12-09 16:05:30 +02:00
1800ff4dc3 Update dependency pytest-asyncio to v0.23.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m6s
Tests / test (3.11) (pull_request) Successful in 1m4s
Tests / test (3.8) (pull_request) Successful in 1m7s
Tests / test (3.9) (pull_request) Successful in 1m1s
Tests / test (3.10) (push) Successful in 1m4s
Tests / test (3.11) (push) Successful in 1m6s
Tests / test (3.8) (push) Successful in 1m0s
Tests / test (3.9) (push) Successful in 1m1s
2023-12-04 10:14:13 +02:00
9557b1759b Update dependency pytest-asyncio to v0.23.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m6s
Tests / test (3.11) (pull_request) Successful in 1m16s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m51s
Tests / test (3.10) (push) Successful in 1m4s
Tests / test (3.11) (push) Successful in 1m6s
Tests / test (3.8) (push) Successful in 1m1s
Tests / test (3.9) (push) Successful in 1m2s
2023-12-03 21:28:30 +02:00
a650039bc9 Update dependency tox to v4.11.4
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m5s
Tests / test (3.11) (pull_request) Successful in 1m4s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m3s
Tests / test (3.10) (push) Successful in 1m6s
Tests / test (3.11) (push) Successful in 1m5s
Tests / test (3.8) (push) Successful in 1m3s
Tests / test (3.9) (push) Successful in 1m2s
2023-11-28 07:18:04 +02:00
a6a1f1cacc Update dependency mypy to v1.7.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m8s
Tests / test (3.11) (pull_request) Successful in 1m13s
Tests / test (3.8) (pull_request) Successful in 1m46s
Tests / test (3.9) (pull_request) Successful in 1m49s
Tests / test (3.10) (push) Successful in 3m17s
Tests / test (3.11) (push) Successful in 1m9s
Tests / test (3.8) (push) Successful in 3m4s
Tests / test (3.9) (push) Successful in 1m34s
2023-11-23 20:34:48 +02:00
c8d5a81a2c Update dependency mypy to v1.7.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m7s
Tests / test (3.11) (pull_request) Successful in 1m5s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m12s
Tests / test (3.10) (push) Successful in 1m29s
Tests / test (3.11) (push) Successful in 1m9s
Tests / test (3.8) (push) Successful in 1m18s
Tests / test (3.9) (push) Successful in 1m19s
2023-11-10 17:25:50 +02:00
c23326cd10 Update dependency black to v23.11.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m9s
Tests / test (3.11) (pull_request) Successful in 1m4s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m1s
Tests / test (3.10) (push) Successful in 1m3s
Tests / test (3.11) (push) Successful in 1m6s
Tests / test (3.8) (push) Successful in 1m0s
Tests / test (3.9) (push) Successful in 1m5s
2023-11-08 08:31:01 +02:00
e55916501d Update dependency pytest-asyncio to v0.22.0 (#30)
All checks were successful
Tests / test (3.10) (push) Successful in 1m2s
Tests / test (3.11) (push) Successful in 1m6s
Tests / test (3.8) (push) Successful in 1m1s
Tests / test (3.9) (push) Successful in 1m2s
2023-10-31 11:06:27 +02:00
4acd61c5c9 Update dependency pytest-asyncio to v0.22.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m10s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m0s
Tests / test (3.9) (pull_request) Successful in 1m2s
2023-10-31 10:19:49 +02:00
ae28461f3b Experiment failed: caching disabled
All checks were successful
Tests / test (3.10) (push) Successful in 1m19s
Tests / test (3.11) (push) Successful in 1m1s
Tests / test (3.8) (push) Successful in 1m3s
Tests / test (3.9) (push) Successful in 59s
2023-10-25 08:40:32 +03:00
b0a5d10d90 EOL fixed
Some checks failed
Tests / test (3.10) (push) Failing after 4m48s
Tests / test (3.8) (push) Has been cancelled
Tests / test (3.9) (push) Has been cancelled
Tests / test (3.11) (push) Has been cancelled
2023-10-25 08:35:28 +03:00
9784c10d13 Added caching for requirements/*.txt 2023-10-25 08:35:04 +03:00
b776b95047 Experiment: dependency caching
All checks were successful
Tests / test (3.10) (push) Successful in 1m3s
Tests / test (3.11) (push) Successful in 1m2s
Tests / test (3.8) (push) Successful in 1m0s
Tests / test (3.9) (push) Successful in 1m0s
2023-10-25 08:30:08 +03:00
f8936321e1 Update dependency pytest to v7.4.3
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m35s
Tests / test (3.11) (pull_request) Successful in 1m16s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m4s
Tests / test (3.10) (push) Successful in 1m9s
Tests / test (3.11) (push) Successful in 1m7s
Tests / test (3.8) (push) Successful in 1m1s
Tests / test (3.9) (push) Successful in 1m3s
2023-10-24 23:24:10 +03:00
cb7cfd1f03 Update dependency black to v23.10.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m13s
Tests / test (3.11) (pull_request) Successful in 1m4s
Tests / test (3.8) (pull_request) Successful in 1m19s
Tests / test (3.9) (pull_request) Successful in 1m1s
Tests / test (3.10) (push) Successful in 1m14s
Tests / test (3.11) (push) Successful in 1m10s
Tests / test (3.8) (push) Successful in 1m2s
Tests / test (3.9) (push) Successful in 1m6s
2023-10-23 23:04:18 +03:00
563069926d Update dependency pylint to v3.0.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m12s
Tests / test (3.11) (pull_request) Successful in 1m8s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m7s
Tests / test (3.10) (push) Successful in 1m9s
Tests / test (3.11) (push) Successful in 1m7s
Tests / test (3.8) (push) Successful in 1m3s
Tests / test (3.9) (push) Successful in 1m4s
2023-10-22 17:45:43 +03:00
ec95e89c5e Update dependency mypy to v1.6.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m8s
Tests / test (3.11) (pull_request) Successful in 1m5s
Tests / test (3.8) (pull_request) Successful in 1m3s
Tests / test (3.9) (pull_request) Successful in 1m4s
Tests / test (3.10) (push) Successful in 1m6s
Tests / test (3.11) (push) Successful in 1m9s
Tests / test (3.8) (push) Successful in 1m2s
Tests / test (3.9) (push) Successful in 1m6s
2023-10-18 08:51:17 +03:00
a02452c1ee Update dependency black to v23.10.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m11s
Tests / test (3.11) (pull_request) Successful in 1m4s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m5s
Tests / test (3.10) (push) Successful in 1m8s
Tests / test (3.11) (push) Successful in 1m6s
Tests / test (3.8) (push) Successful in 1m3s
Tests / test (3.9) (push) Successful in 1m5s
2023-10-17 19:17:13 +03:00
bf3bcab8a2 Update dependency mypy to v1.6.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m11s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m6s
Tests / test (3.9) (pull_request) Successful in 1m5s
Tests / test (3.10) (push) Successful in 1m31s
Tests / test (3.11) (push) Successful in 1m3s
Tests / test (3.8) (push) Successful in 1m29s
Tests / test (3.9) (push) Successful in 1m5s
2023-10-10 20:44:54 +03:00
e8ea7accfa Update dependency pylint to v3.0.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m14s
Tests / test (3.11) (pull_request) Successful in 1m6s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m7s
Tests / test (3.10) (push) Successful in 1m8s
Tests / test (3.11) (push) Successful in 1m4s
Tests / test (3.8) (push) Successful in 1m2s
Tests / test (3.9) (push) Successful in 1m1s
2023-10-05 23:55:07 +03:00
87c35a69d4 Update dependency pylint to v3
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m10s
Tests / test (3.11) (pull_request) Successful in 2m8s
Tests / test (3.8) (pull_request) Successful in 1m48s
Tests / test (3.9) (pull_request) Successful in 1m19s
Tests / test (3.10) (push) Successful in 1m50s
Tests / test (3.11) (push) Successful in 2m7s
Tests / test (3.8) (push) Successful in 1m26s
Tests / test (3.9) (push) Successful in 1m17s
2023-10-02 20:32:53 +03:00
083a91f20c Update dependency pylint to v2.17.7
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m8s
Tests / test (3.11) (pull_request) Successful in 1m2s
Tests / test (3.8) (pull_request) Successful in 1m5s
Tests / test (3.9) (pull_request) Successful in 1m5s
Tests / test (3.10) (push) Successful in 1m6s
Tests / test (3.11) (push) Successful in 1m3s
Tests / test (3.8) (push) Successful in 1m3s
Tests / test (3.9) (push) Successful in 1m4s
2023-10-01 01:11:50 +03:00
84fe3382ef Update dependency pylint to v2.17.6
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m9s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m28s
Tests / test (3.9) (pull_request) Successful in 1m14s
Tests / test (3.10) (push) Successful in 1m28s
Tests / test (3.11) (push) Successful in 1m4s
Tests / test (3.8) (push) Successful in 1m5s
Tests / test (3.9) (push) Successful in 1m9s
2023-09-25 15:03:19 +03:00
6baca46a9c Update dependency black to v23.9.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m8s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m2s
Tests / test (3.10) (push) Successful in 1m3s
Tests / test (3.11) (push) Successful in 1m1s
Tests / test (3.8) (push) Successful in 1m1s
Tests / test (3.9) (push) Successful in 1m3s
2023-09-11 04:39:59 +03:00
0e3bf42c55 Update dependency black to v23.9.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m5s
Tests / test (3.11) (pull_request) Successful in 1m2s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m3s
Tests / test (3.10) (push) Successful in 1m5s
Tests / test (3.11) (push) Successful in 1m3s
Tests / test (3.8) (push) Successful in 1m2s
Tests / test (3.9) (push) Successful in 1m2s
2023-09-09 07:20:09 +03:00
0f5c3c5ed1 Update dependency tox to v4.11.3
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m2s
Tests / test (3.10) (push) Successful in 1m3s
Tests / test (3.11) (push) Successful in 1m2s
Tests / test (3.8) (push) Successful in 1m2s
Tests / test (3.9) (push) Successful in 1m2s
2023-09-09 02:10:52 +03:00
f017082d16 Update dependency tox to v4.11.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.8) (pull_request) Successful in 1m3s
Tests / test (3.9) (pull_request) Successful in 1m5s
Tests / test (3.10) (push) Successful in 1m6s
Tests / test (3.11) (push) Successful in 1m7s
Tests / test (3.8) (push) Successful in 1m9s
Tests / test (3.9) (push) Successful in 1m2s
2023-09-08 07:37:08 +03:00
015511f6ac Update dependency pytest to v7.4.2
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m8s
Tests / test (3.11) (pull_request) Successful in 1m2s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m6s
Tests / test (3.10) (push) Successful in 1m9s
Tests / test (3.11) (push) Successful in 1m5s
Tests / test (3.8) (push) Successful in 1m6s
Tests / test (3.9) (push) Successful in 1m6s
2023-09-07 22:20:37 +03:00
e35e643108 Update dependency build to v1.0.3
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m7s
Tests / test (3.11) (pull_request) Successful in 1m1s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m3s
Tests / test (3.10) (push) Successful in 1m5s
Tests / test (3.11) (push) Successful in 1m2s
Tests / test (3.8) (push) Successful in 1m3s
Tests / test (3.9) (push) Successful in 1m3s
2023-09-07 03:46:59 +03:00
c02f43ff07 Update dependency pytest to v7.4.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m23s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m25s
Tests / test (3.10) (push) Successful in 1m7s
Tests / test (3.11) (push) Successful in 1m41s
Tests / test (3.8) (push) Successful in 1m7s
Tests / test (3.9) (push) Successful in 1m3s
2023-09-02 18:36:56 +03:00
5333d0be9f Update dependency build to v1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m22s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m9s
Tests / test (3.9) (pull_request) Successful in 1m4s
Tests / test (3.10) (push) Successful in 1m8s
Tests / test (3.11) (push) Successful in 1m11s
Tests / test (3.8) (push) Successful in 1m7s
Tests / test (3.9) (push) Successful in 1m4s
2023-09-02 00:05:01 +03:00
29a6d7f739 Update dependency tox to v4.11.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m9s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m26s
Tests / test (3.9) (pull_request) Successful in 1m10s
Tests / test (3.10) (push) Successful in 1m9s
Tests / test (3.11) (push) Successful in 1m7s
Tests / test (3.8) (push) Successful in 1m4s
Tests / test (3.9) (push) Successful in 1m3s
2023-09-01 23:02:51 +03:00
bb934e67ea Update dependency tox to v4.11.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 2m51s
Tests / test (3.11) (pull_request) Successful in 1m47s
Tests / test (3.8) (pull_request) Successful in 1m3s
Tests / test (3.9) (pull_request) Successful in 1m8s
Tests / test (3.10) (push) Successful in 1m13s
Tests / test (3.11) (push) Successful in 1m5s
Tests / test (3.8) (push) Successful in 1m7s
Tests / test (3.9) (push) Successful in 1m6s
2023-08-29 23:12:31 +03:00
7998d556f9 Update dependency tox to v4.10.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m8s
Tests / test (3.11) (pull_request) Successful in 1m3s
Tests / test (3.8) (pull_request) Successful in 1m0s
Tests / test (3.9) (pull_request) Successful in 1m3s
Tests / test (3.10) (push) Successful in 1m5s
Tests / test (3.11) (push) Successful in 1m0s
Tests / test (3.8) (push) Successful in 59s
Tests / test (3.9) (push) Successful in 1m2s
2023-08-21 20:47:16 +03:00
3d30ea3f46 Update dependency mypy to v1.5.1
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m5s
Tests / test (3.11) (pull_request) Successful in 1m2s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m3s
Tests / test (3.10) (push) Successful in 1m4s
Tests / test (3.11) (push) Successful in 1m6s
Tests / test (3.8) (push) Successful in 1m3s
Tests / test (3.9) (push) Successful in 1m20s
2023-08-16 20:27:04 +03:00
97eaedb14a Update dependency tox to v4.9.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m5s
Tests / test (3.11) (pull_request) Successful in 1m0s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m6s
Tests / test (3.10) (push) Successful in 1m4s
Tests / test (3.11) (push) Successful in 1m1s
Tests / test (3.8) (push) Successful in 1m3s
Tests / test (3.9) (push) Successful in 1m2s
2023-08-16 18:23:05 +03:00
72eef216b5 Merge pull request 'Update dependency types-aiofiles to v23.2.0.0' (#6) from renovate/types-aiofiles-23.x into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m9s
Tests / test (3.11) (push) Successful in 1m8s
Tests / test (3.8) (push) Successful in 1m8s
Tests / test (3.9) (push) Successful in 1m3s
Reviewed-on: #6
2023-08-16 16:24:12 +03:00
3c48a6b561 Update dependency types-aiofiles to v23.2.0.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m5s
Tests / test (3.8) (pull_request) Successful in 1m0s
Tests / test (3.9) (pull_request) Successful in 1m1s
2023-08-16 16:19:23 +03:00
b0f6d43b8b Update dependency tox to v4.8.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m11s
Tests / test (3.11) (pull_request) Successful in 1m11s
Tests / test (3.8) (pull_request) Successful in 1m2s
Tests / test (3.9) (pull_request) Successful in 1m10s
Tests / test (3.10) (push) Successful in 1m16s
Tests / test (3.11) (push) Successful in 1m5s
Tests / test (3.8) (push) Successful in 1m4s
Tests / test (3.9) (push) Successful in 1m7s
2023-08-12 22:09:00 +03:00
74db27487f Added build to dev dependencies
All checks were successful
Tests / test (3.10) (push) Successful in 1m8s
Tests / test (3.11) (push) Successful in 1m2s
Tests / test (3.8) (push) Successful in 1m5s
Tests / test (3.9) (push) Successful in 1m6s
2023-08-10 21:47:21 +02:00
95b58e85a9 Changed aiofiles version
All checks were successful
Tests / test (3.10) (push) Successful in 1m25s
Tests / test (3.11) (push) Successful in 1m25s
Tests / test (3.8) (push) Successful in 1m1s
Tests / test (3.9) (push) Successful in 1m3s
2023-08-10 21:34:42 +02:00
83658af314 Merge pull request 'Update dependency mypy to v1.5.0' (#4) from renovate/mypy-1.x into main
All checks were successful
Tests / test (3.10) (push) Successful in 1m5s
Tests / test (3.11) (push) Successful in 1m2s
Tests / test (3.8) (push) Successful in 1m1s
Tests / test (3.9) (push) Successful in 1m3s
Reviewed-on: #4
2023-08-10 17:18:04 +03:00
e9086c1582 Update dependency mypy to v1.5.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m4s
Tests / test (3.11) (pull_request) Successful in 1m0s
Tests / test (3.8) (pull_request) Successful in 1m4s
Tests / test (3.9) (pull_request) Successful in 1m2s
2023-08-10 16:40:48 +03:00
fdd534ba41 Update dependency aiofiles to ~=23.2.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m1s
Tests / test (3.11) (pull_request) Successful in 1m7s
Tests / test (3.8) (pull_request) Successful in 1m1s
Tests / test (3.9) (pull_request) Successful in 1m5s
Tests / test (3.10) (push) Successful in 1m3s
Tests / test (3.11) (push) Successful in 1m1s
Tests / test (3.8) (push) Successful in 59s
Tests / test (3.9) (push) Successful in 1m1s
2023-08-09 14:43:20 +03:00
9d97f8d4b2 Update dependency tox to v4.7.0
All checks were successful
Tests / test (3.10) (pull_request) Successful in 1m2s
Tests / test (3.11) (pull_request) Successful in 1m2s
Tests / test (3.8) (pull_request) Successful in 1m9s
Tests / test (3.9) (pull_request) Successful in 1m12s
Tests / test (3.10) (push) Successful in 1m5s
Tests / test (3.11) (push) Successful in 1m0s
Tests / test (3.8) (push) Successful in 1m0s
Tests / test (3.9) (push) Successful in 1m0s
2023-08-08 18:11:58 +03:00
0c06d2ed58 Fixed Renovate config
All checks were successful
Tests / test (3.10) (push) Successful in 1m1s
Tests / test (3.11) (push) Successful in 1m1s
Tests / test (3.8) (push) Successful in 1m6s
Tests / test (3.9) (push) Successful in 1m1s
2023-08-08 10:28:56 +02:00
245c747991 Update Renovate rules
All checks were successful
Tests / test (3.10) (push) Successful in 1m16s
Tests / test (3.11) (push) Successful in 1m4s
Tests / test (3.8) (push) Successful in 1m2s
Tests / test (3.9) (push) Successful in 1m9s
2023-08-07 12:16:56 +02:00
187187a8a2 Fixed tests workflow
All checks were successful
Tests / test (3.10) (push) Successful in 1m0s
Tests / test (3.11) (push) Successful in 1m2s
Tests / test (3.8) (push) Successful in 1m1s
Tests / test (3.9) (push) Successful in 1m30s
2023-08-07 11:40:50 +02:00
8d27f43cce Updated workflow 2023-08-07 11:24:48 +02:00
f181552fb8 Updated to 2.0.0 2023-08-07 11:21:49 +02:00
32b1acf4aa Updated to 0.2.2
All checks were successful
Tests / test (3.10) (push) Successful in 1m4s
Tests / test (3.11) (push) Successful in 1m13s
Tests / test (3.8) (push) Successful in 1m9s
Tests / test (3.9) (push) Successful in 1m1s
2023-08-06 22:00:14 +02:00
1c1c71d40b Fixed PyroClient.bot_locale 2023-08-06 21:59:48 +02:00
65838450ee Fixed typing of Dict
All checks were successful
Tests / test (3.10) (push) Successful in 1m9s
Tests / test (3.11) (push) Successful in 1m52s
Tests / test (3.8) (push) Successful in 1m23s
Tests / test (3.9) (push) Successful in 1m25s
2023-08-06 21:22:24 +02:00
3f39e07d04 Added coverage display 2023-08-06 21:21:55 +02:00
c5fdd60d13 Added container
Some checks failed
Tests / test (3.10) (push) Successful in 1m26s
Tests / test (3.11) (push) Successful in 1m1s
Tests / test (3.8) (push) Failing after 1m3s
Tests / test (3.9) (push) Successful in 1m11s
2023-08-06 21:11:06 +02:00
35fe69d2a8 Tried another Python versions set
Some checks reported warnings
Tests / test (3.11) (push) Has been cancelled
Tests / test (3.8) (push) Has been cancelled
Tests / test (3.9) (push) Has been cancelled
Tests / test (3.10) (push) Has been cancelled
2023-08-06 19:24:16 +02:00
3bb7ecca7e Updated python versions
Some checks failed
Tests / test (3.10.12) (push) Failing after 5s
Tests / test (3.11.3) (push) Failing after 5s
Tests / test (3.8.17) (push) Failing after 6s
Tests / test (3.9.17) (push) Failing after 4s
2023-08-06 19:14:44 +02:00
64aa2686ea Updated to 0.2.1
Some checks failed
Tests / test (3.10) (push) Failing after 55s
Tests / test (3.11) (push) Failing after 5s
Tests / test (3.8) (push) Failing after 6s
Tests / test (3.9) (push) Failing after 5s
2023-08-06 19:11:16 +02:00
461642a529 Added nested_set tests 2023-08-06 12:51:32 +02:00
e5c0f5c1d1 Added i18n tests 2023-08-06 12:51:23 +02:00
00b1058014 BotLocale now has default_locale 2023-08-06 12:51:06 +02:00
bc5be37ff1 locale is now Union[str, None] 2023-08-06 12:50:34 +02:00
7c756d7065 Switched versioning to semantic 2023-08-06 12:43:41 +02:00
3273b86b75 nested_set raises KeyError if not create_missing 2023-08-06 12:43:01 +02:00
783443e448 Changed imports 2023-08-06 12:42:37 +02:00
723cc40221 Fixed imports 2023-08-06 11:33:41 +02:00
b6537a50ae Changed path to tests/ 2023-08-06 02:08:02 +02:00
e508f37089 Added pytest to pyproject 2023-08-06 02:07:07 +02:00
d66bb9c93e Locale of _() now defaults to "en" 2023-08-06 01:44:51 +02:00
253c85985b Added some basic test 2023-08-06 01:25:32 +02:00
11d49fd476 Fixed escape_forward_slashes error 2023-08-06 01:25:08 +02:00
dc107ebdb3 Updated to 1.9 2023-07-26 14:12:13 +02:00
33c33d08e2 Allowed passing kwargs 2023-07-26 14:12:05 +02:00
295e77e403 Updated to 1.8 2023-07-03 10:57:00 +02:00
279a8e9d84 reports.chat_id can now be "owner" 2023-07-03 10:56:24 +02:00
ae374511cd Updated to 1.7 2023-06-30 10:32:16 +02:00
eb23d3e9b6 No more locations.locale in config 2023-06-30 10:31:49 +02:00
f4e74b5bc6 Added trailing slashes 2023-06-29 16:03:49 +02:00
7b8434ae71 Updated to 1.6 2023-06-29 15:59:06 +02:00
8c2054f496 Improved init flexibility 2023-06-29 15:58:50 +02:00
fe9cc3674f Removed duplicate py version 2023-06-29 15:58:20 +02:00
c71a7555f9 Updated to 1.5 2023-06-26 13:29:47 +02:00
cb755faa9a Added scopes_placeholders 2023-06-26 13:29:26 +02:00
1859d0532c Updated to 1.4 2023-06-26 13:06:55 +02:00
ebce8e0141 Fixed workers and max_concurrent_transmissions 2023-06-26 13:06:23 +02:00
9af6d5cb7c Integrated the scheduler 2023-06-26 12:45:39 +02:00
7f054a6d93 Updated to 1.3 2023-06-26 12:31:52 +02:00
d6e3ecb564 Updated to 1.2 2023-06-26 12:26:13 +02:00
e93e73bca9 Added missing import 2023-06-26 12:25:55 +02:00
3a96df8add Added direct PyroClient support 2023-06-26 12:19:29 +02:00
e3e88e74cd Updated to 1.1 2023-06-26 12:15:56 +02:00
20d47dc3d3 Completely removed Python 3.7 support 2023-06-20 12:41:40 +02:00
931f014242 Updated to 1.0 2023-06-20 12:41:00 +02:00
d352452d94 Fixed package bug 2023-06-20 12:40:44 +02:00
bba0aca25a Updated to 0.9 2023-06-20 12:31:21 +02:00
0d93e08397 Added BotLocale class 2023-06-20 12:30:27 +02:00
b21f7044eb Bump Python version to >=3.8 and version to 0.8 2023-06-13 10:55:44 +02:00
0cdd887e63 Dump ujson to ~=5.8.0 2023-06-13 11:53:56 +03:00
64 changed files with 2293 additions and 466 deletions

View File

@@ -0,0 +1,24 @@
name: Analysis
on:
push:
branches:
- main
- dev
pull_request:
types: [opened, synchronize, reopened]
jobs:
sonarcloud:
name: SonarCloud
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

View File

@@ -0,0 +1,39 @@
name: Tests
on:
push:
branches:
- main
tags-ignore:
- v*
pull_request:
jobs:
test:
name: Build and Test
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
env:
AGENT_TOOLSDIRECTORY: /opt/hostedtoolcache
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions build
- name: Test with tox
run: tox
- name: Build
run: python -m build
- uses: actions/upload-artifact@v3
with:
name: Artifacts
path: dist/*

10
.gitignore vendored
View File

@@ -161,8 +161,10 @@ cython_debug/
#.idea/
# Project
venv
venv_linux
venv_windows
venv/
venv_linux/
venv_windows/
.vscode
.vscode/
tests/.tmp/

View File

@@ -3,6 +3,15 @@
"extends": [
"config:base"
],
"baseBranches": [
"dev"
],
"pip_requirements": {
"fileMatch": [
"requirements/.*\\.txt$"
],
"enabled": true
},
"packageRules": [
{
"matchUpdateTypes": [

View File

@@ -1,2 +1,86 @@
# LibBotUniversal
<h1 align="center">LibBotUniversal</h1>
<p align="center">
<a href="https://git.end-play.xyz/profitroll/LibBotUniversal/src/branch/master/LICENSE"><img alt="PyPI - License" src="https://img.shields.io/pypi/l/libbot">
<a href="https://git.end-play.xyz/profitroll/LibBotUniversal/releases/latest"><img alt="Gitea Release" src="https://img.shields.io/gitea/v/release/profitroll/LibBotUniversal?gitea_url=https%3A%2F%2Fgit.end-play.xyz"></a>
<a href="https://pypi.org/project/libbot/"><img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/libbot"></a>
<a href="https://git.end-play.xyz/profitroll/LibBotUniversal"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
</p>
Handy library for Telegram/Discord bots development.
## Getting started
There are different sub-packages available:
* pyrogram - Telegram bots with Pyrogram's fork "Pyrofork"
* pycord - Discord bots with Pycord
* speed - Performance improvements
* dev - Dependencies for package development purposes
You can freely choose any sub-package you want, as well as add multiple (comma-separated) or none at all.
```shell
# Only general features
pip install libbot
# Only with Pyrogram
pip install libbot[pyrogram]
# With Pycord and Performance improvements
pip install libbot[pycord,speed]
```
## Examples
### Pyrogram
```python
from libbot.pyrogram import PyroClient
def main():
client = PyroClient(scheduler=scheduler)
try:
client.run()
except KeyboardInterrupt:
print("Shutting down...")
finally:
if client.scheduler is not None:
client.scheduler.shutdown()
exit()
if __name__ == "__main__":
main()
```
### Pycord
```python
from discord import Intents
from libbot import sync
from libbot.pycord import PycordBot
async def main():
intents = Intents.default()
bot = PycordBot(intents=intents)
bot.load_extension("cogs")
try:
await bot.start(sync.config_get("bot_token", "bot"))
except KeyboardInterrupt:
logger.warning("Shutting down...")
await bot.close()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
```
## Config examples
For bot config examples please check the examples directory. Without a valid config file, the bot won't start at all, so you need to make sure the correct config file is used.

21
examples/commands.json Normal file
View File

@@ -0,0 +1,21 @@
{
"help": {
"scopes": [
{
"name": "BotCommandScopeDefault"
},
{
"name": "BotCommandScopeChat",
"chat_id": "owner"
}
]
},
"shutdown": {
"scopes": [
{
"name": "BotCommandScopeChat",
"chat_id": "owner"
}
]
}
}

View File

@@ -0,0 +1,13 @@
{
"locale": "en",
"debug": false,
"bot": {
"owners": [
0
],
"debug_guilds": [
0
],
"bot_token": ""
}
}

View File

@@ -0,0 +1,38 @@
{
"locale": "en",
"bot": {
"owner": 0,
"api_id": 0,
"api_hash": "",
"bot_token": "",
"workers": 1,
"max_concurrent_transmissions": 1,
"scoped_commands": true
},
"reports": {
"chat_id": "owner"
},
"disabled_plugins": [],
"commands": {
"help": {
"scopes": [
{
"name": "BotCommandScopeDefault"
},
{
"name": "BotCommandScopeChat",
"chat_id": "owner"
}
]
},
"shutdown": {
"scopes": [
{
"name": "BotCommandScopeChat",
"chat_id": "owner"
}
]
}
}
}

23
examples/locale.json Normal file
View File

@@ -0,0 +1,23 @@
{
"metadata": {
"flag": "🇬🇧",
"name": "English",
"codes": [
"en"
]
},
"bot": {
"name": "Your Bot",
"about": "I'm a your bot. Nice to meet you!",
"description": "I'm just your bot. Yet nice to meet you!"
},
"commands": {
"help": "Show help message"
},
"messages": {
"help": "Sample Text"
},
"callbacks": {
"sample": "This button is working!"
}
}

View File

@@ -1,7 +0,0 @@
__name__ = "libbot"
__version__ = "0.7"
__license__ = "GPL3"
__author__ = "Profitroll"
from .__main__ import *
from . import sync

View File

@@ -1,93 +0,0 @@
from pathlib import Path
from typing import Any, Union
import aiofiles
try:
from ujson import dumps, loads
except ImportError:
from json import dumps, loads
from libbot.sync import nested_set
async def json_read(path: Union[str, Path]) -> Any:
"""Read contents of a JSON file
### Args:
* path (`Union[str, Path]`): Path-like object or path as a string
### Returns:
* `Any`: File contents
"""
async with aiofiles.open(str(path), mode="r", encoding="utf-8") as f:
data = await f.read()
return loads(data)
async def json_write(data: Any, path: Union[str, Path]) -> None:
"""Write contents to a JSON file
### Args:
* data (`Any`): Contents to write. Must be a JSON serializable
* path (`Union[str, Path]`): Path-like object or path as a string of a destination
"""
async with aiofiles.open(str(path), mode="w", encoding="utf-8") as f:
await f.write(
dumps(data, ensure_ascii=False, escape_forward_slashes=False, indent=4)
)
async def config_get(
key: str, *path: str, config_file: Union[str, Path] = "config.json"
) -> Any:
"""Get a value of the config key by its path provided
For example, `foo.bar.key` has a path of `"foo", "bar"` and the key `"key"`
### Args:
* key (`str`): Key that contains the value
* *path (`str`): Path to the key that contains the value
* config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Returns:
* `Any`: Key's value
### Example:
Get the "salary" of "Pete" from this JSON structure:
```json
{
"users": {
"Pete": {
"salary": 10.0
}
}
}
```
This can be easily done with the following code:
```python
import libbot
salary = await libbot.config_get("salary", "users", "Pete")
```
"""
this_key = await json_read(config_file)
for dict_key in path:
this_key = this_key[dict_key]
return this_key[key]
async def config_set(
key: str, value: Any, *path: str, config_file: Union[str, Path] = "config.json"
) -> None:
"""Set config's key by its path to the value
### Args:
* key (`str`): Key that leads to the value
* value (`Any`): Any JSON serializable data
* *path (`str`): Path to the key of the target
* config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
"""
await json_write(
nested_set(await json_read(config_file), value, *(*path, key)), config_file
)
return

View File

@@ -1,113 +0,0 @@
from os import listdir
from pathlib import Path
from typing import Any, Dict
from libbot import config_get, json_read, sync
async def _(key: str, *args: str, locale: str = sync.config_get("locale")) -> Any:
"""Get value of locale string
### Args:
* key (`str`): The last key of the locale's keys path
* *args (`list`): Path to key like: `dict[args][key]`
* locale (`str`): Locale to looked up in. Defaults to config's `"locale"` value
### Returns:
* `Any`: Value of provided locale key. Is usually `str`, `dict` or `list`
"""
if locale is None:
locale = sync.config_get("locale")
try:
this_dict = await json_read(
Path(f'{await config_get("locale", "locations")}/{locale}.json')
)
except FileNotFoundError:
try:
this_dict = await json_read(
Path(
f'{await config_get("locale", "locations")}/{await config_get("locale")}.json'
)
)
except FileNotFoundError:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
this_key = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
return this_key[key]
except KeyError:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
async def in_all_locales(key: str, *args: str) -> list:
"""Get value of the provided key and path in all available locales
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
### Returns:
* `list`: List of values in all locales
"""
output = []
files_locales = listdir(await config_get("locale", "locations"))
valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales]
for lc in valid_locales:
try:
this_dict = await json_read(
Path(f'{await config_get("locale", "locations")}/{lc}.json')
)
except FileNotFoundError:
continue
this_key = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
output.append(this_key[key])
except KeyError:
continue
return output
async def in_every_locale(key: str, *args: str) -> Dict[str, Any]:
"""Get value of the provided key and path in every available locale with locale tag
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
### Returns:
* `Dict[str, Any]`: Locale is a key and it's value from locale file is a value
"""
output = {}
files_locales = listdir(await config_get("locale", "locations"))
valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales]
for lc in valid_locales:
try:
this_dict = await json_read(
Path(f'{await config_get("locale", "locations")}/{lc}.json')
)
except FileNotFoundError:
continue
this_key = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
output[lc] = this_key[key]
except KeyError:
continue
return output

View File

@@ -1,112 +0,0 @@
from os import listdir
from pathlib import Path
from typing import Any, Dict
from libbot import sync
from libbot.sync import config_get, json_read
def _(key: str, *args: str, locale: str = sync.config_get("locale")) -> Any:
"""Get value of locale string
### Args:
* key (`str`): The last key of the locale's keys path
* *args (`list`): Path to key like: `dict[args][key]`
* locale (`str`): Locale to looked up in. Defaults to config's `"locale"` value
### Returns:
* `Any`: Value of provided locale key. Is usually `str`, `dict` or `list`
"""
if locale is None:
locale = sync.config_get("locale")
try:
this_dict = json_read(
Path(f'{config_get("locale", "locations")}/{locale}.json')
)
except FileNotFoundError:
try:
this_dict = json_read(
Path(f'{config_get("locale", "locations")}/{config_get("locale")}.json')
)
except FileNotFoundError:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
this_key = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
return this_key[key]
except KeyError:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
def in_all_locales(key: str, *args: str) -> list:
"""Get value of the provided key and path in all available locales
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
### Returns:
* `list`: List of values in all locales
"""
output = []
files_locales = listdir(config_get("locale", "locations"))
valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales]
for lc in valid_locales:
try:
this_dict = json_read(
Path(f'{config_get("locale", "locations")}/{lc}.json')
)
except FileNotFoundError:
continue
this_key = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
output.append(this_key[key])
except KeyError:
continue
return output
def in_every_locale(key: str, *args: str) -> Dict[str, Any]:
"""Get value of the provided key and path in every available locale with locale tag
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`list`): Path to key like: `dict[args][key]`.
### Returns:
* `Dict[str, Any]`: Locale is a key and it's value from locale file is a value
"""
output = {}
files_locales = listdir(config_get("locale", "locations"))
valid_locales = [".".join(entry.split(".")[:-1]) for entry in files_locales]
for lc in valid_locales:
try:
this_dict = json_read(
Path(f'{config_get("locale", "locations")}/{lc}.json')
)
except FileNotFoundError:
continue
this_key = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
output[lc] = this_key[key]
except KeyError:
continue
return output

View File

@@ -1,110 +0,0 @@
from pathlib import Path
from typing import Any, Union
try:
from ujson import dumps, loads
except ImportError:
from json import dumps, loads
def json_read(path: Union[str, Path]) -> Any:
"""Read contents of a JSON file
### Args:
* path (`Union[str, Path]`): Path-like object or path as a string
### Returns:
* `Any`: File contents
"""
with open(str(path), mode="r", encoding="utf-8") as f:
data = f.read()
return loads(data)
def json_write(data: Any, path: Union[str, Path]) -> None:
"""Write contents to a JSON file
### Args:
* data (`Any`): Contents to write. Must be a JSON serializable
* path (`Union[str, Path]`): Path-like object or path as a string of a destination
"""
with open(str(path), mode="w", encoding="utf-8") as f:
f.write(dumps(data, ensure_ascii=False, escape_forward_slashes=False, indent=4))
def nested_set(target: dict, value: Any, *path: str, create_missing=True) -> dict:
"""Set the key by its path to the value
### Args:
* target (`dict`): Dictionary to perform modifications on
* value (`Any`): Any data
* *path (`str`): Path to the key of the target
* create_missing (`bool`, *optional*): Create keys on the way if they're missing. Defaults to `True`
### Returns:
* `dict`: Changed dictionary
"""
d = target
for key in path[:-1]:
if key in d:
d = d[key]
elif create_missing:
d = d.setdefault(key, {})
else:
return target
if path[-1] in d or create_missing:
d[path[-1]] = value
return target
def config_get(
key: str, *path: str, config_file: Union[str, Path] = "config.json"
) -> Any:
"""Get a value of the config key by its path provided
For example, `foo.bar.key` has a path of `"foo", "bar"` and the key `"key"`
### Args:
* key (`str`): Key that contains the value
* *path (`str`): Path to the key that contains the value
* config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Returns:
* `Any`: Key's value
### Example:
Get the "salary" of "Pete" from this JSON structure:
```json
{
"users": {
"Pete": {
"salary": 10.0
}
}
}
```
This can be easily done with the following code:
```python
import libbot
salary = libbot.sync.config_get("salary", "users", "Pete")
```
"""
this_key = json_read(config_file)
for dict_key in path:
this_key = this_key[dict_key]
return this_key[key]
def config_set(
key: str, value: Any, *path: str, config_file: Union[str, Path] = "config.json"
) -> None:
"""Set config's key by its path to the value
### Args:
* key (`str`): Key that leads to the value
* value (`Any`): Any JSON serializable data
* *path (`str`): Path to the key of the target
* config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
"""
json_write(nested_set(json_read(config_file), value, *(*path, key)), config_file)
return

View File

@@ -1,47 +1,72 @@
[build-system]
requires = ["setuptools>=62.6,<66"]
requires = ["setuptools>=62.6", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "libbot"
version = "0.7"
dynamic = ["version", "dependencies", "optional-dependencies"]
authors = [{ name = "Profitroll" }]
description = "Universal bot library with functions needed for basic Discord/Telegram bot development."
readme = "README.md"
requires-python = ">=3.7"
license = { text = "GPL3" }
requires-python = ">=3.11"
license = { text = "GPLv3" }
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Utilities",
]
dependencies = ["aiofiles~=23.1.0"]
[project.optional-dependencies]
pycord = ["py-cord>=2.0.0"]
pyrogram = ["pyrogram>=2.0.0"]
speed = ["ujson==5.7.0"]
[tool.setuptools.dynamic]
version = { attr = "libbot.__version__" }
dependencies = { file = "requirements/_.txt" }
[tool.setuptools.dynamic.optional-dependencies]
dev = { file = "requirements/dev.txt" }
pycord = { file = "requirements/pycord.txt" }
pyrogram = { file = "requirements/pyrogram.txt" }
speed = { file = "requirements/speed.txt" }
[project.urls]
Source = "https://git.end-play.xyz/profitroll/LibBotUniversal"
Documentation = "https://git.end-play.xyz/profitroll/LibBotUniversal/wiki"
Tracker = "https://git.end-play.xyz/profitroll/LibBotUniversal/issues"
[tool.setuptools]
packages = ["libbot", "libbot.i18n", "libbot.sync", "libbot.i18n.sync"]
[tool.setuptools_scm]
[tool.setuptools.packages.find]
where = ["src"]
[tool.black]
target-version = ['py37', 'py38', 'py39', 'py310', 'py311']
line-length = 108
target-version = ["py311", "py312", "py313"]
[tool.isort]
profile = "black"
[tool.pytest.ini_options]
minversion = "6.0"
python_files = ["test_*.py"]
pythonpath = "."
testpaths = ["tests"]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
[tool.mypy]
namespace_packages = true
install_types = true
strict = true
show_error_codes = true
[tool.pylint]
disable = ["line-too-long"]
[tool.pylint.main]
extension-pkg-whitelist = ["ujson"]
py-version = 3.11
[tool.coverage.run]
source = ["libbot"]

1
requirements/_.txt Normal file
View File

@@ -0,0 +1 @@
aiofiles>=23.0.0

11
requirements/dev.txt Normal file
View File

@@ -0,0 +1,11 @@
black==24.10.0
build==1.2.2.post1
isort==5.13.2
mypy==1.14.0
pylint==3.3.3
pytest-asyncio==0.25.0
pytest-cov==6.0.0
pytest==8.3.4
tox==4.23.2
types-aiofiles==24.1.0.20241221
types-ujson==5.10.0.20240515

2
requirements/pycord.txt Normal file
View File

@@ -0,0 +1,2 @@
apscheduler~=3.11.0
py-cord~=2.6.0

View File

@@ -0,0 +1,2 @@
apscheduler~=3.11.0
pyrofork~=2.3.32

1
requirements/speed.txt Normal file
View File

@@ -0,0 +1 @@
ujson~=5.10.0

View File

@@ -1,3 +0,0 @@
[metadata]
description_file=README.md
license_files=LICENSE

View File

@@ -1,4 +0,0 @@
from setuptools import setup
if __name__ == "__main__":
setup()

2
sonar-project.properties Normal file
View File

@@ -0,0 +1,2 @@
sonar.projectKey=profitroll_libbot
sonar.organization=profitroll

5
src/libbot/__init__.py Normal file
View File

@@ -0,0 +1,5 @@
__version__ = "4.0.0"
__license__ = "GPL3"
__author__ = "Profitroll"
from . import utils, errors, i18n, pycord, pyrogram

View File

@@ -0,0 +1 @@
from .config import ConfigKeyError, ConfigValueError

View File

@@ -0,0 +1,37 @@
from typing import Any, List, Optional
class ConfigKeyError(Exception):
"""Raised when config key is not found.
### Attributes:
* key (`str | List[str]`): Missing config key.
"""
def __init__(self, key: str | List[str]) -> None:
self.key: str | List[str] = key
super().__init__(
f"Config key {'.'.join(key) if isinstance(key, list) else key} is missing. Please set in your config file."
)
def __str__(self):
return f"Config key {'.'.join(self.key) if isinstance(self.key, list) else self.key} is missing. Please set in your config file."
class ConfigValueError(Exception):
"""Raised when config key's value is invalid.
### Attributes:
* key (`str | List[str]`): Invalid config key.
* value (`Optional[Any]`): Key's correct value.
"""
def __init__(self, key: str | List[str], value: Optional[Any] = None) -> None:
self.key: str | List[str] = key
self.value: Optional[Any] = value
super().__init__(
f"Config key {'.'.join(key) if isinstance(key, list) else key} has invalid value. {f'Must be {value}. ' if value else ''}Please set in your config file."
)
def __str__(self):
return f"Config key {'.'.join(self.key) if isinstance(self.key, list) else self.key} has invalid value. {f'Must be {self.value}. ' if self.value else ''}Please set in your config file."

View File

@@ -0,0 +1,2 @@
from ._functions import _, in_all_locales, in_every_locale
from .classes import BotLocale

View File

@@ -0,0 +1,232 @@
from os import listdir, PathLike
from pathlib import Path
from typing import Any, Dict, List
from ..utils.config import config_get
from ..utils.json import json_read
from ..utils.syncs import asyncable
def _get_valid_locales(locales_root: str | PathLike[str]) -> List[str]:
return [".".join(entry.split(".")[:-1]) for entry in listdir(locales_root)]
@asyncable
def _(
key: str,
*args: str,
locale: str | None = "en",
locales_root: str | Path = Path("locale"),
) -> Any:
"""Get value of locale string
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`str`): Path to key like: `dict[args][key]`.
* locale (`str | None`): Locale to looked up in. Defaults to `"en"`.
* locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### Returns:
* `Any`: Value of provided locale key. Is usually `str`, `Dict[str, Any]` or `List[Any]`
"""
if locale is None:
locale: str = config_get("locale")
try:
this_dict: Dict[str, Any] = json_read(Path(f"{locales_root}/{locale}.json"))
except FileNotFoundError:
try:
this_dict: Dict[str, Any] = json_read(Path(f'{locales_root}/{config_get("locale")}.json'))
except FileNotFoundError:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
this_key: Dict[str, Any] = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
return this_key[key]
except KeyError:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
@_.asynchronous
async def _(
key: str,
*args: str,
locale: str | None = "en",
locales_root: str | Path = Path("locale"),
) -> Any:
"""Get value of locale string
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`str`): Path to key like: `dict[args][key]`.
* locale (`str | None`): Locale to looked up in. Defaults to `"en"`.
* locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### Returns:
* `Any`: Value of provided locale key. Is usually `str`, `Dict[str, Any]` or `List[Any]`
"""
locale: str = config_get("locale") if locale is None else locale
try:
this_dict: Dict[str, Any] = await json_read(Path(f"{locales_root}/{locale}.json"))
except FileNotFoundError:
try:
this_dict: Dict[str, Any] = await json_read(
Path(f'{locales_root}/{await config_get("locale")}.json')
)
except FileNotFoundError:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
this_key: Dict[str, Any] = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
return this_key[key]
except KeyError:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
@asyncable
def in_all_locales(key: str, *args: str, locales_root: str | Path = Path("locale")) -> List[Any]:
"""Get value of the provided key and path in all available locales
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`str`): Path to key like: `dict[args][key]`.
* locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### Returns:
* `List[Any]`: List of values in all locales
"""
output: List[Any] = []
for locale in _get_valid_locales(locales_root):
try:
this_dict: Dict[str, Any] = json_read(Path(f"{locales_root}/{locale}.json"))
except FileNotFoundError:
continue
this_key: Dict[str, Any] = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
output.append(this_key[key])
except KeyError:
continue
return output
@in_all_locales.asynchronous
async def in_all_locales(key: str, *args: str, locales_root: str | Path = Path("locale")) -> List[Any]:
"""Get value of the provided key and path in all available locales
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`str`): Path to key like: `dict[args][key]`.
* locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### Returns:
* `List[Any]`: List of values in all locales
"""
output: List[Any] = []
for locale in _get_valid_locales(locales_root):
try:
this_dict: Dict[str, Any] = await json_read(Path(f"{locales_root}/{locale}.json"))
except FileNotFoundError:
continue
this_key: Dict[str, Any] = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
output.append(this_key[key])
except KeyError:
continue
return output
@asyncable
def in_every_locale(
key: str, *args: str, locales_root: str | Path = Path("locale")
) -> Dict[str, Any]:
"""Get value of the provided key and path in every available locale with locale tag
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`str`): Path to key like: `dict[args][key]`.
* locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### Returns:
* `Dict[str, Any]`: Locale is a key, and it's value from locale file is a value
"""
output: Dict[str, Any] = {}
for locale in _get_valid_locales(locales_root):
try:
this_dict: Dict[str, Any] = json_read(Path(f"{locales_root}/{locale}.json"))
except FileNotFoundError:
continue
this_key: Dict[str, Any] = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
output[locale] = this_key[key]
except KeyError:
continue
return output
@in_every_locale.asynchronous
async def in_every_locale(
key: str, *args: str, locales_root: str | Path = Path("locale")
) -> Dict[str, Any]:
"""Get value of the provided key and path in every available locale with locale tag
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`str`): Path to key like: `dict[args][key]`.
* locales_root (`str | Path`, *optional*): Folder where locales are located. Defaults to `Path("locale")`.
### Returns:
* `Dict[str, Any]`: Locale is a key, and it's value from locale file is a value
"""
output: Dict[str, Any] = {}
for locale in _get_valid_locales(locales_root):
try:
this_dict: Dict[str, Any] = await json_read(Path(f"{locales_root}/{locale}.json"))
except FileNotFoundError:
continue
this_key: Dict[str, Any] = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
output[locale] = this_key[key]
except KeyError:
continue
return output

View File

@@ -0,0 +1 @@
from .bot_locale import BotLocale

View File

@@ -0,0 +1,124 @@
from os import listdir
from pathlib import Path
from typing import Any, Dict, List
from ...utils.config import config_get
from ...utils.json import json_read
class BotLocale:
"""Small addon that can be used by bot clients' classes in order to minimize I/O"""
def __init__(
self,
default_locale: str | None = "en",
locales_root: str | Path = Path("locale"),
) -> None:
if isinstance(locales_root, str):
locales_root = Path(locales_root)
elif not isinstance(locales_root, Path):
raise TypeError("'locales_root' must be a valid path or path-like object")
files_locales: List[str] = listdir(locales_root)
valid_locales: List[str] = [".".join(entry.split(".")[:-1]) for entry in files_locales]
self.default: str = config_get("locale") if default_locale is None else default_locale
self.locales: Dict[str, Any] = {}
for locale in valid_locales:
self.locales[locale] = json_read(Path(f"{locales_root}/{locale}.json"))
def _(self, key: str, *args: str, locale: str | None = None) -> Any:
"""Get value of locale string
### Args:
* key (`str`): The last key of the locale's keys path
* *args (`str`): Path to key like: `dict[args][key]`
* locale (`str | None`, *optional*): Locale to looked up in. Defaults to config's `"locale"` value
### Returns:
* `Any`: Value of provided locale key. Is usually `str`, `Dict[str, Any]` or `List[Any]`
"""
if locale is None:
locale: str = self.default
try:
this_dict: Dict[str, Any] = self.locales[locale]
except KeyError:
try:
this_dict: Dict[str, Any] = self.locales[self.default]
except KeyError:
return (
f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
)
this_key: Dict[str, Any] = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
return this_key[key]
except KeyError:
return f'⚠️ Locale in config is invalid: could not get "{key}" in {args} from locale "{locale}"'
def in_all_locales(self, key: str, *args: str) -> List[Any]:
"""Get value of the provided key and path in all available locales
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`str`): Path to key like: `dict[args][key]`.
### Returns:
* `List[Any]`: List of values in all locales
"""
output: List[Any] = []
for name, locale in self.locales.items():
try:
this_dict: Dict[str, Any] = locale
except KeyError:
continue
this_key: Dict[str, Any] = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
output.append(this_key[key])
except KeyError:
continue
return output
def in_every_locale(self, key: str, *args: str) -> Dict[str, Any]:
"""Get value of the provided key and path in every available locale with locale tag
### Args:
* key (`str`): The last key of the locale's keys path.
* *args (`str`): Path to key like: `dict[args][key]`.
### Returns:
* `Dict[str, Any]`: Locale is a key, and it's value from locale file is a value
"""
output: Dict[str, Any] = {}
for name, locale in self.locales.items():
try:
this_dict: Dict[str, Any] = locale
except KeyError:
continue
this_key: Dict[str, Any] = this_dict
for dict_key in args:
this_key = this_key[dict_key]
try:
output[name] = this_key[key]
except KeyError:
continue
return output

View File

View File

@@ -0,0 +1 @@
from .bot import PycordBot

View File

@@ -0,0 +1,73 @@
import logging
from pathlib import Path
from typing import Any, Dict
from typing_extensions import override
try:
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.schedulers.background import BackgroundScheduler
from discord import Bot
except ImportError as exc:
raise ImportError("You need to install libbot[pycord] in order to use this class.") from exc
try:
from ujson import loads
except ImportError:
from json import loads
from ...i18n.classes import BotLocale
logger = logging.getLogger(__name__)
class PycordBot(Bot):
@override
def __init__(
self,
*args,
config: Dict[str, Any] | None = None,
config_path: str | Path = Path("config.json"),
locales_root: str | Path | None = None,
scheduler: AsyncIOScheduler | BackgroundScheduler | None = None,
**kwargs,
):
if config is None:
with open(config_path, "r", encoding="utf-8") as f:
self.config: dict = loads(f.read())
else:
self.config = config
super().__init__(
debug_guilds=(self.config["bot"]["debug_guilds"] if self.config["debug"] else None),
owner_ids=self.config["bot"]["owners"],
*args,
**kwargs,
)
self.bot_locale: BotLocale = BotLocale(
default_locale=self.config["locale"],
locales_root=(Path("locale") if locales_root is None else locales_root),
)
self.default_locale: str = self.bot_locale.default
self.locales: Dict[str, Any] = self.bot_locale.locales
self._ = self.bot_locale._
self.in_all_locales = self.bot_locale.in_all_locales
self.in_every_locale = self.bot_locale.in_every_locale
self.scheduler: AsyncIOScheduler | BackgroundScheduler | None = scheduler
@override
async def start(self, token: str, reconnect: bool = True, scheduler_start: bool = True) -> None:
if self.scheduler is not None and scheduler_start:
self.scheduler.start()
await super().start(token, reconnect=reconnect)
@override
async def close(self, scheduler_shutdown: bool = True, scheduler_wait: bool = True) -> None:
if self.scheduler is not None and scheduler_shutdown:
self.scheduler.shutdown(scheduler_wait)
await super().close()

View File

View File

@@ -0,0 +1,3 @@
from .client import PyroClient
from .command import PyroCommand
from .commandset import CommandSet

View File

@@ -0,0 +1,387 @@
import asyncio
import logging
import sys
from datetime import datetime, timedelta
from os import cpu_count, getpid
from pathlib import Path
from time import time
from typing import Any, Dict, List
from typing_extensions import override
try:
import pyrogram
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.schedulers.background import BackgroundScheduler
from pyrogram.client import Client
from pyrogram.errors import BadRequest
from pyrogram.handlers.message_handler import MessageHandler
from pyrogram.raw.all import layer
from pyrogram.types import (
BotCommand,
BotCommandScopeAllChatAdministrators,
BotCommandScopeAllGroupChats,
BotCommandScopeAllPrivateChats,
BotCommandScopeChat,
BotCommandScopeChatAdministrators,
BotCommandScopeChatMember,
BotCommandScopeDefault,
)
except ImportError as exc:
raise ImportError("You need to install libbot[pyrogram] in order to use this class.") from exc
try:
from ujson import dumps, loads
except ImportError:
from json import dumps, loads
from ...i18n.classes import BotLocale
from ...i18n import _
from .command import PyroCommand
from .commandset import CommandSet
logger = logging.getLogger(__name__)
class PyroClient(Client):
@override
def __init__(
self,
name: str = "bot_client",
owner: int | None = None,
config: Dict[str, Any] | None = None,
config_path: str | Path = Path("config.json"),
api_id: int | None = None,
api_hash: str | None = None,
bot_token: str | None = None,
workers: int = min(32, cpu_count() + 4),
locales_root: str | Path | None = None,
plugins_root: str = "plugins",
plugins_exclude: List[str] | None = None,
sleep_threshold: int = 120,
max_concurrent_transmissions: int = 1,
commands_source: Dict[str, dict] | None = None,
scoped_commands: bool | None = None,
i18n_bot_info: bool = False,
scheduler: AsyncIOScheduler | BackgroundScheduler | None = None,
**kwargs,
):
if config is None:
with open(config_path, "r", encoding="utf-8") as f:
self.config: dict = loads(f.read())
else:
self.config = config
super().__init__(
name=name,
api_id=self.config["bot"]["api_id"] if api_id is None else api_id,
api_hash=self.config["bot"]["api_hash"] if api_hash is None else api_hash,
bot_token=self.config["bot"]["bot_token"] if bot_token is None else bot_token,
# Workers should be `min(32, cpu_count() + 4)`, otherwise
# handlers land in another event loop and you won't see them
workers=self.config["bot"]["workers"] if "workers" in self.config["bot"] else workers,
plugins=dict(
root=plugins_root,
exclude=self.config["disabled_plugins"] if plugins_exclude is None else plugins_exclude,
),
sleep_threshold=sleep_threshold,
max_concurrent_transmissions=(
self.config["bot"]["max_concurrent_transmissions"]
if "max_concurrent_transmissions" in self.config["bot"]
else max_concurrent_transmissions
),
**kwargs,
)
self.owner: int = self.config["bot"]["owner"] if owner is None else owner
self.commands: List[PyroCommand] = []
self.commands_source: Dict[str, dict] = (
self.config["commands"] if commands_source is None else commands_source
)
self.scoped_commands: bool = (
self.config["bot"]["scoped_commands"] if scoped_commands is None else scoped_commands
)
self.start_time: float = 0
self.bot_locale: BotLocale = BotLocale(
default_locale=self.config["locale"],
locales_root=(Path("locale") if locales_root is None else locales_root),
)
self.default_locale: str = self.bot_locale.default
self.locales: dict = self.bot_locale.locales
self._ = self.bot_locale._
self.in_all_locales = self.bot_locale.in_all_locales
self.in_every_locale = self.bot_locale.in_every_locale
self.scheduler: AsyncIOScheduler | BackgroundScheduler | None = scheduler
self.scopes_placeholders: Dict[str, int] = {"owner": self.owner}
self.i18n_bot_info: bool = i18n_bot_info
@override
async def start(self, register_commands: bool = True, scheduler_start: bool = True) -> None:
await super().start()
self.start_time = time()
logger.info(
"Bot is running with Pyrogram v%s (Layer %s) and has started as @%s on PID %s.",
pyrogram.__version__,
layer,
self.me.username,
getpid(),
)
if self.i18n_bot_info:
# Register default bot's info
try:
await self.set_bot_info(
name=self._("name", "bot"),
about=self._("about", "bot"),
description=self._("description", "bot"),
lang_code="",
)
logger.info(
"Bot's info for the default locale %s has been updated",
self.default_locale,
)
except KeyError:
logger.warning(
"Default locale %s has incorrect keys or values in bot section",
self.default_locale,
)
# Register bot's info for each available locale
for locale_code in self.locales:
locale = self.locales[locale_code]
if "metadata" not in locale or ("codes" not in locale["metadata"]):
logger.warning(
"Locale %s is missing metadata or metadata.codes key",
locale_code,
)
continue
for code in locale["metadata"]["codes"]:
try:
await self.set_bot_info(
name=locale["bot"]["name"],
about=locale["bot"]["about"],
description=locale["bot"]["description"],
lang_code=code,
)
logger.info(
"Bot's info for the locale %s has been updated",
code,
)
except KeyError:
logger.warning(
"Locale %s has incorrect keys or values in bot section",
locale_code,
)
# Send a message to the bot's reports chat about the startup
try:
await self.send_message(
chat_id=(
self.owner
if self.config["reports"]["chat_id"] == "owner"
else self.config["reports"]["chat_id"]
),
text=f"Bot started PID `{getpid()}`",
)
except BadRequest:
logger.warning("Unable to send message to report chat.")
if self.scheduler is None:
return
# Schedule the task to register all commands
if register_commands:
self.scheduler.add_job(
self.register_commands,
trigger="date",
run_date=datetime.now() + timedelta(seconds=5),
kwargs={"command_sets": await self.collect_commands()},
)
if scheduler_start:
self.scheduler.start()
@override
async def stop(
self, exit_completely: bool = True, scheduler_shutdown: bool = True, scheduler_wait: bool = True
) -> None:
try:
await self.send_message(
chat_id=(
self.owner
if self.config["reports"]["chat_id"] == "owner"
else self.config["reports"]["chat_id"]
),
text=f"Bot stopped with PID `{getpid()}`",
)
await asyncio.sleep(0.5)
except BadRequest:
logger.warning("Unable to send message to report chat.")
if self.scheduler is not None and scheduler_shutdown:
self.scheduler.shutdown(scheduler_wait)
await super().stop()
logger.warning("Bot stopped with PID %s.", getpid())
if exit_completely:
try:
sys.exit()
except SystemExit as exc:
raise SystemExit("Bot has been shut down, this is not an application error!") from exc
async def collect_commands(self) -> List[CommandSet] | None:
"""Gather list of the bot's commands
### Returns:
* `List[CommandSet]`: List of the commands' sets.
"""
command_sets = None
# If config's bot.scoped_commands is true - more complicated
# scopes system will be used instead of simple global commands
if self.scoped_commands:
scopes = {}
command_sets = []
# Iterate through all commands in config
for command, contents in self.commands_source.items():
# Iterate through all scopes of a command
for scope in contents["scopes"]:
if dumps(scope) not in scopes:
scopes[dumps(scope)] = {"_": []}
# Add command to the scope's flattened key in scopes dict
scopes[dumps(scope)]["_"].append(BotCommand(command, _(command, "commands")))
for locale, string in (self.in_every_locale(command, "commands")).items():
if locale not in scopes[dumps(scope)]:
scopes[dumps(scope)][locale] = []
scopes[dumps(scope)][locale].append(BotCommand(command, string))
# Iterate through all scopes and its commands
for scope, locales in scopes.items():
# Make flat key a dict again
scope_dict = loads(scope)
# Replace "owner" in the bot scope with owner's id
for placeholder, chat_id in self.scopes_placeholders.items():
if "chat_id" in scope_dict and scope_dict["chat_id"] == placeholder:
scope_dict["chat_id"] = chat_id
# Create object with the same name and args from the dict
try:
scope_obj = globals()[scope_dict["name"]](
**{key: value for key, value in scope_dict.items() if key != "name"}
)
except NameError:
logger.error(
"Could not register commands of the scope '%s' due to an invalid scope class provided!",
scope_dict["name"],
)
continue
except TypeError:
logger.error(
"Could not register commands of the scope '%s' due to an invalid class arguments provided!",
scope_dict["name"],
)
continue
# Add set of commands to the list of the command sets
for locale, commands in locales.items():
if locale == "_":
command_sets.append(CommandSet(commands, scope=scope_obj, language_code=""))
continue
command_sets.append(CommandSet(commands, scope=scope_obj, language_code=locale))
logger.info("Registering the following command sets: %s", command_sets)
else:
# This part here looks into the handlers and looks for commands
# in it, if there are any. Then adds them to self.commands
for handler in self.dispatcher.groups[0]:
if isinstance(handler, MessageHandler) and (
hasattr(handler.filters, "base") or hasattr(handler.filters, "other")
):
for entry in [handler.filters.base, handler.filters.other]:
if hasattr(entry, "commands"):
for command in entry.commands:
logger.info("I see a command %s in my filters", command)
self.add_command(command)
return command_sets
def add_command(
self,
command: str,
) -> None:
"""Add command to the bot's internal commands list
### Args:
* command (`str`)
"""
self.commands.append(
PyroCommand(
command,
_(command, "commands"),
)
)
logger.info(
"Added command '%s' to the bot's internal commands list",
command,
)
async def register_commands(self, command_sets: List[CommandSet] | None = None) -> None:
"""Register commands stored in bot's 'commands' attribute"""
if command_sets is None:
commands = [
BotCommand(command=command.command, description=command.description)
for command in self.commands
]
logger.info("Registering commands %s with a default scope 'BotCommandScopeDefault'", commands)
await self.set_bot_commands(commands)
return
for command_set in command_sets:
logger.info(
"Registering command set with commands %s and scope '%s' (%s)",
command_set.commands,
command_set.scope,
command_set.language_code,
)
await self.set_bot_commands(
command_set.commands,
command_set.scope,
language_code=command_set.language_code,
)
async def remove_commands(self, command_sets: List[CommandSet] | None = None) -> None:
"""Remove commands stored in bot's 'commands' attribute"""
if command_sets is None:
logger.info("Removing commands with a default scope 'BotCommandScopeDefault'")
await self.delete_bot_commands(BotCommandScopeDefault())
return
for command_set in command_sets:
logger.info(
"Removing command set with scope '%s' (%s)",
command_set.scope,
command_set.language_code,
)
await self.delete_bot_commands(
command_set.scope,
language_code=command_set.language_code,
)

View File

@@ -0,0 +1,9 @@
from dataclasses import dataclass
@dataclass
class PyroCommand:
"""Command stored in PyroClient's 'commands' attribute"""
command: str
description: str

View File

@@ -0,0 +1,33 @@
from dataclasses import dataclass
from typing import List
try:
from pyrogram.types import (
BotCommand,
BotCommandScopeAllChatAdministrators,
BotCommandScopeAllGroupChats,
BotCommandScopeAllPrivateChats,
BotCommandScopeChat,
BotCommandScopeChatAdministrators,
BotCommandScopeChatMember,
BotCommandScopeDefault,
)
except ImportError as exc:
raise ImportError("You need to install libbot[pyrogram] in order to use this class.") from exc
@dataclass
class CommandSet:
"""Command stored in PyroClient's 'commands' attribute"""
commands: List[BotCommand]
scope: (
BotCommandScopeDefault
| BotCommandScopeAllPrivateChats
| BotCommandScopeAllGroupChats
| BotCommandScopeAllChatAdministrators
| BotCommandScopeChat
| BotCommandScopeChatAdministrators
| BotCommandScopeChatMember
) = BotCommandScopeDefault
language_code: str = ""

View File

@@ -0,0 +1,3 @@
from . import misc
from .config import config_get, config_set, config_delete
from .json import json_read, json_write

View File

@@ -0,0 +1 @@
from ._functions import config_get, config_set, config_delete

View File

@@ -0,0 +1,183 @@
from pathlib import Path
from typing import Any, Dict
from ..json import json_read, json_write
from ..misc import nested_delete, nested_set
from ..syncs import asyncable
try:
from ujson import dumps, loads
except ImportError:
from json import dumps, loads
DEFAULT_CONFIG_LOCATION: str = "config.json"
@asyncable
def config_get(key: str, *path: str, config_file: str | Path = DEFAULT_CONFIG_LOCATION) -> Any:
"""Get a value of the config key by its path provided
For example, `foo.bar.key` has a path of `"foo", "bar"` and the key `"key"`
### Args:
* key (`str`): Key that contains the value
* *path (`str`): Path to the key that contains the value
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Returns:
* `Any`: Key's value
### Example:
Get the "salary" of "Pete" from this JSON structure:
```json
{
"users": {
"Pete": {
"salary": 10.0
}
}
}
```
This can be easily done with the following code:
```python
import libbot
salary = libbot.sync.config_get("salary", "users", "Pete")
```
"""
this_key: Dict[str, Any] = json_read(config_file)
for dict_key in path:
this_key = this_key[dict_key]
return this_key[key]
@config_get.asynchronous
async def config_get(key: str, *path: str, config_file: str | Path = DEFAULT_CONFIG_LOCATION) -> Any:
"""Get a value of the config key by its path provided
For example, `foo.bar.key` has a path of `"foo", "bar"` and the key `"key"`
### Args:
* key (`str`): Key that contains the value
* *path (`str`): Path to the key that contains the value
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Returns:
* `Any`: Key's value
### Example:
Get the "salary" of "Pete" from this JSON structure:
```json
{
"users": {
"Pete": {
"salary": 10.0
}
}
}
```
This can be easily done with the following code:
```python
import libbot
salary = await libbot.config_get("salary", "users", "Pete")
```
"""
this_key: Dict[str, Any] = await json_read(config_file)
for dict_key in path:
this_key = this_key[dict_key]
return this_key[key]
@asyncable
def config_set(key: str, value: Any, *path: str, config_file: str | Path = DEFAULT_CONFIG_LOCATION) -> None:
"""Set config's key by its path to the value
### Args:
* key (`str`): Key that leads to the value
* value (`Any`): Any JSON serializable data
* *path (`str`): Path to the key of the target
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Raises:
* `KeyError`: Key is not found under path provided
"""
json_write(nested_set(json_read(config_file), value, *(*path, key)), config_file)
@config_set.asynchronous
async def config_set(
key: str, value: Any, *path: str, config_file: str | Path = DEFAULT_CONFIG_LOCATION
) -> None:
"""Set config's key by its path to the value
### Args:
* key (`str`): Key that leads to the value
* value (`Any`): Any JSON serializable data
* *path (`str`): Path to the key of the target
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Raises:
* `KeyError`: Key is not found under path provided
"""
await json_write(nested_set(await json_read(config_file), value, *(*path, key)), config_file)
@asyncable
def config_delete(
key: str,
*path: str,
missing_ok: bool = False,
config_file: str | Path = DEFAULT_CONFIG_LOCATION,
) -> None:
"""Set config's key by its path
### Args:
* key (`str`): Key to delete
* *path (`str`): Path to the key of the target
* missing_ok (`bool`): Do not raise an exception if the key is missing. Defaults to `False`
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Raises:
* `KeyError`: Key is not found under path provided and `missing_ok` is `False`
"""
config_data: Dict[str, Any] = json_read(config_file)
try:
nested_delete(config_data, *(*path, key))
except KeyError as exc:
if not missing_ok:
raise exc from exc
json_write(config_data, config_file)
@config_delete.asynchronous
async def config_delete(
key: str,
*path: str,
missing_ok: bool = False,
config_file: str | Path = DEFAULT_CONFIG_LOCATION,
) -> None:
"""Set config's key by its path
### Args:
* key (`str`): Key to delete
* *path (`str`): Path to the key of the target
* missing_ok (`bool`): Do not raise an exception if the key is missing. Defaults to `False`
* config_file (`str | Path`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"`
### Raises:
* `KeyError`: Key is not found under path provided and `missing_ok` is `False`
"""
config_data: Dict[str, Any] = await json_read(config_file)
try:
nested_delete(config_data, *(*path, key))
except KeyError as exc:
if not missing_ok:
raise exc from exc
await json_write(config_data, config_file)

View File

@@ -0,0 +1 @@
from ._functions import json_read, json_write

View File

@@ -0,0 +1,76 @@
from pathlib import Path
from typing import Any
import aiofiles
from ..misc import supports_argument
from ..syncs import asyncable
try:
from ujson import dumps, loads
except ImportError:
from json import dumps, loads
@asyncable
def json_read(path: str | Path) -> Any:
"""Read contents of a JSON file
### Args:
* path (`str | Path`): Path-like object or path as a string
### Returns:
* `Any`: File contents
"""
with open(str(path), mode="r", encoding="utf-8") as f:
data = f.read()
return loads(data)
@json_read.asynchronous
async def json_read(path: str | Path) -> Any:
"""Read contents of a JSON file
### Args:
* path (`str | Path`): Path-like object or path as a string
### Returns:
* `Any`: File contents
"""
async with aiofiles.open(str(path), mode="r", encoding="utf-8") as f:
data = await f.read()
return loads(data)
@asyncable
def json_write(data: Any, path: str | Path) -> None:
"""Write contents to a JSON file
### Args:
* data (`Any`): Contents to write. Must be a JSON serializable
* path (`str | Path`): Path-like object or path as a string of a destination
"""
with open(str(path), mode="w", encoding="utf-8") as f:
f.write(
dumps(data, ensure_ascii=False, escape_forward_slashes=False, indent=4)
if supports_argument(dumps, "escape_forward_slashes")
else dumps(data, ensure_ascii=False, indent=4)
)
@json_write.asynchronous
async def json_write(data: Any, path: str | Path) -> None:
"""Write contents to a JSON file
### Args:
* data (`Any`): Contents to write. Must be a JSON serializable
* path (`str | Path`): Path-like object or path as a string of a destination
"""
async with aiofiles.open(str(path), mode="w", encoding="utf-8") as f:
await f.write(
dumps(data, ensure_ascii=False, escape_forward_slashes=False, indent=4)
if supports_argument(dumps, "escape_forward_slashes")
else dumps(data, ensure_ascii=False, indent=4)
)

View File

@@ -0,0 +1 @@
from ._functions import supports_argument, nested_set, nested_delete

View File

@@ -0,0 +1,85 @@
import inspect
from typing import Any, Dict
from typing import Callable
def supports_argument(func: Callable, arg_name: str) -> bool:
"""Check whether a function has a specific argument
### Args:
* func (`Callable`): Function to be inspected
* arg_name (`str`): Argument to be checked
### Returns:
* `bool`: `True` if argument is supported and `False` if not
"""
if hasattr(func, "__code__"):
return arg_name in inspect.signature(func).parameters
if hasattr(func, "__doc__"):
if doc := func.__doc__:
first_line = doc.splitlines()[0]
return arg_name in first_line
return False
def nested_set(target: dict, value: Any, *path: str, create_missing=True) -> Dict[str, Any]:
"""Set the key by its path to the value
### Args:
* target (`dict`): Dictionary to perform modifications on
* value (`Any`): Any data
* *path (`str`): Path to the key of the target
* create_missing (`bool`, *optional*): Create keys on the way if they're missing. Defaults to `True`
### Raises:
* `KeyError`: Key is not found under path provided
### Returns:
* `Dict[str, Any]`: Changed dictionary
"""
d = target
for key in path[:-1]:
if key in d:
d = d[key]
elif create_missing:
d = d.setdefault(key, {})
else:
raise KeyError(
f"Key '{key}' is not found under path provided ({path}) and create_missing is False"
)
if path[-1] in d or create_missing:
d[path[-1]] = value
return target
def nested_delete(target: dict, *path: str) -> Dict[str, Any]:
"""Delete the key by its path
### Args:
* target (`dict`): Dictionary to perform modifications on
### Raises:
* `KeyError`: Key is not found under path provided
### Returns:
`Dict[str, Any]`: Changed dictionary
"""
d = target
for key in path[:-1]:
if key in d:
d = d[key]
else:
raise KeyError(f"Key '{key}' is not found under path provided ({path})")
if path[-1] in d:
del d[path[-1]]
else:
raise KeyError(f"Key '{path[-1]}' is not found under path provided ({path})")
return target

View File

@@ -0,0 +1 @@
from ._syncs import asyncable

View File

@@ -0,0 +1,69 @@
import asyncio
import inspect
from inspect import FrameInfo
from typing import Any, Callable, Optional, Type
class asyncable:
"""Allows to mark a callable able to be async.
Source: https://itsjohannawren.medium.com/single-call-sync-and-async-in-python-2acadd07c9d6"""
def __init__(self, method: Callable):
self.__sync = method
self.__async = None
def asynchronous(self, method: Callable) -> "asyncable":
if not isinstance(method, Callable):
raise RuntimeError("NOT CALLABLE!!!")
self.__async = method
return self
@staticmethod
def __is_awaited() -> bool:
frame: FrameInfo = inspect.stack()[2]
if not hasattr(frame, "positions"):
return False
return (
frame.positions.col_offset >= 6
and frame.code_context[frame.index][frame.positions.col_offset - 6 : frame.positions.col_offset]
== "await "
)
def __get__(
self,
instance: Type,
*args,
owner_class: Optional[Type[Type]] = None,
**kwargs,
) -> Callable:
if self.__is_awaited():
if self.__async is None:
raise RuntimeError(
"Attempting to call asyncable with await, but no asynchronous call has been defined"
)
bound_method = self.__async.__get__(instance, owner_class)
if isinstance(self.__sync, classmethod):
return lambda: asyncio.ensure_future(bound_method(owner_class, *args, **kwargs))
return lambda: asyncio.ensure_future(bound_method(*args, **kwargs))
bound_method = self.__sync.__get__(instance, owner_class)
return lambda: bound_method(*args, **kwargs)
def __call__(self, *args, **kwargs) -> Any:
if self.__is_awaited():
if self.__async is None:
raise RuntimeError(
"Attempting to call asyncable with await, but no asynchronous call has been defined"
)
return asyncio.ensure_future(self.__async(*args, **kwargs))
return self.__sync(*args, **kwargs)

6
tests/config.json Normal file
View File

@@ -0,0 +1,6 @@
{
"locale": "en",
"bot": {
"bot_token": "sample_token"
}
}

38
tests/conftest.py Normal file
View File

@@ -0,0 +1,38 @@
from json import dumps, loads
from os import makedirs
from pathlib import Path
from uuid import uuid4
import pytest
from libbot.i18n import BotLocale
@pytest.fixture()
def location_config() -> Path:
makedirs(Path("tests/.tmp"), exist_ok=True)
filename = str(uuid4())
with open(Path("tests/config.json"), "r", encoding="utf-8") as file:
config = loads(file.read())
with open(Path(f"tests/.tmp/{filename}.json"), "w", encoding="utf-8") as file:
file.write(
dumps(
config,
ensure_ascii=False,
indent=4,
)
)
return Path(f"tests/.tmp/{filename}.json")
@pytest.fixture()
def location_locale() -> Path:
return Path("tests/data/locale/")
@pytest.fixture()
def bot_locale(location_locale: Path) -> BotLocale:
return BotLocale(locales_root=location_locale)

1
tests/data/empty.json Normal file
View File

@@ -0,0 +1 @@
{}

3
tests/data/invalid.json Normal file
View File

@@ -0,0 +1,3 @@
{
"foo": 'bar'
}

23
tests/data/locale/en.json Normal file
View File

@@ -0,0 +1,23 @@
{
"metadata": {
"flag": "🇬🇧",
"name": "English",
"codes": [
"en"
]
},
"bot": {
"name": "",
"about": "",
"description": ""
},
"foo": "bar",
"messages": {
"example": "okay"
},
"callbacks": {
"default": {
"nested": "sure"
}
}
}

23
tests/data/locale/uk.json Normal file
View File

@@ -0,0 +1,23 @@
{
"metadata": {
"flag": "🇺🇦",
"name": "Українська",
"codes": [
"uk"
]
},
"bot": {
"name": "",
"about": "",
"description": ""
},
"foo": "бар",
"messages": {
"example": "окей"
},
"callbacks": {
"default": {
"nested": "авжеж"
}
}
}

15
tests/data/test.json Normal file
View File

@@ -0,0 +1,15 @@
{
"foo": "bar",
"abcdefg": [
"higklmnop",
{
"lol": {
"kek": [
1.0000035,
0.2542,
1337
]
}
}
]
}

51
tests/test_bot_locale.py Normal file
View File

@@ -0,0 +1,51 @@
from typing import Any, List
import pytest
from libbot.i18n import BotLocale
@pytest.mark.parametrize(
"key, args, locale, expected",
[
("foo", [], None, "bar"),
("foo", [], "uk", "бар"),
("example", ["messages"], None, "okay"),
("example", ["messages"], "uk", "окей"),
("nested", ["callbacks", "default"], None, "sure"),
("nested", ["callbacks", "default"], "uk", "авжеж"),
],
)
def test_bot_locale_get(
key: str,
args: List[str],
locale: str | None,
expected: Any,
bot_locale: BotLocale,
):
assert (
bot_locale._(key, *args, locale=locale) if locale is not None else bot_locale._(key, *args)
) == expected
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], ["bar", "бар"]),
("example", ["messages"], ["okay", "окей"]),
("nested", ["callbacks", "default"], ["sure", "авжеж"]),
],
)
def test_i18n_in_all_locales(key: str, args: List[str], expected: Any, bot_locale: BotLocale):
assert (bot_locale.in_all_locales(key, *args)) == expected
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], {"en": "bar", "uk": "бар"}),
("example", ["messages"], {"en": "okay", "uk": "окей"}),
("nested", ["callbacks", "default"], {"en": "sure", "uk": "авжеж"}),
],
)
def test_i18n_in_every_locale(key: str, args: List[str], expected: Any, bot_locale: BotLocale):
assert (bot_locale.in_every_locale(key, *args)) == expected

View File

@@ -0,0 +1,65 @@
from pathlib import Path
from typing import Any, List
import pytest
from libbot.utils import config_delete, config_get, config_set
@pytest.mark.asyncio
@pytest.mark.parametrize(
"args, expected",
[
(["locale"], "en"),
(["bot_token", "bot"], "sample_token"),
],
)
async def test_config_get_valid(args: List[str], expected: str, location_config: Path):
assert await config_get(args[0], *args[1:], config_file=location_config) == expected
@pytest.mark.asyncio
@pytest.mark.parametrize(
"args, expected",
[
(["bot_stonks", "bot"], pytest.raises(KeyError)),
],
)
async def test_config_get_invalid(args: List[str], expected: Any, location_config: Path):
with expected:
assert await config_get(args[0], *args[1:], config_file=location_config) == expected
@pytest.mark.asyncio
@pytest.mark.parametrize(
"key, path, value",
[
("locale", [], "en"),
("bot_token", ["bot"], "sample_token"),
],
)
async def test_config_set(key: str, path: List[str], value: Any, location_config: Path):
await config_set(key, value, *path, config_file=location_config)
assert await config_get(key, *path, config_file=location_config) == value
@pytest.mark.asyncio
@pytest.mark.parametrize(
"key, path",
[
("bot_token", ["bot"]),
],
)
async def test_config_delete(key: str, path: List[str], location_config: Path):
await config_delete(key, *path, config_file=location_config)
assert key not in (await config_get(*path, config_file=location_config))
@pytest.mark.asyncio
@pytest.mark.parametrize(
"key, path",
[
("bot_lol", ["bot"]),
],
)
async def test_config_delete_missing(key: str, path: List[str], location_config: Path):
assert await config_delete(key, *path, missing_ok=True, config_file=location_config) is None

60
tests/test_config_sync.py Normal file
View File

@@ -0,0 +1,60 @@
from pathlib import Path
from typing import Any, List
import pytest
from libbot.utils import config_delete, config_get, config_set
@pytest.mark.parametrize(
"args, expected",
[
(["locale"], "en"),
(["bot_token", "bot"], "sample_token"),
],
)
async def test_config_get_valid(args: List[str], expected: str, location_config: Path):
assert config_get(args[0], *args[1:], config_file=location_config) == expected
@pytest.mark.parametrize(
"args, expected",
[
(["bot_stonks", "bot"], pytest.raises(KeyError)),
],
)
def test_config_get_invalid(args: List[str], expected: Any, location_config: Path):
with expected:
assert config_get(args[0], *args[1:], config_file=location_config) == expected
@pytest.mark.parametrize(
"key, path, value",
[
("locale", [], "en"),
("bot_token", ["bot"], "sample_token"),
],
)
def test_config_set(key: str, path: List[str], value: Any, location_config: Path):
config_set(key, value, *path, config_file=location_config)
assert config_get(key, *path, config_file=location_config) == value
@pytest.mark.parametrize(
"key, path",
[
("bot_token", ["bot"]),
],
)
def test_config_delete(key: str, path: List[str], location_config: Path):
config_delete(key, *path, config_file=location_config)
assert key not in config_get(*path, config_file=location_config)
@pytest.mark.parametrize(
"key, path",
[
("bot_lol", ["bot"]),
],
)
def test_config_delete_missing(key: str, path: List[str], location_config: Path):
assert config_delete(key, *path, missing_ok=True, config_file=location_config) is None

57
tests/test_i18n_async.py Normal file
View File

@@ -0,0 +1,57 @@
from pathlib import Path
from typing import Any, List
import pytest
from libbot import i18n
@pytest.mark.asyncio
@pytest.mark.parametrize(
"key, args, locale, expected",
[
("foo", [], None, "bar"),
("foo", [], "uk", "бар"),
("example", ["messages"], None, "okay"),
("example", ["messages"], "uk", "окей"),
("nested", ["callbacks", "default"], None, "sure"),
("nested", ["callbacks", "default"], "uk", "авжеж"),
],
)
async def test_i18n_get(
key: str,
args: List[str],
locale: str | None,
expected: Any,
location_locale: Path,
):
assert (
await i18n._(key, *args, locale=locale, locales_root=location_locale)
if locale is not None
else await i18n._(key, *args, locales_root=location_locale)
) == expected
@pytest.mark.asyncio
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], ["bar", "бар"]),
("example", ["messages"], ["okay", "окей"]),
("nested", ["callbacks", "default"], ["sure", "авжеж"]),
],
)
async def test_i18n_in_all_locales(key: str, args: List[str], expected: Any, location_locale: Path):
assert (await i18n.in_all_locales(key, *args, locales_root=location_locale)) == expected
@pytest.mark.asyncio
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], {"en": "bar", "uk": "бар"}),
("example", ["messages"], {"en": "okay", "uk": "окей"}),
("nested", ["callbacks", "default"], {"en": "sure", "uk": "авжеж"}),
],
)
async def test_i18n_in_every_locale(key: str, args: List[str], expected: Any, location_locale: Path):
assert (await i18n.in_every_locale(key, *args, locales_root=location_locale)) == expected

54
tests/test_i18n_sync.py Normal file
View File

@@ -0,0 +1,54 @@
from pathlib import Path
from typing import Any, List
import pytest
from libbot.i18n import _, in_all_locales, in_every_locale
@pytest.mark.parametrize(
"key, args, locale, expected",
[
("foo", [], None, "bar"),
("foo", [], "uk", "бар"),
("example", ["messages"], None, "okay"),
("example", ["messages"], "uk", "окей"),
("nested", ["callbacks", "default"], None, "sure"),
("nested", ["callbacks", "default"], "uk", "авжеж"),
],
)
def test_i18n_get(
key: str,
args: List[str],
locale: str | None,
expected: Any,
location_locale: Path,
):
assert (
_(key, *args, locale=locale, locales_root=location_locale)
if locale is not None
else _(key, *args, locales_root=location_locale)
) == expected
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], ["bar", "бар"]),
("example", ["messages"], ["okay", "окей"]),
("nested", ["callbacks", "default"], ["sure", "авжеж"]),
],
)
def test_i18n_in_all_locales(key: str, args: List[str], expected: Any, location_locale: Path):
assert (in_all_locales(key, *args, locales_root=location_locale)) == expected
@pytest.mark.parametrize(
"key, args, expected",
[
("foo", [], {"en": "bar", "uk": "бар"}),
("example", ["messages"], {"en": "okay", "uk": "окей"}),
("nested", ["callbacks", "default"], {"en": "sure", "uk": "авжеж"}),
],
)
def test_i18n_in_every_locale(key: str, args: List[str], expected: Any, location_locale: Path):
assert (in_every_locale(key, *args, locales_root=location_locale)) == expected

63
tests/test_json_async.py Normal file
View File

@@ -0,0 +1,63 @@
try:
from ujson import JSONDecodeError, dumps
except ImportError:
from json import dumps, JSONDecodeError
from pathlib import Path
from typing import Any
import pytest
from libbot.utils import json_read, json_write
@pytest.mark.asyncio
@pytest.mark.parametrize(
"path, expected",
[
(
"tests/data/test.json",
{
"foo": "bar",
"abcdefg": ["higklmnop", {"lol": {"kek": [1.0000035, 0.2542, 1337]}}],
},
),
("tests/data/empty.json", {}),
],
)
async def test_json_read_valid(path: str | Path, expected: Any):
assert await json_read(path) == expected
@pytest.mark.asyncio
@pytest.mark.parametrize(
"path, expected",
[
("tests/data/invalid.json", JSONDecodeError),
("tests/data/nonexistent.json", FileNotFoundError),
],
)
async def test_json_read_invalid(path: str | Path, expected: Any):
with pytest.raises(expected):
await json_read(path)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"data, path",
[
(
{
"foo": "bar",
"abcdefg": ["higklmnop", {"lol": {"kek": [1.0000035, 0.2542, 1337]}}],
},
"tests/data/test.json",
),
({}, "tests/data/empty.json"),
],
)
async def test_json_write(data: Any, path: str | Path):
await json_write(data, path)
assert Path(path).is_file()
with open(path, "r", encoding="utf-8") as f:
assert f.read() == dumps(data, ensure_ascii=False, indent=4)

60
tests/test_json_sync.py Normal file
View File

@@ -0,0 +1,60 @@
try:
from ujson import JSONDecodeError, dumps
except ImportError:
from json import dumps, JSONDecodeError
from pathlib import Path
from typing import Any
import pytest
from libbot.utils import json_read, json_write
@pytest.mark.parametrize(
"path, expected",
[
(
"tests/data/test.json",
{
"foo": "bar",
"abcdefg": ["higklmnop", {"lol": {"kek": [1.0000035, 0.2542, 1337]}}],
},
),
("tests/data/empty.json", {}),
],
)
def test_json_read_valid(path: str | Path, expected: Any):
assert json_read(path) == expected
@pytest.mark.parametrize(
"path, expected",
[
("tests/data/invalid.json", JSONDecodeError),
("tests/data/nonexistent.json", FileNotFoundError),
],
)
def test_json_read_invalid(path: str | Path, expected: Any):
with pytest.raises(expected):
assert json_read(path) == expected
@pytest.mark.parametrize(
"data, path",
[
(
{
"foo": "bar",
"abcdefg": ["higklmnop", {"lol": {"kek": [1.0000035, 0.2542, 1337]}}],
},
"tests/data/test.json",
),
({}, "tests/data/empty.json"),
],
)
def test_json_write(data: Any, path: str | Path):
json_write(data, path)
assert Path(path).is_file()
with open(path, "r", encoding="utf-8") as f:
assert f.read() == dumps(data, ensure_ascii=False, indent=4)

78
tests/test_nested_set.py Normal file
View File

@@ -0,0 +1,78 @@
from typing import Any, Dict, List
import pytest
from libbot.utils.misc import nested_delete, nested_set
@pytest.mark.parametrize(
"target, value, path, create_missing, expected",
[
({"foo": "bar"}, "rab", ["foo"], True, {"foo": "rab"}),
({"foo": "bar"}, {"123": 456}, ["foo"], True, {"foo": {"123": 456}}),
(
{"foo": {"bar": {}}},
True,
["foo", "bar", "test"],
True,
{"foo": {"bar": {"test": True}}},
),
(
{"foo": {"bar": {}}},
True,
["foo", "bar", "test"],
False,
{"foo": {"bar": {}}},
),
],
)
def test_nested_set_valid(
target: Dict[str, Any],
value: Any,
path: List[str],
create_missing: bool,
expected: Any,
):
assert (nested_set(target, value, *path, create_missing=create_missing)) == expected
@pytest.mark.parametrize(
"target, value, path, create_missing, expected",
[
(
{"foo": {"bar": {}}},
True,
["foo", "bar", "test1", "test2"],
False,
KeyError,
),
],
)
def test_nested_set_invalid(
target: Dict[str, Any],
value: Any,
path: List[str],
create_missing: bool,
expected: Any,
):
with pytest.raises(expected):
assert (nested_set(target, value, *path, create_missing=create_missing)) == expected
@pytest.mark.parametrize(
"target, path, expected",
[
({"foo": "bar"}, ["foo"], {}),
({"foo": "bar", "bar": "foo"}, ["bar"], {"foo": "bar"}),
(
{"foo": {"bar": {}}},
["foo", "bar"],
{"foo": {}},
),
],
)
def test_nested_delete(
target: Dict[str, Any],
path: List[str],
expected: Any,
):
assert (nested_delete(target, *path)) == expected

25
tests/test_utils.py Normal file
View File

@@ -0,0 +1,25 @@
from typing import Callable
import pytest
from libbot.utils.misc import supports_argument
def func1(foo: str, bar: str):
"""Dummy function with specific arguments"""
pass
def func2(foo: str):
"""Dummy function with specific arguments"""
pass
@pytest.mark.parametrize(
"func, arg_name, result",
[
(func1, "foo", True),
(func2, "bar", False),
],
)
def test_supports_argument(func: Callable, arg_name: str, result: bool):
assert supports_argument(func, arg_name) == result

22
tox.ini Normal file
View File

@@ -0,0 +1,22 @@
[tox]
minversion = 3.11.0
envlist = py311, py312, py313
isolated_build = true
[gh-actions]
python =
3.11: py311
3.12: py312
3.13: py313
[testenv]
setenv =
PYTHONPATH = {toxinidir}
deps =
-r{toxinidir}/requirements/_.txt
-r{toxinidir}/requirements/dev.txt
-r{toxinidir}/requirements/pycord.txt
-r{toxinidir}/requirements/pyrogram.txt
-r{toxinidir}/requirements/speed.txt
commands =
pytest --basetemp={envtmpdir} --cov=libbot