diff --git a/.dockerignore b/.dockerignore
index 99fd4a241b..74003e7e30 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -140,17 +140,11 @@ test.py
# Other stuff
.env.example
.gitignore
-.lint.py
-.pylintrc
-.travis.yml
+.github/
app.json
CHANGELOG.md
-CODE_OF_CONDUCT.md
-CONTRIBUTING.md
-requirements.min.txt
Procfile
pyproject.toml
README.md
-runtime.txt
-SPONSORS.json
-stack.yml
\ No newline at end of file
+Pipfile
+Pipfile.lock
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 28a29c07b5..0000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: "[BUG] bug report title here"
-labels: 'maybe: bug'
-assignees: ''
-
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**Bot Info**
-Bot version (check with `@modmail about`):
-Host method (Heroku, self-host, etc):
-
-**To Reproduce**
-Steps to reproduce the behavior:
-1. Who can reproduce (ex. anyone, owners)?
-2. Where can it be reproduced (ex. in thread channels, recipient DM's)?
-3. Done what to cause the error?
-4. Any recently made changes to your bot?
-5. Errored
-
-**Error Logs**
-If your Modmail bot is online, type `@modmail debug hastebin` and include the link here.
-If your Modmail bot is not online or the previous command did not generate a link, do the following:
-
-1. Select your *bot* application at https://dashboard.heroku.com
-2. [Restart your bot](https://i.imgur.com/3FcrlKz.png)
-3. Reproduce the error to populate the error logs
-4. [Copy and paste the logs](https://i.imgur.com/TTrhitm.png)
-
-**Screenshots**
-Add screenshots to help explain your problem.
-
-**Additional context**
-Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000000..99779ab4f3
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,55 @@
+name: Bug Report
+description: File a bug report
+title: "[BUG]: your bug report title"
+labels: "maybe: bug"
+body:
+ - type: input
+ id: bot-info-version
+ attributes:
+ label: Bot Version
+ description: Check it with `@modmail about`
+ placeholder: eg. v3.9.4
+ validations:
+ required: true
+ - type: dropdown
+ id: bot-info-hosting
+ attributes:
+ label: How are you hosting Modmail?
+ description: You can check it with `@modmail about` if you are unsure
+ options:
+ - Heroku
+ - Systemd
+ - PM2
+ - Patreon
+ - Other
+ validations:
+ required: true
+ - type: input
+ id: logs
+ attributes:
+ label: Error Logs
+ placeholder: https://hastebin.cc/placeholder
+ description:
+ "If your Modmail bot is online, type `@modmail debug hastebin` and include the link here.
+
+ If your Modmail bot is not online or the previous command did not generate a link, do the following:
+
+ 1. Select your *bot* application at https://dashboard.heroku.com
+
+ 2. [Restart your bot](https://i.imgur.com/3FcrlKz.png)
+
+ 3. Reproduce the error to populate the error logs
+
+ 4. [Copy and paste the logs](https://i.imgur.com/TTrhitm.png)"
+ validations:
+ required: true
+ - type: textarea
+ id: screenshots
+ attributes:
+ label: Screenshots
+ description: "[optional] You may add screenshots to further explain your problem."
+ - type: textarea
+ id: additional-info
+ attributes:
+ label: Additional Information
+ description: "[optional] You may provide additional context for us to better understand how this issue occured."
diff --git a/.github/ISSUE_TEMPLATE/command-request.md b/.github/ISSUE_TEMPLATE/command-request.md
deleted file mode 100644
index d3c1673a6b..0000000000
--- a/.github/ISSUE_TEMPLATE/command-request.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-name: Command request
-about: Request a new command
-title: "your title here"
-labels: command-request
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Who will this benefit**
-Does this feature apply to a great portion of users?
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..e9a2d9fcd4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Discord Server
+ url: https://discord.gg/etJNHCQ
+ about: Please ask hosting-related questions here before creating an issue.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 7cd7a506cd..0000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: "your title here"
-labels: feature-request
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Who will this benefit**
-Does this feature apply to a great portion of users?
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000000..b6a4437f2d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,46 @@
+name: Feature Request
+description: Suggest an idea for this project
+title: "your feature request title"
+labels: "feature request"
+body:
+ - type: textarea
+ id: problem-relation
+ attributes:
+ label: Is your feature request related to a problem? Please elaborate.
+ description: A clear and concise description of what the problem is.
+ placeholder: eg. I'm always frustrated when...
+ validations:
+ required: true
+ - type: textarea
+ id: solution
+ attributes:
+ label: Describe the solution you'd like
+ description: A clear and concise description of what you want to happen.
+ validations:
+ required: true
+ - type: checkboxes
+ id: complications
+ attributes:
+ label: Does your solution involve any of the following?
+ options:
+ - label: Logviewer
+ - label: New config option
+ - type: textarea
+ id: alternatives
+ attributes:
+ label: Describe alternatives you've considered
+ description: A clear and concise description of any alternative solutions or features you've considered.
+ validations:
+ required: true
+ - type: textarea
+ id: benefit
+ attributes:
+ label: Who will this benefit?
+ description: Does this feature apply to a great portion of users?
+ validations:
+ required: true
+ - type: textarea
+ id: additional-info
+ attributes:
+ label: Additional Information
+ description: "[optional] You may provide additional context or screenshots for us to better understand the need of the feature."
diff --git a/.github/workflows/lints.yml b/.github/workflows/lints.yml
index 94b322d968..145a83d489 100644
--- a/.github/workflows/lints.yml
+++ b/.github/workflows/lints.yml
@@ -14,20 +14,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v1
- - name: Set up Python 3.7
- uses: actions/setup-python@v1
+ - uses: actions/checkout@v2
+ - name: Set up Python 3.9
+ uses: actions/setup-python@v2
with:
- python-version: 3.7
+ python-version: 3.9
- name: Install dependencies
run: |
- python -m pip install --upgrade pip
- python -m pip install bandit==1.6.2 pylint black==19.10b0
- continue-on-error: true
+ python -m pip install --upgrade pip pipenv
+ pipenv install --dev --system
- name: Bandit syntax check
run: bandit -r . -b .bandit_baseline.json
- name: Pylint
- run: pylint ./bot.py cogs/*.py core/*.py --disable=import-error --exit-zero -r y
+ run: pylint ./bot.py cogs/*.py core/*.py --exit-zero -r y
continue-on-error: true
- name: Black
run: |
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 292a4f434f..073db1ef6e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,14 @@ however, insignificant breaking changes do not guarantee a major version bump, s
- Certain situations where the internal thread cache breaks and spams new channels. ([GH #3022](https://github.com/kyb3r/modmail/issues/3022), [PR #3028](https://github.com/kyb3r/modmail/pull/3028))
- Blocked users are now no longer allowed to use `?contact` and react to contact. ([COMMENT #819004157](https://github.com/kyb3r/modmail/issues/2969#issuecomment-819004157), [PR #3027](https://github.com/kyb3r/modmail/pull/3027))
+# v3.9.5
+
+## Internal
+
+- Bumped discord.py to v1.7.3, updated all other packages to latest.
+- More debug log files are now kept.
+- Resolve SSL errors by retrying without SSL
+
# v3.9.4
## Fixed
diff --git a/Dockerfile b/Dockerfile
index 8165e06a53..34aba25ce6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,11 +1,16 @@
-FROM python:3.7-alpine
+FROM python:3.9-slim as py
+
+FROM py as build
+
+RUN apt update && apt install -y g++
+COPY requirements.txt /
+RUN pip install --prefix=/inst -U -r /requirements.txt
+
+FROM py
+
ENV USING_DOCKER yes
+COPY --from=build /inst /usr/local
+
WORKDIR /modmailbot
+CMD ["python", "bot.py"]
COPY . /modmailbot
-RUN export PIP_NO_CACHE_DIR=false \
- && apk update \
- && apk add --update --no-cache --virtual .build-deps alpine-sdk \
- && pip install pipenv \
- && pipenv install --deploy --ignore-pipfile \
- && apk del .build-deps
-CMD ["pipenv", "run", "bot"]
\ No newline at end of file
diff --git a/Pipfile b/Pipfile
index f9621c3493..4ed01f5b70 100644
--- a/Pipfile
+++ b/Pipfile
@@ -3,31 +3,27 @@ name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
-[[source]]
-name = "pypi"
-url = "https://pypi.org/simple"
-verify_ssl = true
-
[dev-packages]
-black = "==19.10b0"
-pylint = "*"
-bandit = "==1.6.2"
-flake8 = "*"
+bandit = "~=1.7.0"
+black = "==21.6b0"
+pylint = "~=2.9.3"
[packages]
-colorama = ">=0.4.0"
-python-dateutil = ">=2.7.0"
-emoji = ">=0.2"
-uvloop = {version = ">=0.12.0",sys_platform = "!= 'win32'"}
-motor = ">=2.0.0"
-natural = "==0.2.0"
-isodate = ">=0.6.0"
-dnspython = "~=1.16.0"
-parsedatetime = "==2.6"
-aiohttp = ">=3.6.0,<3.7.0"
-python-dotenv = ">=0.10.3"
-pipenv = "*"
-"discord.py" = "==1.6.0"
+aiohttp = "==3.7.4.post0"
+colorama = "~=0.4.4" # Doesn't officially support Python 3.9 yet, v0.4.5 will support 3.9
+"discord.py" = "==1.7.3"
+emoji = "~=1.2.0"
+isodate = "~=0.6.0"
+motor = "~=2.4.0"
+natural = "~=0.2.0"
+parsedatetime = "~=2.6"
+pymongo = {extras = ["srv"], version = "*"} # Required by motor
+python-dateutil = "~=2.8.1"
+python-dotenv = "~=0.18.0"
+uvloop = {version = ">=0.15.2", markers = "sys_platform != 'win32'"}
[scripts]
bot = "python bot.py"
+
+[requires]
+python_version = "3.9"
diff --git a/Pipfile.lock b/Pipfile.lock
index aaa491011e..a9f820119e 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,16 +1,13 @@
{
"_meta": {
"hash": {
- "sha256": "bfe06c9fe1db25178b01413114093b26f0d32e9a90a031c048ff3ddc7b6644b7"
+ "sha256": "0e726213f83b90d7c4e90a04cea6636dbdc5be2ad82049c96820535e5cc3d1ad"
},
"pipfile-spec": 6,
- "requires": {},
+ "requires": {
+ "python_version": "3.9"
+ },
"sources": [
- {
- "name": "pypi",
- "url": "https://pypi.org/simple",
- "verify_ssl": true
- },
{
"name": "pypi",
"url": "https://pypi.org/simple",
@@ -21,29 +18,46 @@
"default": {
"aiohttp": {
"hashes": [
- "sha256:1a4160579ffbc1b69e88cb6ca8bb0fbd4947dfcbf9fb1e2a4fc4c7a4a986c1fe",
- "sha256:206c0ccfcea46e1bddc91162449c20c72f308aebdcef4977420ef329c8fcc599",
- "sha256:2ad493de47a8f926386fa6d256832de3095ba285f325db917c7deae0b54a9fc8",
- "sha256:319b490a5e2beaf06891f6711856ea10591cfe84fe9f3e71a721aa8f20a0872a",
- "sha256:470e4c90da36b601676fe50c49a60d34eb8c6593780930b1aa4eea6f508dfa37",
- "sha256:60f4caa3b7f7a477f66ccdd158e06901e1d235d572283906276e3803f6b098f5",
- "sha256:66d64486172b032db19ea8522328b19cfb78a3e1e5b62ab6a0567f93f073dea0",
- "sha256:687461cd974722110d1763b45c5db4d2cdee8d50f57b00c43c7590d1dd77fc5c",
- "sha256:698cd7bc3c7d1b82bb728bae835724a486a8c376647aec336aa21a60113c3645",
- "sha256:797456399ffeef73172945708810f3277f794965eb6ec9bd3a0c007c0476be98",
- "sha256:a885432d3cabc1287bcf88ea94e1826d3aec57fd5da4a586afae4591b061d40d",
- "sha256:c506853ba52e516b264b106321c424d03f3ddef2813246432fa9d1cefd361c81",
- "sha256:fb83326d8295e8840e4ba774edf346e87eca78ba8a89c55d2690352842c15ba5"
+ "sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe",
+ "sha256:0563c1b3826945eecd62186f3f5c7d31abb7391fedc893b7e2b26303b5a9f3fe",
+ "sha256:114b281e4d68302a324dd33abb04778e8557d88947875cbf4e842c2c01a030c5",
+ "sha256:14762875b22d0055f05d12abc7f7d61d5fd4fe4642ce1a249abdf8c700bf1fd8",
+ "sha256:15492a6368d985b76a2a5fdd2166cddfea5d24e69eefed4630cbaae5c81d89bd",
+ "sha256:17c073de315745a1510393a96e680d20af8e67e324f70b42accbd4cb3315c9fb",
+ "sha256:209b4a8ee987eccc91e2bd3ac36adee0e53a5970b8ac52c273f7f8fd4872c94c",
+ "sha256:230a8f7e24298dea47659251abc0fd8b3c4e38a664c59d4b89cca7f6c09c9e87",
+ "sha256:2e19413bf84934d651344783c9f5e22dee452e251cfd220ebadbed2d9931dbf0",
+ "sha256:393f389841e8f2dfc86f774ad22f00923fdee66d238af89b70ea314c4aefd290",
+ "sha256:3cf75f7cdc2397ed4442594b935a11ed5569961333d49b7539ea741be2cc79d5",
+ "sha256:3d78619672183be860b96ed96f533046ec97ca067fd46ac1f6a09cd9b7484287",
+ "sha256:40eced07f07a9e60e825554a31f923e8d3997cfc7fb31dbc1328c70826e04cde",
+ "sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf",
+ "sha256:4b302b45040890cea949ad092479e01ba25911a15e648429c7c5aae9650c67a8",
+ "sha256:515dfef7f869a0feb2afee66b957cc7bbe9ad0cdee45aec7fdc623f4ecd4fb16",
+ "sha256:547da6cacac20666422d4882cfcd51298d45f7ccb60a04ec27424d2f36ba3eaf",
+ "sha256:5df68496d19f849921f05f14f31bd6ef53ad4b00245da3195048c69934521809",
+ "sha256:64322071e046020e8797117b3658b9c2f80e3267daec409b350b6a7a05041213",
+ "sha256:7615dab56bb07bff74bc865307aeb89a8bfd9941d2ef9d817b9436da3a0ea54f",
+ "sha256:79ebfc238612123a713a457d92afb4096e2148be17df6c50fb9bf7a81c2f8013",
+ "sha256:7b18b97cf8ee5452fa5f4e3af95d01d84d86d32c5e2bfa260cf041749d66360b",
+ "sha256:932bb1ea39a54e9ea27fc9232163059a0b8855256f4052e776357ad9add6f1c9",
+ "sha256:a00bb73540af068ca7390e636c01cbc4f644961896fa9363154ff43fd37af2f5",
+ "sha256:a5ca29ee66f8343ed336816c553e82d6cade48a3ad702b9ffa6125d187e2dedb",
+ "sha256:af9aa9ef5ba1fd5b8c948bb11f44891968ab30356d65fd0cc6707d989cd521df",
+ "sha256:bb437315738aa441251214dad17428cafda9cdc9729499f1d6001748e1d432f4",
+ "sha256:bdb230b4943891321e06fc7def63c7aace16095be7d9cf3b1e01be2f10fba439",
+ "sha256:c6e9dcb4cb338d91a73f178d866d051efe7c62a7166653a91e7d9fb18274058f",
+ "sha256:cffe3ab27871bc3ea47df5d8f7013945712c46a3cc5a95b6bee15887f1675c22",
+ "sha256:d012ad7911653a906425d8473a1465caa9f8dea7fcf07b6d870397b774ea7c0f",
+ "sha256:d9e13b33afd39ddeb377eff2c1c4f00544e191e1d1dee5b6c51ddee8ea6f0cf5",
+ "sha256:e4b2b334e68b18ac9817d828ba44d8fcb391f6acb398bcc5062b14b2cbeac970",
+ "sha256:e54962802d4b8b18b6207d4a927032826af39395a3bd9196a5af43fc4e60b009",
+ "sha256:f705e12750171c0ab4ef2a3c76b9a4024a62c4103e3a55dd6f99265b9bc6fcfc",
+ "sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a",
+ "sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95"
],
"index": "pypi",
- "version": "==3.6.3"
- },
- "appdirs": {
- "hashes": [
- "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41",
- "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"
- ],
- "version": "==1.4.4"
+ "version": "==3.7.4.post0"
},
"async-timeout": {
"hashes": [
@@ -55,25 +69,19 @@
},
"attrs": {
"hashes": [
- "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6",
- "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==20.3.0"
- },
- "certifi": {
- "hashes": [
- "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c",
- "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"
+ "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1",
+ "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"
],
- "version": "==2020.12.5"
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+ "version": "==21.2.0"
},
"chardet": {
"hashes": [
- "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
- "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
+ "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
+ "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
],
- "version": "==3.0.4"
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+ "version": "==4.0.0"
},
"colorama": {
"hashes": [
@@ -85,48 +93,35 @@
},
"discord.py": {
"hashes": [
- "sha256:3df148daf6fbcc7ab5b11042368a3cd5f7b730b62f09fb5d3cbceff59bcfbb12",
- "sha256:ba8be99ff1b8c616f7b6dcb700460d0222b29d4c11048e74366954c465fdd05f"
+ "sha256:462cd0fe307aef8b29cbfa8dd613e548ae4b2cb581d46da9ac0d46fb6ea19408",
+ "sha256:c6f64db136de0e18e090f6752ea68bdd4ab0a61b82dfe7acecefa22d6477bb0c"
],
"index": "pypi",
- "version": "==1.6.0"
- },
- "distlib": {
- "hashes": [
- "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb",
- "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"
- ],
- "version": "==0.3.1"
+ "version": "==1.7.3"
},
"dnspython": {
"hashes": [
"sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01",
"sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"
],
- "index": "pypi",
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
"emoji": {
"hashes": [
- "sha256:e42da4f8d648f8ef10691bc246f682a1ec6b18373abfd9be10ec0b398823bd11"
+ "sha256:496f432058567985838c13d67dde84ca081614a8286c0b9cdc7d63dfa89d51a3",
+ "sha256:6b19b65da8d6f30551eead1705539cc0eadcd9e33a6ecbc421a29b87f96287eb"
],
"index": "pypi",
- "version": "==0.6.0"
- },
- "filelock": {
- "hashes": [
- "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59",
- "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"
- ],
- "version": "==3.0.12"
+ "version": "==1.2.0"
},
"idna": {
"hashes": [
- "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16",
- "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1"
+ "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a",
+ "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"
],
- "markers": "python_version >= '3.4'",
- "version": "==3.1"
+ "markers": "python_version >= '3.5'",
+ "version": "==3.2"
},
"isodate": {
"hashes": [
@@ -138,34 +133,54 @@
},
"motor": {
"hashes": [
- "sha256:428d94750123d19fcd0a89b8671ff9b4656f205217bad9f44161748c64c5fc80",
- "sha256:f1692b760d834707e3477996ce8d407af8cd61c1a2abedbf81c22ef14675e61a"
+ "sha256:1196db507142ef8f00d953efa2f37b39335ef2d72af6ce4fbccfd870b65c5e9f",
+ "sha256:839c11a43897dbec8e5ba0e87a9c9b877239803126877b2efa5cef89aa6b687a"
],
"index": "pypi",
- "version": "==2.3.0"
+ "version": "==2.4.0"
},
"multidict": {
"hashes": [
- "sha256:1ece5a3369835c20ed57adadc663400b5525904e53bae59ec854a5d36b39b21a",
- "sha256:275ca32383bc5d1894b6975bb4ca6a7ff16ab76fa622967625baeebcf8079000",
- "sha256:3750f2205b800aac4bb03b5ae48025a64e474d2c6cc79547988ba1d4122a09e2",
- "sha256:4538273208e7294b2659b1602490f4ed3ab1c8cf9dbdd817e0e9db8e64be2507",
- "sha256:5141c13374e6b25fe6bf092052ab55c0c03d21bd66c94a0e3ae371d3e4d865a5",
- "sha256:51a4d210404ac61d32dada00a50ea7ba412e6ea945bbe992e4d7a595276d2ec7",
- "sha256:5cf311a0f5ef80fe73e4f4c0f0998ec08f954a6ec72b746f3c179e37de1d210d",
- "sha256:6513728873f4326999429a8b00fc7ceddb2509b01d5fd3f3be7881a257b8d463",
- "sha256:7388d2ef3c55a8ba80da62ecfafa06a1c097c18032a501ffd4cabbc52d7f2b19",
- "sha256:9456e90649005ad40558f4cf51dbb842e32807df75146c6d940b6f5abb4a78f3",
- "sha256:c026fe9a05130e44157b98fea3ab12969e5b60691a276150db9eda71710cd10b",
- "sha256:d14842362ed4cf63751648e7672f7174c9818459d169231d03c56e84daf90b7c",
- "sha256:e0d072ae0f2a179c375f67e3da300b47e1a83293c554450b29c900e50afaae87",
- "sha256:f07acae137b71af3bb548bd8da720956a3bc9f9a0b87733e0899226a2317aeb7",
- "sha256:fbb77a75e529021e7c4a8d4e823d88ef4d23674a202be4f5addffc72cbb91430",
- "sha256:fcfbb44c59af3f8ea984de67ec7c306f618a3ec771c2843804069917a8f2e255",
- "sha256:feed85993dbdb1dbc29102f50bca65bdc68f2c0c8d352468c25b54874f23c39d"
+ "sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a",
+ "sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93",
+ "sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632",
+ "sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656",
+ "sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79",
+ "sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7",
+ "sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d",
+ "sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5",
+ "sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224",
+ "sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26",
+ "sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea",
+ "sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348",
+ "sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6",
+ "sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76",
+ "sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1",
+ "sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f",
+ "sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952",
+ "sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a",
+ "sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37",
+ "sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9",
+ "sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359",
+ "sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8",
+ "sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da",
+ "sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3",
+ "sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d",
+ "sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf",
+ "sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841",
+ "sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d",
+ "sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93",
+ "sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f",
+ "sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647",
+ "sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635",
+ "sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456",
+ "sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda",
+ "sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5",
+ "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281",
+ "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80"
],
- "markers": "python_version >= '3.5'",
- "version": "==4.7.6"
+ "markers": "python_version >= '3.6'",
+ "version": "==5.1.0"
},
"natural": {
"hashes": [
@@ -182,160 +197,203 @@
"index": "pypi",
"version": "==2.6"
},
- "pipenv": {
- "hashes": [
- "sha256:4ab2f60742184d851ac44b9e1d423afe71dc2ea7a68bde07eb890c8b4ce5a420",
- "sha256:8253fe6f9cfb3791a54da8a0571f73c918cb3457dd908684c1800a13a06ec4c1"
+ "pymongo": {
+ "extras": [
+ "srv"
+ ],
+ "hashes": [
+ "sha256:02dc0b0f48ed3cd06c13b7e31b066bf91e00dac5f8147b0a0a45f9009bfab857",
+ "sha256:053b4ebf91c7395d1fcd2ce6a9edff0024575b7b2de6781554a4114448a8adc9",
+ "sha256:070a4ef689c9438a999ec3830e69b208ff0d12251846e064d947f97d819d1d05",
+ "sha256:072ba7cb65c8aa4d5c5659bf6722ee85781c9d7816dc00679b8b6f3dff1ddafc",
+ "sha256:0b6055e0ef451ff73c93d0348d122a0750dddf323b9361de5835dac2f6cf7fc1",
+ "sha256:11f9e0cfc84ade088a38df2708d0b958bb76360181df1b2e1e1a41beaa57952b",
+ "sha256:18290649759f9db660972442aa606f845c368db9b08c4c73770f6da14113569b",
+ "sha256:186104a94d39b8412f8e3de385acd990a628346a4402d4f3a288a82b8660bd22",
+ "sha256:1970cfe2aec1bf74b40cf30c130ad10cd968941694630386db33e1d044c22a2e",
+ "sha256:19d4bd0fc29aa405bb1781456c9cfff9fceabb68543741eb17234952dbc2bbb0",
+ "sha256:1bab889ae7640eba739f67fcbf8eff252dddc60d4495e6ddd3a87cd9a95fdb52",
+ "sha256:1bc6fe7279ff40c6818db002bf5284aa03ec181ea1b1ceaeee33c289d412afa7",
+ "sha256:208debdcf76ed39ebf24f38509f50dc1c100e31e8653817fedb8e1f867850a13",
+ "sha256:2399a85b54f68008e483b2871f4a458b4c980469c7fe921595ede073e4844f1e",
+ "sha256:246ec420e4c8744fceb4e259f906211b9c198e1f345e6158dcd7cbad3737e11e",
+ "sha256:24f8aeec4d6b894a6128844e50ff423dd02462ee83addf503c598ee3a80ddf3d",
+ "sha256:255a35bf29185f44b412e31a927d9dcedda7c2c380127ecc4fbf2f61b72fa978",
+ "sha256:2dbfbbded947a83a3dffc2bd1ec4750c17e40904692186e2c55a3ad314ca0222",
+ "sha256:2e92aa32300a0b5e4175caec7769f482b292769807024a86d674b3f19b8e3755",
+ "sha256:316c1b8723afa9870567cd6dff35d440b2afeda53aa13da6c5ab85f98ed6f5ca",
+ "sha256:333bfad77aa9cd11711febfb75eed0bb537a1d022e1c252714dad38993590240",
+ "sha256:39dafa2eaf577d1969f289dc9a44501859a1897eb45bd589e93ce843fc610800",
+ "sha256:3ce83f17f641a62a4dfb0ba1b8a3c1ced7c842f511b5450d90c030c7828e3693",
+ "sha256:46d5ec90276f71af3a29917b30f2aec2315a2759b5f8d45b3b63a07ca8a070a3",
+ "sha256:48d5bc80ab0af6b60c4163c5617f5cd23f2f880d7600940870ea5055816af024",
+ "sha256:4ba0def4abef058c0e5101e05e3d5266e6fffb9795bbf8be0fe912a7361a0209",
+ "sha256:5af390fa9faf56c93252dab09ea57cd020c9123aa921b63a0ed51832fdb492e7",
+ "sha256:5e574664f1468872cd40f74e4811e22b1aa4de9399d6bcfdf1ee6ea94c017fcf",
+ "sha256:625befa3bc9b40746a749115cc6a15bf20b9bd7597ca55d646205b479a2c99c7",
+ "sha256:6261bee7c5abadeac7497f8f1c43e521da78dd13b0a2439f526a7b0fc3788824",
+ "sha256:657ad80de8ec9ed656f28844efc801a0802961e8c6a85038d97ff6f555ef4919",
+ "sha256:6b89dc51206e4971c5568c797991eaaef5dc2a6118d67165858ad11752dba055",
+ "sha256:6e66780f14c2efaf989cd3ac613b03ee6a8e3a0ba7b96c0bb14adca71a427e55",
+ "sha256:6fb3f85870ae26896bb44e67db94045f2ebf00c5d41e6b66cdcbb5afd644fc18",
+ "sha256:701e08457183da70ed96b35a6b43e6ba1df0b47c837b063cde39a1fbe1aeda81",
+ "sha256:70761fd3c576b027eec882b43ee0a8e5b22ff9c20cdf4d0400e104bc29e53e34",
+ "sha256:73b400fdc22de84bae0dbf1a22613928a41612ec0a3d6ed47caf7ad4d3d0f2ff",
+ "sha256:7412a36798966624dc4c57d64aa43c2d1100b348abd98daaac8e99e57d87e1d7",
+ "sha256:78ecb8d42f50d393af912bfb1fb1dcc9aabe9967973efb49ee577e8f1cea494c",
+ "sha256:7c6a9948916a7bbcc6d3a9f6fb75db1acb5546078023bfb3db6efabcd5a67527",
+ "sha256:7c72d08acdf573455b2b9d2b75b8237654841d63a48bc2327dc102c6ee89b75a",
+ "sha256:7d98ce3c42921bb91566121b658e0d9d59a9082a9bd6f473190607ff25ab637f",
+ "sha256:845a8b83798b2fb11b09928413cb32692866bfbc28830a433d9fa4c8c3720dd0",
+ "sha256:94d38eba4d1b5eb3e6bfece0651b855a35c44f32fd91f512ab4ba41b8c0d3e66",
+ "sha256:9a13661681d17e43009bb3e85e837aa1ec5feeea1e3654682a01b8821940f8b3",
+ "sha256:a0e5dff6701fa615f165306e642709e1c1550d5b237c5a7a6ea299886828bd50",
+ "sha256:a2239556ff7241584ce57be1facf25081669bb457a9e5cbe68cce4aae6567aa1",
+ "sha256:a325600c83e61e3c9cebc0c2b1c8c4140fa887f789085075e8f44c8ff2547eb9",
+ "sha256:a3566acfbcde46911c52810374ecc0354fdb841284a3efef6ff7105bc007e9a8",
+ "sha256:a634a4730ce0b0934ed75e45beba730968e12b4dafbb22f69b3b2f616d9e644e",
+ "sha256:a6d055f01b83b1a4df8bb0c61983d3bdffa913764488910af3620e5c2450bf83",
+ "sha256:a752ecd1a26000a6d67be7c9a2e93801994a8b3f866ac95b672fbc00225ca91a",
+ "sha256:a9ba2a63777027b06b116e1ea8248e66fd1bedc2c644f93124b81a91ddbf6d88",
+ "sha256:aaa038eafb7186a4abbb311fcf20724be9363645882bbce540bef4797e812a7a",
+ "sha256:af586e85144023686fb0af09c8cdf672484ea182f352e7ceead3d832de381e1b",
+ "sha256:b0a0cf39f589e52d801fdef418305562bc030cdf8929217463c8433c65fd5c2f",
+ "sha256:b1c4874331ab960429caca81acb9d2932170d66d6d6f87e65dc4507a85aca152",
+ "sha256:b3b5b3cbc3fdf4fcfa292529df2a85b5d9c7053913a739d3069af1e12e12219f",
+ "sha256:b542d56ed1b8d5cf3bb36326f814bd2fbe8812dfd2582b80a15689ea433c0e35",
+ "sha256:b6ea08758b6673610b3c5bdf47189286cf9c58b1077558706a2f6f8744922527",
+ "sha256:b754240daafecd9d5fce426b0fbaaed03f4ebb130745c8a4ae9231fffb8d75e5",
+ "sha256:b772bab31cbd9cb911e41e1a611ebc9497f9a32a7348e2747c38210f75c00f41",
+ "sha256:b88d1742159bc93a078733f9789f563cef26f5e370eba810476a71aa98e5fbc2",
+ "sha256:b8bf42d3b32f586f4c9e37541769993783a534ad35531ce8a4379f6fa664fba9",
+ "sha256:bc9ac81e73573516070d24ce15da91281922811f385645df32bd3c8a45ab4684",
+ "sha256:c188db6cf9e14dbbb42f5254292be96f05374a35e7dfa087cc2140f0ff4f10f6",
+ "sha256:c55782a55f4a013a78ac5b6ee4b8731a192dea7ab09f1b6b3044c96d5128edd4",
+ "sha256:c5cab230e7cabdae9ff23c12271231283efefb944c1b79bed79a91beb65ba547",
+ "sha256:cbf8672edeb7b7128c4a939274801f0e32bbf5159987815e3d1eace625264a46",
+ "sha256:cc2894fe91f31a513860238ede69fe47fada21f9e7ddfe73f7f9fef93a971e41",
+ "sha256:cda9e628b1315beec8341e8c04aac9a0b910650b05e0751e42e399d5694aeacb",
+ "sha256:ceae3ab9e11a27aaab42878f1d203600dfd24f0e43678b47298219a0f10c0d30",
+ "sha256:ced944dcdd561476deef7cb7bfd4987c69fffbfeff6d02ca4d5d4fd592d559b7",
+ "sha256:d04ca462cb99077e6c059e97c072957caf2918e6e4191e3161c01c439e0193de",
+ "sha256:d1131562ddc2ea8a446f66c2648d7dabec2b3816fc818528eb978a75a6d23b2e",
+ "sha256:d1740776b70367277323fafb76bcf09753a5cc9824f5d705bac22a34ff3668ea",
+ "sha256:d6e11ffd43184d529d6752d6dcb62b994f903038a17ea2168ef1910c96324d26",
+ "sha256:d73e10772152605f6648ba4410318594f1043bbfe36d2fadee7c4b8912eff7c5",
+ "sha256:da8288bc4a7807c6715416deed1c57d94d5e03e93537889e002bf985be503f1a",
+ "sha256:db93608a246da44d728842b8fa9e45aa9782db76955f634a707739a8d53ff544",
+ "sha256:dcd3d0009fbb6e454d729f8b22d0063bd9171c31a55e0f0271119bd4f2700023",
+ "sha256:dd1f49f949a658c4e8f81ed73f9aad25fcc7d4f62f767f591e749e30038c4e1d",
+ "sha256:dd6ff2192f34bd622883c745a56f492b1c9ccd44e14953e8051c33024a2947d5",
+ "sha256:e018a4921657c2d3f89c720b7b90b9182e277178a04a7e9542cc79d7d787ca51",
+ "sha256:e2b7670c0c8c6b501464150dd49dd0d6be6cb7f049e064124911cec5514fa19e",
+ "sha256:e7a33322e08021c37e89cae8ff06327503e8a1719e97c69f32c31cbf6c30d72c",
+ "sha256:e8a82e35d52ad6f867e88096a1a2b9bdc7ec4d5e65c7b4976a248bf2d1a32a93",
+ "sha256:e9faf8d4712d5ea301d74abfcf6dafe4b7f4af7936e91f283b0ad7bf69ed3e3a",
+ "sha256:ec5ca7c0007ce268048bbe0ffc6846ed1616cf3d8628b136e81d5e64ff3f52a2",
+ "sha256:eee42a1cc06565f6b21caa1f504ec15e07de7ebfd520ab57f8cb3308bc118e22",
+ "sha256:f2acf9bbcd514e901f82c4ca6926bbd2ae61716728f110b4343eb0a69612d018",
+ "sha256:f55c1ddcc1f6050b07d468ce594f55dbf6107b459e16f735d26818d7be1e9538",
+ "sha256:f6977a520bd96e097c8a37a8cbb9faa1ea99d21bf84190195056e25f688af73d",
+ "sha256:f94c7d22fb36b184734dded7345a04ec5f95130421c775b8b0c65044ef073f34",
+ "sha256:fa8957e9a1b202cb45e6b839c241cd986c897be1e722b81d2f32e9c6aeee80b0",
+ "sha256:fd3854148005c808c485c754a184c71116372263709958b42aefbef2e5dd373a",
+ "sha256:fe5872ce6f9627deac8314bdffd3862624227c3de4c17ef0cc78bbf0402999eb",
+ "sha256:ffbae429ba9e42d0582d3ac63fdb410338892468a2107d8ff68228ec9a39a0ed"
],
"index": "pypi",
- "version": "==2020.11.15"
- },
- "pymongo": {
- "hashes": [
- "sha256:019ddf7ced8e42cc6c8c608927c799be8097237596c94ffe551f6ef70e55237e",
- "sha256:047c325c4a96e7be7d11acf58639bcf71a81ca212d9c6590e3369bc28678647a",
- "sha256:047cc2007b280672ddfdf2e7b862aad8d898f481f65bbc9067bfa4e420a019a9",
- "sha256:061d59f525831c4051af0b6dbafa62b0b8b168d4ef5b6e3c46d0811b8499d100",
- "sha256:082832a59da18efab4d9148cca396451bac99da9757f31767f706e828b5b8500",
- "sha256:0a53a751d977ad02f1bd22ddb6288bb4816c4758f44a50225462aeeae9cbf6a0",
- "sha256:1222025db539641071a1b67f6950f65a6342a39db5b454bf306abd6954f1ad8a",
- "sha256:1580fad512c678b720784e5c9018621b1b3bd37fb5b1633e874738862d6435c7",
- "sha256:202ea1d4edc8a5439fc179802d807b49e7e563207fea5610779e56674ac770c6",
- "sha256:21d7b48567a1c80f9266e0ab61c1218a31279d911da345679188733e354f81cc",
- "sha256:264843ce2af0640994a4331148ef5312989bc004678c457460758766c9b4decc",
- "sha256:270a1f6a331eac3a393090af06df68297cb31a8b2df0bdcbd97dc613c5758e78",
- "sha256:29a6840c2ac778010547cad5870f3db2e080ad7fad01197b07fff993c08692c8",
- "sha256:3646c2286d889618d43e01d9810ac1fc17709d2b4dec61366df5edc8ba228b3e",
- "sha256:36b9b98a39565a8f33803c81569442b35e749a72fb1aa7d0bcdb1a33052f8bcc",
- "sha256:3ec8f8e106a1476659d8c020228b45614daabdbdb6c6454a843a1d4f77d13339",
- "sha256:422069f2cebf58c9dd9e8040b4768f7be4f228c95bc4505e8fa8e7b4f7191ad8",
- "sha256:44376a657717de8847d5d71a9305f3595c7e78c91ac77edbb87058d12ede87a6",
- "sha256:45728e6aae3023afb5b2829586d1d2bfd9f0d71cfd7d3c924b71a5e9aef617a8",
- "sha256:46792b71ab802d9caf1fc9d52e83399ef8e1a36e91eef4d827c06e36b8df2230",
- "sha256:4942a5659ae927bb764a123a6409870ca5dd572d83b3bfb71412c9a191bbf792",
- "sha256:4be4fe9d18523da98deeb0b554ac76e1dc1562ee879d62572b34dda8593efcc1",
- "sha256:523804bd8fcb5255508052b50073a27c701b90a73ea46e29be46dad5fe01bde6",
- "sha256:540dafd6f4a0590fc966465c726b80fa7c0804490c39786ef29236fe68c94401",
- "sha256:5980509801cbd2942df31714d055d89863684b4de26829c349362e610a48694e",
- "sha256:5ad7b96c27acd7e256b33f47cf3d23bd7dd902f9c033ae43f32ffcbc37bebafd",
- "sha256:6122470dfa61d4909b75c98012c1577404ba4ab860d0095e0c6980560cb3711f",
- "sha256:6175fd105da74a09adb38f93be96e1f64873294c906e5e722cbbc5bd10c44e3b",
- "sha256:646d4d30c5aa7c0ddbfe9b990f0f77a88621024a21ad0b792bd9d58caa9611f0",
- "sha256:6700e251c6396cc05d7460dc05ef8e19e60a7b53b62c007725b48e123aaa2b1c",
- "sha256:6aac7e0e8de92f11a410eb68c24a2decbac6f094e82fd95d22546d0168e7a18b",
- "sha256:6e7a6057481a644970e43475292e1c0af095ca39a20fe83781196bd6e6690a38",
- "sha256:76579fcf77052b39796fe4a11818d1289dd48cffe15951b3403288fa163c29f6",
- "sha256:7e69fa025a1db189443428f345fea5555d16413df6addc056e17bb8c9794b006",
- "sha256:7f0c507e1f108790840d6c4b594019ebf595025c324c9f7e9c9b2b15b41f884e",
- "sha256:813db97e9955b6b1b50b5cebd18cb148580603bb9b067ea4c5cc656b333bc906",
- "sha256:82d5ded5834b6c92380847860eb28dcaf20b847a27cee5811c4aaceef87fd280",
- "sha256:82f6e42ba40440a7e0a20bfe12465a3b62d65966a4c7ad1a21b36ffff88de6fe",
- "sha256:8d669c720891781e7c82d412cad39f9730ef277e3957b48a3344dae47d3caa03",
- "sha256:944ed467feb949e103555863fa934fb84216a096b0004ca364d3ddf9d18e2b9e",
- "sha256:96c6aef7ffb0d37206c0342abb82d874fa8cdc344267277ec63f562b94335c22",
- "sha256:9be785bd4e1ba0148fb00ca84e4dbfbd1c74df3af3a648559adc60b0782f34de",
- "sha256:9d19843568df9d263dc92ae4cc2279879add8a26996473f9155590cac635b321",
- "sha256:a118a1df7280ffab7fe0f3eab325868339ff1c4d5b8e0750db0f0a796da8f849",
- "sha256:b4294ddf76452459433ecfa6a93258608b5e462c76ef15e4695ed5e2762f009f",
- "sha256:b50af6701b4a5288b77fb4db44a363aa9485caf2c3e7a40c0373fd45e34440af",
- "sha256:b875bb4b438931dce550e170bfb558597189b8d0160f4ac60f14a21955161699",
- "sha256:b95d2c2829b5956bf54d9a22ffec911dea75abf0f0f7e0a8a57423434bfbde91",
- "sha256:c046e09e886f4539f8626afba17fa8f2e6552731f9384e2827154e3e3b7fda4e",
- "sha256:c1d1992bbdf363b22b5a9543ab7d7c6f27a1498826d50d91319b803ddcf1142e",
- "sha256:c2b67881392a9e85aa108e75f62cdbe372d5a3f17ea5f8d3436dcf4662052f14",
- "sha256:c6cf288c9e03195d8e12b72a6388b32f18a5e9c2545622417a963e428e1fe496",
- "sha256:c812b6e53344e92f10f12235219fb769c491a4a87a02c9c3f93fe632e493bda8",
- "sha256:cc421babc687dc52ce0fc19787b2404518ca749d9db59576100946ff886f38ed",
- "sha256:ce53c00be204ec4428d3c1f3c478ae89d388efec575544c27f57b61e9fa4a7f2",
- "sha256:ce9964c117cbe5cf6269f30a2b334d28675956e988b7dbd0b4f7370924afda2e",
- "sha256:d6f82e86896a8db70e8ae8fa4b7556a0f188f1d8a6c53b2ba229889d55a59308",
- "sha256:d9d3ae537f61011191b2fd6f8527b9f9f8a848b37d4c85a0f7bb28004c42b546",
- "sha256:e565d1e4388765c135052717f15f9e0314f9d172062444c6b3fc0002e93ed04b",
- "sha256:ed98683d8f01f1c46ef2d02469e04e9a8fe9a73a9741a4e6e66677a73b59bec8",
- "sha256:ef18aa15b1aa18c42933deed5233b3284186e9ed85c25d2704ceff5099a3964c",
- "sha256:fa741e9c805567239f845c7e9a016aff797f9bb02ff9bc8ccd2fbd9eafefedd4",
- "sha256:fc4946acb6cdada08f60aca103b61334995523da65be5fe816ea8571c9967d46",
- "sha256:fcc66d17a3363b7bd6d2655de8706e25a3cd1be2bd1b8e8d8a5c504a6ef893ae"
- ],
- "version": "==3.11.2"
+ "version": "==3.12.0"
},
"python-dateutil": {
"hashes": [
- "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
- "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
+ "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
+ "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
],
"index": "pypi",
- "version": "==2.8.1"
+ "version": "==2.8.2"
},
"python-dotenv": {
"hashes": [
- "sha256:0c8d1b80d1a1e91717ea7d526178e3882732420b03f08afea0406db6402e220e",
- "sha256:587825ed60b1711daea4832cf37524dfd404325b7db5e25ebe88c495c9f807a0"
+ "sha256:dd8fe852847f4fbfadabf6183ddd4c824a9651f02d51714fa075c95561959c7d",
+ "sha256:effaac3c1e58d89b3ccb4d04a40dc7ad6e0275fda25fd75ae9d323e2465e202d"
],
"index": "pypi",
- "version": "==0.15.0"
+ "version": "==0.18.0"
},
"six": {
"hashes": [
- "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
- "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
+ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
+ "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
- "version": "==1.15.0"
- },
- "uvloop": {
- "hashes": [
- "sha256:08b109f0213af392150e2fe6f81d33261bb5ce968a288eb698aad4f46eb711bd",
- "sha256:123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e",
- "sha256:4315d2ec3ca393dd5bc0b0089d23101276778c304d42faff5dc4579cb6caef09",
- "sha256:4544dcf77d74f3a84f03dd6278174575c44c67d7165d4c42c71db3fdc3860726",
- "sha256:afd5513c0ae414ec71d24f6f123614a80f3d27ca655a4fcf6cabe50994cc1891",
- "sha256:b4f591aa4b3fa7f32fb51e2ee9fea1b495eb75b0b3c8d0ca52514ad675ae63f7",
- "sha256:bcac356d62edd330080aed082e78d4b580ff260a677508718f88016333e2c9c5",
- "sha256:e7514d7a48c063226b7d06617cbb12a14278d4323a065a8d46a7962686ce2e95",
- "sha256:f07909cd9fc08c52d294b1570bba92186181ca01fe3dc9ffba68955273dd7362"
- ],
- "markers": "sys_platform != 'win32'",
- "version": "==0.14.0"
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "version": "==1.16.0"
},
- "virtualenv": {
+ "typing-extensions": {
"hashes": [
- "sha256:54b05fc737ea9c9ee9f8340f579e5da5b09fb64fd010ab5757eb90268616907c",
- "sha256:b7a8ec323ee02fb2312f098b6b4c9de99559b462775bc8fe3627a73706603c1b"
+ "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497",
+ "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342",
+ "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==20.2.2"
+ "version": "==3.10.0.0"
},
- "virtualenv-clone": {
+ "uvloop": {
"hashes": [
- "sha256:07e74418b7cc64f4fda987bf5bc71ebd59af27a7bc9e8a8ee9fd54b1f2390a27",
- "sha256:665e48dd54c84b98b71a657acb49104c54e7652bce9c1c4f6c6976ed4c827a29"
+ "sha256:0de811931e90ae2da9e19ce70ffad73047ab0c1dba7c6e74f9ae1a3aabeb89bd",
+ "sha256:1ff05116ede1ebdd81802df339e5b1d4cab1dfbd99295bf27e90b4cec64d70e9",
+ "sha256:2d8ffe44ae709f839c54bacf14ed283f41bee90430c3b398e521e10f8d117b3a",
+ "sha256:5cda65fc60a645470b8525ce014516b120b7057b576fa876cdfdd5e60ab1efbb",
+ "sha256:63a3288abbc9c8ee979d7e34c34e780b2fbab3e7e53d00b6c80271119f277399",
+ "sha256:7522df4e45e4f25b50adbbbeb5bb9847495c438a628177099d2721f2751ff825",
+ "sha256:7f4b8a905df909a407c5791fb582f6c03b0d3b491ecdc1cdceaefbc9bf9e08f6",
+ "sha256:905f0adb0c09c9f44222ee02f6b96fd88b493478fffb7a345287f9444e926030",
+ "sha256:ae2b325c0f6d748027f7463077e457006b4fdb35a8788f01754aadba825285ee",
+ "sha256:e71fb9038bfcd7646ca126c5ef19b17e48d4af9e838b2bcfda7a9f55a6552a32"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==0.5.4"
+ "markers": "sys_platform != 'win32'",
+ "version": "==0.15.3"
},
"yarl": {
"hashes": [
- "sha256:040b237f58ff7d800e6e0fd89c8439b841f777dd99b4a9cca04d6935564b9409",
- "sha256:17668ec6722b1b7a3a05cc0167659f6c95b436d25a36c2d52db0eca7d3f72593",
- "sha256:3a584b28086bc93c888a6c2aa5c92ed1ae20932f078c46509a66dce9ea5533f2",
- "sha256:4439be27e4eee76c7632c2427ca5e73703151b22cae23e64adb243a9c2f565d8",
- "sha256:48e918b05850fffb070a496d2b5f97fc31d15d94ca33d3d08a4f86e26d4e7c5d",
- "sha256:9102b59e8337f9874638fcfc9ac3734a0cfadb100e47d55c20d0dc6087fb4692",
- "sha256:9b930776c0ae0c691776f4d2891ebc5362af86f152dd0da463a6614074cb1b02",
- "sha256:b3b9ad80f8b68519cc3372a6ca85ae02cc5a8807723ac366b53c0f089db19e4a",
- "sha256:bc2f976c0e918659f723401c4f834deb8a8e7798a71be4382e024bcc3f7e23a8",
- "sha256:c22c75b5f394f3d47105045ea551e08a3e804dc7e01b37800ca35b58f856c3d6",
- "sha256:c52ce2883dc193824989a9b97a76ca86ecd1fa7955b14f87bf367a61b6232511",
- "sha256:ce584af5de8830d8701b8979b18fcf450cef9a382b1a3c8ef189bedc408faf1e",
- "sha256:da456eeec17fa8aa4594d9a9f27c0b1060b6a75f2419fe0c00609587b2695f4a",
- "sha256:db6db0f45d2c63ddb1a9d18d1b9b22f308e52c83638c26b422d520a815c4b3fb",
- "sha256:df89642981b94e7db5596818499c4b2219028f2a528c9c37cc1de45bf2fd3a3f",
- "sha256:f18d68f2be6bf0e89f1521af2b1bb46e66ab0018faafa81d70f358153170a317",
- "sha256:f379b7f83f23fe12823085cd6b906edc49df969eb99757f58ff382349a3303c6"
+ "sha256:00d7ad91b6583602eb9c1d085a2cf281ada267e9a197e8b7cae487dadbfa293e",
+ "sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434",
+ "sha256:15263c3b0b47968c1d90daa89f21fcc889bb4b1aac5555580d74565de6836366",
+ "sha256:2ce4c621d21326a4a5500c25031e102af589edb50c09b321049e388b3934eec3",
+ "sha256:31ede6e8c4329fb81c86706ba8f6bf661a924b53ba191b27aa5fcee5714d18ec",
+ "sha256:324ba3d3c6fee56e2e0b0d09bf5c73824b9f08234339d2b788af65e60040c959",
+ "sha256:329412812ecfc94a57cd37c9d547579510a9e83c516bc069470db5f75684629e",
+ "sha256:4736eaee5626db8d9cda9eb5282028cc834e2aeb194e0d8b50217d707e98bb5c",
+ "sha256:4953fb0b4fdb7e08b2f3b3be80a00d28c5c8a2056bb066169de00e6501b986b6",
+ "sha256:4c5bcfc3ed226bf6419f7a33982fb4b8ec2e45785a0561eb99274ebbf09fdd6a",
+ "sha256:547f7665ad50fa8563150ed079f8e805e63dd85def6674c97efd78eed6c224a6",
+ "sha256:5b883e458058f8d6099e4420f0cc2567989032b5f34b271c0827de9f1079a424",
+ "sha256:63f90b20ca654b3ecc7a8d62c03ffa46999595f0167d6450fa8383bab252987e",
+ "sha256:68dc568889b1c13f1e4745c96b931cc94fdd0defe92a72c2b8ce01091b22e35f",
+ "sha256:69ee97c71fee1f63d04c945f56d5d726483c4762845400a6795a3b75d56b6c50",
+ "sha256:6d6283d8e0631b617edf0fd726353cb76630b83a089a40933043894e7f6721e2",
+ "sha256:72a660bdd24497e3e84f5519e57a9ee9220b6f3ac4d45056961bf22838ce20cc",
+ "sha256:73494d5b71099ae8cb8754f1df131c11d433b387efab7b51849e7e1e851f07a4",
+ "sha256:7356644cbed76119d0b6bd32ffba704d30d747e0c217109d7979a7bc36c4d970",
+ "sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10",
+ "sha256:8aa3decd5e0e852dc68335abf5478a518b41bf2ab2f330fe44916399efedfae0",
+ "sha256:97b5bdc450d63c3ba30a127d018b866ea94e65655efaf889ebeabc20f7d12406",
+ "sha256:9ede61b0854e267fd565e7527e2f2eb3ef8858b301319be0604177690e1a3896",
+ "sha256:b2e9a456c121e26d13c29251f8267541bd75e6a1ccf9e859179701c36a078643",
+ "sha256:b5dfc9a40c198334f4f3f55880ecf910adebdcb2a0b9a9c23c9345faa9185721",
+ "sha256:bafb450deef6861815ed579c7a6113a879a6ef58aed4c3a4be54400ae8871478",
+ "sha256:c49ff66d479d38ab863c50f7bb27dee97c6627c5fe60697de15529da9c3de724",
+ "sha256:ce3beb46a72d9f2190f9e1027886bfc513702d748047b548b05dab7dfb584d2e",
+ "sha256:d26608cf178efb8faa5ff0f2d2e77c208f471c5a3709e577a7b3fd0445703ac8",
+ "sha256:d597767fcd2c3dc49d6eea360c458b65643d1e4dbed91361cf5e36e53c1f8c96",
+ "sha256:d5c32c82990e4ac4d8150fd7652b972216b204de4e83a122546dce571c1bdf25",
+ "sha256:d8d07d102f17b68966e2de0e07bfd6e139c7c02ef06d3a0f8d2f0f055e13bb76",
+ "sha256:e46fba844f4895b36f4c398c5af062a9808d1f26b2999c58909517384d5deda2",
+ "sha256:e6b5460dc5ad42ad2b36cca524491dfcaffbfd9c8df50508bddc354e787b8dc2",
+ "sha256:f040bcc6725c821a4c0665f3aa96a4d0805a7aaf2caf266d256b8ed71b9f041c",
+ "sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a",
+ "sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71"
],
- "markers": "python_version >= '3.5'",
- "version": "==1.5.1"
+ "markers": "python_version >= '3.6'",
+ "version": "==1.6.3"
}
},
"develop": {
@@ -348,43 +406,35 @@
},
"astroid": {
"hashes": [
- "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703",
- "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"
+ "sha256:7b963d1c590d490f60d2973e57437115978d3a2529843f160b5003b721e1e925",
+ "sha256:83e494b02d75d07d4e347b27c066fd791c0c74fc96c613d1ea3de0c82c48168f"
],
- "markers": "python_version >= '3.5'",
- "version": "==2.4.2"
- },
- "attrs": {
- "hashes": [
- "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6",
- "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==20.3.0"
+ "markers": "python_version ~= '3.6'",
+ "version": "==2.6.5"
},
"bandit": {
"hashes": [
- "sha256:336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952",
- "sha256:41e75315853507aa145d62a78a2a6c5e3240fe14ee7c601459d0df9418196065"
+ "sha256:216be4d044209fa06cf2a3e51b319769a51be8318140659719aa7a115c35ed07",
+ "sha256:8a4c7415254d75df8ff3c3b15cfe9042ecee628a1e40b44c15a98890fbfc2608"
],
"index": "pypi",
- "version": "==1.6.2"
+ "version": "==1.7.0"
},
"black": {
"hashes": [
- "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b",
- "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"
+ "sha256:dc132348a88d103016726fe360cb9ede02cecf99b76e3660ce6c596be132ce04",
+ "sha256:dfb8c5a069012b2ab1e972e7b908f5fb42b6bbabcba0a788b86dc05067c7d9c7"
],
"index": "pypi",
- "version": "==19.10b0"
+ "version": "==21.6b0"
},
"click": {
"hashes": [
- "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
- "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
+ "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a",
+ "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==7.1.2"
+ "markers": "python_version >= '3.6'",
+ "version": "==8.0.1"
},
"colorama": {
"hashes": [
@@ -394,64 +444,57 @@
"index": "pypi",
"version": "==0.4.4"
},
- "flake8": {
- "hashes": [
- "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839",
- "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"
- ],
- "index": "pypi",
- "version": "==3.8.4"
- },
"gitdb": {
"hashes": [
- "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac",
- "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"
+ "sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0",
+ "sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"
],
"markers": "python_version >= '3.4'",
- "version": "==4.0.5"
+ "version": "==4.0.7"
},
"gitpython": {
"hashes": [
- "sha256:42dbefd8d9e2576c496ed0059f3103dcef7125b9ce16f9d5f9c834aed44a1dac",
- "sha256:867ec3dfb126aac0f8296b19fb63b8c4a399f32b4b6fafe84c4b10af5fa9f7b5"
+ "sha256:b838a895977b45ab6f0cc926a9045c8d1c44e2b653c1fcc39fe91f42c6e8f05b",
+ "sha256:fce760879cd2aebd2991b3542876dc5c4a909b30c9d69dfc488e504a8db37ee8"
],
- "markers": "python_version >= '3.4'",
- "version": "==3.1.12"
+ "markers": "python_version >= '3.6'",
+ "version": "==3.1.18"
},
"isort": {
"hashes": [
- "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e",
- "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"
+ "sha256:eed17b53c3e7912425579853d078a0832820f023191561fcee9d7cae424e0813",
+ "sha256:f65ce5bd4cbc6abdfbe29afc2f0245538ab358c14590912df638033f157d555e"
],
- "markers": "python_version >= '3.6' and python_version < '4.0'",
- "version": "==5.7.0"
+ "markers": "python_version < '4.0' and python_full_version >= '3.6.1'",
+ "version": "==5.9.2"
},
"lazy-object-proxy": {
"hashes": [
- "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d",
- "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449",
- "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08",
- "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a",
- "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50",
- "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd",
- "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239",
- "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb",
- "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea",
- "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e",
- "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156",
- "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142",
- "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442",
- "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62",
- "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db",
- "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531",
- "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383",
- "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a",
- "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357",
- "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4",
- "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==1.4.3"
+ "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653",
+ "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61",
+ "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2",
+ "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837",
+ "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3",
+ "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43",
+ "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726",
+ "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3",
+ "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587",
+ "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8",
+ "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a",
+ "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd",
+ "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f",
+ "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad",
+ "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4",
+ "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b",
+ "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf",
+ "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981",
+ "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741",
+ "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e",
+ "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93",
+ "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"
+ ],
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
+ "version": "==1.6.0"
},
"mccabe": {
"hashes": [
@@ -460,124 +503,132 @@
],
"version": "==0.6.1"
},
- "pathspec": {
- "hashes": [
- "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd",
- "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"
- ],
- "version": "==0.8.1"
- },
- "pbr": {
+ "mypy-extensions": {
"hashes": [
- "sha256:5fad80b613c402d5b7df7bd84812548b2a61e9977387a80a5fc5c396492b13c9",
- "sha256:b236cde0ac9a6aedd5e3c34517b423cd4fd97ef723849da6b0d2231142d89c00"
+ "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
+ "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
],
- "markers": "python_version >= '2.6'",
- "version": "==5.5.1"
+ "version": "==0.4.3"
},
- "pycodestyle": {
+ "pathspec": {
"hashes": [
- "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367",
- "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"
+ "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a",
+ "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==2.6.0"
+ "version": "==0.9.0"
},
- "pyflakes": {
+ "pbr": {
"hashes": [
- "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92",
- "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"
+ "sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd",
+ "sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==2.2.0"
+ "markers": "python_version >= '2.6'",
+ "version": "==5.6.0"
},
"pylint": {
"hashes": [
- "sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210",
- "sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f"
+ "sha256:1f333dc72ef7f5ea166b3230936ebcfb1f3b722e76c980cb9fe6b9f95e8d3172",
+ "sha256:748f81e5776d6273a6619506e08f1b48ff9bcb8198366a56821cf11aac14fc87"
],
"index": "pypi",
- "version": "==2.6.0"
+ "version": "==2.9.5"
},
"pyyaml": {
"hashes": [
- "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97",
- "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76",
- "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2",
- "sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e",
- "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648",
- "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf",
- "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f",
- "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2",
- "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee",
- "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a",
- "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d",
- "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c",
- "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"
- ],
- "version": "==5.3.1"
+ "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf",
+ "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696",
+ "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393",
+ "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77",
+ "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922",
+ "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5",
+ "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8",
+ "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10",
+ "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc",
+ "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018",
+ "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e",
+ "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253",
+ "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347",
+ "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183",
+ "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541",
+ "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb",
+ "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185",
+ "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc",
+ "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db",
+ "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa",
+ "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46",
+ "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122",
+ "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b",
+ "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63",
+ "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df",
+ "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc",
+ "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247",
+ "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6",
+ "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"
+ ],
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
+ "version": "==5.4.1"
},
"regex": {
"hashes": [
- "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538",
- "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4",
- "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc",
- "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa",
- "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444",
- "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1",
- "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af",
- "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8",
- "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9",
- "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88",
- "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba",
- "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364",
- "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e",
- "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7",
- "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0",
- "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31",
- "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683",
- "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee",
- "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b",
- "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884",
- "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c",
- "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e",
- "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562",
- "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85",
- "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c",
- "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6",
- "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d",
- "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b",
- "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70",
- "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b",
- "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b",
- "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f",
- "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0",
- "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5",
- "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5",
- "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f",
- "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e",
- "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512",
- "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d",
- "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917",
- "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"
- ],
- "version": "==2020.11.13"
+ "sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f",
+ "sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad",
+ "sha256:173bc44ff95bc1e96398c38f3629d86fa72e539c79900283afa895694229fe6a",
+ "sha256:1c78780bf46d620ff4fff40728f98b8afd8b8e35c3efd638c7df67be2d5cddbf",
+ "sha256:2366fe0479ca0e9afa534174faa2beae87847d208d457d200183f28c74eaea59",
+ "sha256:2bceeb491b38225b1fee4517107b8491ba54fba77cf22a12e996d96a3c55613d",
+ "sha256:2ddeabc7652024803666ea09f32dd1ed40a0579b6fbb2a213eba590683025895",
+ "sha256:2fe5e71e11a54e3355fa272137d521a40aace5d937d08b494bed4529964c19c4",
+ "sha256:319eb2a8d0888fa6f1d9177705f341bc9455a2c8aca130016e52c7fe8d6c37a3",
+ "sha256:3f5716923d3d0bfb27048242a6e0f14eecdb2e2a7fac47eda1d055288595f222",
+ "sha256:422dec1e7cbb2efbbe50e3f1de36b82906def93ed48da12d1714cabcd993d7f0",
+ "sha256:4c9c3155fe74269f61e27617529b7f09552fbb12e44b1189cebbdb24294e6e1c",
+ "sha256:4f64fc59fd5b10557f6cd0937e1597af022ad9b27d454e182485f1db3008f417",
+ "sha256:564a4c8a29435d1f2256ba247a0315325ea63335508ad8ed938a4f14c4116a5d",
+ "sha256:59506c6e8bd9306cd8a41511e32d16d5d1194110b8cfe5a11d102d8b63cf945d",
+ "sha256:598c0a79b4b851b922f504f9f39a863d83ebdfff787261a5ed061c21e67dd761",
+ "sha256:59c00bb8dd8775473cbfb967925ad2c3ecc8886b3b2d0c90a8e2707e06c743f0",
+ "sha256:6110bab7eab6566492618540c70edd4d2a18f40ca1d51d704f1d81c52d245026",
+ "sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854",
+ "sha256:791aa1b300e5b6e5d597c37c346fb4d66422178566bbb426dd87eaae475053fb",
+ "sha256:8394e266005f2d8c6f0bc6780001f7afa3ef81a7a2111fa35058ded6fce79e4d",
+ "sha256:875c355360d0f8d3d827e462b29ea7682bf52327d500a4f837e934e9e4656068",
+ "sha256:89e5528803566af4df368df2d6f503c84fbfb8249e6631c7b025fe23e6bd0cde",
+ "sha256:99d8ab206a5270c1002bfcf25c51bf329ca951e5a169f3b43214fdda1f0b5f0d",
+ "sha256:9a854b916806c7e3b40e6616ac9e85d3cdb7649d9e6590653deb5b341a736cec",
+ "sha256:b85ac458354165405c8a84725de7bbd07b00d9f72c31a60ffbf96bb38d3e25fa",
+ "sha256:bc84fb254a875a9f66616ed4538542fb7965db6356f3df571d783f7c8d256edd",
+ "sha256:c92831dac113a6e0ab28bc98f33781383fe294df1a2c3dfd1e850114da35fd5b",
+ "sha256:cbe23b323988a04c3e5b0c387fe3f8f363bf06c0680daf775875d979e376bd26",
+ "sha256:ccb3d2190476d00414aab36cca453e4596e8f70a206e2aa8db3d495a109153d2",
+ "sha256:d8bbce0c96462dbceaa7ac4a7dfbbee92745b801b24bce10a98d2f2b1ea9432f",
+ "sha256:db2b7df831c3187a37f3bb80ec095f249fa276dbe09abd3d35297fc250385694",
+ "sha256:e586f448df2bbc37dfadccdb7ccd125c62b4348cb90c10840d695592aa1b29e0",
+ "sha256:e5983c19d0beb6af88cb4d47afb92d96751fb3fa1784d8785b1cdf14c6519407",
+ "sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874",
+ "sha256:eaf58b9e30e0e546cdc3ac06cf9165a1ca5b3de8221e9df679416ca667972035",
+ "sha256:ed693137a9187052fc46eedfafdcb74e09917166362af4cc4fddc3b31560e93d",
+ "sha256:edd1a68f79b89b0c57339bce297ad5d5ffcc6ae7e1afdb10f1947706ed066c9c",
+ "sha256:f080248b3e029d052bf74a897b9d74cfb7643537fbde97fe8225a6467fb559b5",
+ "sha256:f9392a4555f3e4cb45310a65b403d86b589adc773898c25a39184b1ba4db8985",
+ "sha256:f98dc35ab9a749276f1a4a38ab3e0e2ba1662ce710f6530f5b0a6656f1c32b58"
+ ],
+ "version": "==2021.7.6"
},
"six": {
"hashes": [
- "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
- "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
+ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
+ "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
- "version": "==1.15.0"
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "version": "==1.16.0"
},
"smmap": {
"hashes": [
- "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4",
- "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"
+ "sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182",
+ "sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==3.0.4"
+ "markers": "python_version >= '3.5'",
+ "version": "==4.0.0"
},
"stevedore": {
"hashes": [
@@ -592,44 +643,9 @@
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
- "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'",
+ "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.2"
},
- "typed-ast": {
- "hashes": [
- "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1",
- "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d",
- "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6",
- "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd",
- "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37",
- "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151",
- "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07",
- "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440",
- "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70",
- "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496",
- "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea",
- "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400",
- "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc",
- "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606",
- "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc",
- "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581",
- "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412",
- "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a",
- "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2",
- "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787",
- "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f",
- "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937",
- "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64",
- "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487",
- "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b",
- "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41",
- "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a",
- "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3",
- "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166",
- "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"
- ],
- "version": "==1.4.2"
- },
"wrapt": {
"hashes": [
"sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"
diff --git a/README.md b/README.md
index 9d90568bc8..19931575c9 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,11 @@
+<<<<<<< HEAD
+=======
+
+>>>>>>> master
@@ -188,6 +192,13 @@ Real Madrid:
+
+
+Discord Advice Center:
+
+
+
+
Become a sponsor on [Patreon](https://patreon.com/kyber).
diff --git a/SPONSORS.json b/SPONSORS.json
index 53034c57b3..30081e24e5 100644
--- a/SPONSORS.json
+++ b/SPONSORS.json
@@ -21,7 +21,7 @@
"value": "[**Click Here**](https://www.youtube.com/channel/UCgSmBJD9imASmJRleycTCwQ?sub_confirmation=1)"
},
{
- "name": "Discord Server!",
+ "name": "Discord Server",
"value": "[**Click Here**](https://discord.gg/V8ErqHb)"
}
]
@@ -37,7 +37,7 @@
},
"fields": [
{
- "name": "Discord Server!",
+ "name": "Discord Server",
"value": "[**Click here**](https://discord.gg/BanCwptMJV)"
}
]
@@ -46,7 +46,7 @@
{
"embed": {
"description": "Quality Hosting at Prices You Deserve!",
- "color": 50195251,
+ "color": 3137203,
"footer": {
"icon_url": "https://primeserversinc.com/images/Prime_Logo_P_Sassy.png",
"text": "Prime Servers, Inc."
@@ -70,5 +70,25 @@
}
]
}
+ },
+ {
+ "embed": {
+ "description": "──── 《𝐃𝐢𝐬𝐜𝐨𝐫𝐝 𝐀𝐝𝐯𝐢𝐜𝐞 𝐂𝐞𝐧𝐭𝐞𝐫 》 ────\n\n◈ We are a server aimed to meet your discord needs. We have tools, tricks and tips to grow your server and advertise your server. We offer professional server reviews and suggestions how to run it successfully as a part of our courtesy. Join the server and get the chance to add our very own BUMP BOT called DAC Advertise where you can advertise your server to other servers!\n",
+ "color": 53380,
+ "author": {
+ "name": "Discord Advice Center",
+ "url": "https://discord.gg/nkMDQfuK",
+ "icon_url": "https://i.imgur.com/cjVtRw5.jpg"
+ },
+ "image": {
+ "url": "https://i.imgur.com/1hrjcHd.png"
+ },
+ "fields": [
+ {
+ "name": "Discord Server",
+ "value": "[**Click Here**](https://discord.gg/zmwZy5fd9v)"
+ }
+ ]
+ }
}
]
diff --git a/bot.py b/bot.py
index 8961001ab1..4c235dedad 100644
--- a/bot.py
+++ b/bot.py
@@ -1,4 +1,8 @@
+<<<<<<< HEAD
__version__ = "v3.10.0-dev3"
+=======
+__version__ = "3.9.5"
+>>>>>>> master
import asyncio
@@ -325,9 +329,7 @@ def log_channel(self) -> typing.Optional[discord.TextChannel]:
try:
channel = self.main_category.channels[0]
self.config["log_channel_id"] = channel.id
- logger.warning(
- "No log channel set, setting #%s to be the log channel.", channel.name
- )
+ logger.warning("No log channel set, setting #%s to be the log channel.", channel.name)
return channel
except IndexError:
pass
@@ -389,9 +391,7 @@ def auto_triggers(self) -> typing.Dict[str, str]:
def token(self) -> str:
token = self.config["token"]
if token is None:
- logger.critical(
- "TOKEN must be set, set this as bot token found on the Discord Developer Portal."
- )
+ logger.critical("TOKEN must be set, set this as bot token found on the Discord Developer Portal.")
sys.exit(0)
return token
@@ -507,11 +507,7 @@ def command_perm(self, command_name: str) -> PermissionLevel:
logger.debug("Command %s not found.", command_name)
return PermissionLevel.INVALID
level = next(
- (
- check.permission_level
- for check in command.checks
- if hasattr(check, "permission_level")
- ),
+ (check.permission_level for check in command.checks if hasattr(check, "permission_level")),
None,
)
if level is None:
@@ -524,7 +520,7 @@ async def on_connect(self):
await self.api.validate_database_connection()
except Exception:
logger.debug("Logging out due to failed database connection.")
- return await self.logout()
+ return await self.close()
logger.debug("Connected to gateway.")
await self.config.refresh()
@@ -539,15 +535,14 @@ async def on_ready(self):
if self.guild is None:
logger.error("Logging out due to invalid GUILD_ID.")
- return await self.logout()
+ return await self.close()
logger.line()
logger.debug("Client ready.")
logger.info("Logged in as: %s", self.user)
logger.info("Bot ID: %s", self.user.id)
owners = ", ".join(
- getattr(self.get_user(owner_id), "name", str(owner_id))
- for owner_id in self.bot_owner_ids
+ getattr(self.get_user(owner_id), "name", str(owner_id)) for owner_id in self.bot_owner_ids
)
logger.info("Owners: %s", owners)
logger.info("Prefix: %s", self.prefix)
@@ -570,9 +565,7 @@ async def on_ready(self):
logger.debug("Closing thread for recipient %s.", recipient_id)
after = 0
else:
- logger.debug(
- "Thread for recipient %s will be closed after %s seconds.", recipient_id, after
- )
+ logger.debug("Thread for recipient %s will be closed after %s seconds.", recipient_id, after)
thread = await self.threads.find(recipient_id=int(recipient_id))
@@ -614,9 +607,7 @@ async def on_ready(self):
if log_data:
logger.debug("Successfully closed thread with channel %s.", log["channel_id"])
else:
- logger.debug(
- "Failed to close thread with channel %s, skipping.", log["channel_id"]
- )
+ logger.debug("Failed to close thread with channel %s, skipping.", log["channel_id"])
if self.config.get("data_collection"):
self.metadata_loop = tasks.Loop(
@@ -637,9 +628,7 @@ async def on_ready(self):
self.autoupdate_loop.before_loop(self.before_autoupdate)
self.autoupdate_loop.start()
- other_guilds = [
- guild for guild in self.guilds if guild not in {self.guild, self.modmail_guild}
- ]
+ other_guilds = [guild for guild in self.guilds if guild not in {self.guild, self.modmail_guild}]
if any(other_guilds):
logger.warning(
"The bot is in more servers other than the main and staff server. "
@@ -652,7 +641,7 @@ async def convert_emoji(self, name: str) -> str:
ctx = SimpleNamespace(bot=self, guild=self.modmail_guild)
converter = commands.EmojiConverter()
- if name not in UNICODE_EMOJI:
+ if name not in UNICODE_EMOJI["en"]:
try:
name = await converter.convert(ctx, name.strip(":"))
except commands.BadArgument as e:
@@ -877,9 +866,7 @@ async def get_thread_cooldown(self, author: discord.Member):
cooldown = datetime.fromisoformat(last_log_closed_at) + thread_cooldown
except ValueError:
logger.warning("Error with 'thread_cooldown'.", exc_info=True)
- cooldown = datetime.fromisoformat(last_log_closed_at) + self.config.remove(
- "thread_cooldown"
- )
+ cooldown = datetime.fromisoformat(last_log_closed_at) + self.config.remove("thread_cooldown")
if cooldown > now:
# User messaged before thread cooldown ended
@@ -927,12 +914,8 @@ async def process_dm_modmail(self, message: discord.Message) -> None:
color=self.error_color,
description=self.config["disabled_new_thread_response"],
)
- embed.set_footer(
- text=self.config["disabled_new_thread_footer"], icon_url=self.guild.icon_url
- )
- logger.info(
- "A new thread was blocked from %s due to disabled Modmail.", message.author
- )
+ embed.set_footer(text=self.config["disabled_new_thread_footer"], icon_url=self.guild.icon_url)
+ logger.info("A new thread was blocked from %s due to disabled Modmail.", message.author)
await self.add_reaction(message, blocked_emoji)
return await message.channel.send(embed=embed)
@@ -948,9 +931,7 @@ async def process_dm_modmail(self, message: discord.Message) -> None:
text=self.config["disabled_current_thread_footer"],
icon_url=self.guild.icon_url,
)
- logger.info(
- "A message was blocked from %s due to disabled Modmail.", message.author
- )
+ logger.info("A message was blocked from %s due to disabled Modmail.", message.author)
await self.add_reaction(message, blocked_emoji)
return await message.channel.send(embed=embed)
@@ -1031,15 +1012,11 @@ async def trigger_auto_triggers(self, message, channel, *, cls=commands.Context)
invoker = None
if self.config.get("use_regex_autotrigger"):
- trigger = next(
- filter(lambda x: re.search(x, message.content), self.auto_triggers.keys())
- )
+ trigger = next(filter(lambda x: re.search(x, message.content), self.auto_triggers.keys()))
if trigger:
invoker = re.search(trigger, message.content).group(0)
else:
- trigger = next(
- filter(lambda x: x.lower() in message.content.lower(), self.auto_triggers.keys())
- )
+ trigger = next(filter(lambda x: x.lower() in message.content.lower(), self.auto_triggers.keys()))
if trigger:
invoker = trigger.lower()
@@ -1175,9 +1152,7 @@ async def process_commands(self, message):
ctxs = await self.get_contexts(message)
for ctx in ctxs:
if ctx.command:
- if not any(
- 1 for check in ctx.command.checks if hasattr(check, "permission_level")
- ):
+ if not any(1 for check in ctx.command.checks if hasattr(check, "permission_level")):
logger.debug(
"Command %s has no permissions check, adding invalid level.",
ctx.command.qualified_name,
@@ -1205,9 +1180,7 @@ async def process_commands(self, message):
else:
await self.api.append_log(message, type_="internal")
elif ctx.invoked_with:
- exc = commands.CommandNotFound(
- 'Command "{}" is not found'.format(ctx.invoked_with)
- )
+ exc = commands.CommandNotFound('Command "{}" is not found'.format(ctx.invoked_with))
self.dispatch("command_error", ctx, exc)
async def on_typing(self, channel, user, _):
@@ -1282,9 +1255,7 @@ async def handle_reaction_events(self, payload):
if not thread.recipient.dm_channel:
await thread.recipient.create_dm()
try:
- linked_message = await thread.find_linked_message_from_dm(
- message, either_direction=True
- )
+ linked_message = await thread.find_linked_message_from_dm(message, either_direction=True)
except ValueError as e:
logger.warning("Failed to find linked message for reactions: %s", e)
return
@@ -1293,9 +1264,13 @@ async def handle_reaction_events(self, payload):
if not thread:
return
try:
+<<<<<<< HEAD
_, *linked_message = await thread.find_linked_messages(
message.id, either_direction=True
)
+=======
+ _, linked_message = await thread.find_linked_messages(message.id, either_direction=True)
+>>>>>>> master
except ValueError as e:
logger.warning("Failed to find linked message for reactions: %s", e)
return
@@ -1326,6 +1301,7 @@ async def handle_react_to_contact(self, payload):
else:
emoji_fmt = f"<:{payload.emoji.name}:{payload.emoji.id}>"
+<<<<<<< HEAD
if emoji_fmt != react_message_emoji:
return
channel = self.get_channel(payload.channel_id)
@@ -1358,6 +1334,11 @@ async def on_raw_reaction_add(self, payload):
await asyncio.gather(
self.handle_reaction_events(payload), self.handle_react_to_contact(payload),
)
+=======
+ ctx = await self.get_context(message)
+ ctx.author = member
+ await ctx.invoke(self.get_command("contact"), user=member, manual_trigger=False)
+>>>>>>> master
async def on_raw_reaction_remove(self, payload):
if self.config["transfer_reactions"]:
@@ -1383,9 +1364,7 @@ async def on_guild_channel_delete(self, channel):
await self.config.update()
return
- audit_logs = self.modmail_guild.audit_logs(
- limit=10, action=discord.AuditLogAction.channel_delete
- )
+ audit_logs = self.modmail_guild.audit_logs(limit=10, action=discord.AuditLogAction.channel_delete)
entry = await audit_logs.find(lambda a: int(a.target.id) == channel.id)
if entry is None:
@@ -1423,9 +1402,7 @@ async def on_member_join(self, member):
return
thread = await self.threads.find(recipient=member)
if thread:
- embed = discord.Embed(
- description="The recipient has joined the server.", color=self.mod_color
- )
+ embed = discord.Embed(description="The recipient has joined the server.", color=self.mod_color)
await thread.channel.send(embed=embed)
async def on_message_delete(self, message):
@@ -1458,9 +1435,7 @@ async def on_message_delete(self, message):
if not thread:
return
- audit_logs = self.modmail_guild.audit_logs(
- limit=10, action=discord.AuditLogAction.message_delete
- )
+ audit_logs = self.modmail_guild.audit_logs(limit=10, action=discord.AuditLogAction.message_delete)
entry = await audit_logs.find(lambda a: a.target == self.user)
@@ -1469,15 +1444,11 @@ async def on_message_delete(self, message):
try:
await thread.delete_message(message, note=False)
- embed = discord.Embed(
- description="Successfully deleted message.", color=self.main_color
- )
+ embed = discord.Embed(description="Successfully deleted message.", color=self.main_color)
except ValueError as e:
if str(e) not in {"DM message not found.", "Malformed thread message."}:
logger.debug("Failed to find linked message to delete: %s", e)
- embed = discord.Embed(
- description="Failed to delete message.", color=self.error_color
- )
+ embed = discord.Embed(description="Failed to delete message.", color=self.error_color)
else:
return
except discord.NotFound:
@@ -1505,9 +1476,7 @@ async def on_message_edit(self, before, after):
_, blocked_emoji = await self.retrieve_emoji()
await self.add_reaction(after, blocked_emoji)
else:
- embed = discord.Embed(
- description="Successfully Edited Message", color=self.main_color
- )
+ embed = discord.Embed(description="Successfully Edited Message", color=self.main_color)
embed.set_footer(text=f"Message ID: {after.id}")
await after.channel.send(embed=embed)
@@ -1518,9 +1487,7 @@ async def on_error(self, event_method, *args, **kwargs):
async def on_command_error(self, context, exception):
if isinstance(exception, commands.BadArgument):
await context.trigger_typing()
- await context.send(
- embed=discord.Embed(color=self.error_color, description=str(exception))
- )
+ await context.send(embed=discord.Embed(color=self.error_color, description=str(exception)))
elif isinstance(exception, commands.CommandNotFound):
logger.warning("CommandNotFound: %s", exception)
elif isinstance(exception, commands.MissingRequiredArgument):
@@ -1541,9 +1508,7 @@ async def on_command_error(self, context, exception):
embed=discord.Embed(color=self.error_color, description=check.fail_msg)
)
if hasattr(check, "permission_level"):
- corrected_permission_level = self.command_perm(
- context.command.qualified_name
- )
+ corrected_permission_level = self.command_perm(context.command.qualified_name)
logger.warning(
"User %s does not have permission to use this command: `%s` (%s).",
context.author.name,
@@ -1552,9 +1517,7 @@ async def on_command_error(self, context, exception):
)
logger.warning("CheckFailure: %s", exception)
elif isinstance(exception, commands.DisabledCommand):
- logger.info(
- "DisabledCommand: %s is trying to run eval but it's disabled", context.author.name
- )
+ logger.info("DisabledCommand: %s is trying to run eval but it's disabled", context.author.name)
else:
logger.error("Unexpected exception:", exc_info=exception)
@@ -1578,9 +1541,7 @@ async def post_metadata(self):
if info.team is not None:
data.update(
{
- "owner_name": info.team.owner.name
- if info.team.owner is not None
- else "No Owner",
+ "owner_name": info.team.owner.name if info.team.owner is not None else "No Owner",
"owner_id": info.team.owner_id,
"team": True,
}
@@ -1642,7 +1603,11 @@ async def autoupdate(self):
pass
command = "git pull"
- proc = await asyncio.create_subprocess_shell(command, stderr=PIPE, stdout=PIPE,)
+ proc = await asyncio.create_subprocess_shell(
+ command,
+ stderr=PIPE,
+ stdout=PIPE,
+ )
err = await proc.stderr.read()
err = err.decode("utf-8").rstrip()
res = await proc.stdout.read()
@@ -1658,9 +1623,7 @@ async def autoupdate(self):
channel = self.update_channel
if self.hosting_method in (HostingMethod.PM2, HostingMethod.SYSTEMD):
embed = discord.Embed(title="Bot has been updated", color=self.main_color)
- embed.set_footer(
- text=f"Updating Modmail v{self.version} " f"-> v{latest.version}"
- )
+ embed.set_footer(text=f"Updating Modmail v{self.version} " f"-> v{latest.version}")
if self.config["update_notifications"]:
await channel.send(embed=embed)
else:
@@ -1669,12 +1632,10 @@ async def autoupdate(self):
description="If you do not have an auto-restart setup, please manually start the bot.",
color=self.main_color,
)
- embed.set_footer(
- text=f"Updating Modmail v{self.version} " f"-> v{latest.version}"
- )
+ embed.set_footer(text=f"Updating Modmail v{self.version} " f"-> v{latest.version}")
if self.config["update_notifications"]:
await channel.send(embed=embed)
- await self.logout()
+ return await self.close()
async def before_autoupdate(self):
await self.wait_for_connected()
@@ -1705,9 +1666,9 @@ def main():
pass
# check discord version
- if discord.__version__ != "1.6.0":
+ if discord.__version__ != "1.7.3":
logger.error(
- "Dependencies are not updated, run pipenv install. discord.py version expected 1.6.0, received %s",
+ "Dependencies are not updated, run pipenv install. discord.py version expected 1.7.3, received %s",
discord.__version__,
)
sys.exit(0)
diff --git a/cogs/modmail.py b/cogs/modmail.py
index ef816a99c3..4e6c1fc126 100644
--- a/cogs/modmail.py
+++ b/cogs/modmail.py
@@ -42,9 +42,7 @@ async def setup(self, ctx):
"""
if ctx.guild != self.bot.modmail_guild:
- return await ctx.send(
- f"You can only setup in the Modmail guild: {self.bot.modmail_guild}."
- )
+ return await ctx.send(f"You can only setup in the Modmail guild: {self.bot.modmail_guild}.")
if self.bot.main_category is not None:
logger.debug("Can't re-setup server, main_category is found.")
@@ -79,15 +77,11 @@ async def setup(self, ctx):
logger.info("Granting %s access to Modmail category.", key.name)
overwrites[key] = discord.PermissionOverwrite(read_messages=True)
- category = await self.bot.modmail_guild.create_category(
- name="Modmail", overwrites=overwrites
- )
+ category = await self.bot.modmail_guild.create_category(name="Modmail", overwrites=overwrites)
await category.edit(position=0)
- log_channel = await self.bot.modmail_guild.create_text_channel(
- name="bot-logs", category=category
- )
+ log_channel = await self.bot.modmail_guild.create_text_channel(name="bot-logs", category=category)
embed = discord.Embed(
title="Friendly Reminder",
@@ -328,7 +322,9 @@ async def move(self, ctx, *, arguments):
silent_words = ["silent", "silently"]
silent = any(word in silent_words for word in options.split())
- await thread.channel.edit(category=category, sync_permissions=True)
+ await thread.channel.move(
+ category=category, end=True, sync_permissions=True, reason=f"{ctx.author} moved this thread."
+ )
if self.bot.config["thread_move_notify"] and not silent:
embed = discord.Embed(
@@ -434,9 +430,7 @@ def parse_user_or_role(ctx, user_or_role):
@commands.command(aliases=["alert"])
@checks.has_permissions(PermissionLevel.SUPPORTER)
@checks.thread_only()
- async def notify(
- self, ctx, *, user_or_role: Union[discord.Role, User, str.lower, None] = None
- ):
+ async def notify(self, ctx, *, user_or_role: Union[discord.Role, User, str.lower, None] = None):
"""
Notify a user or role when the next thread message received.
@@ -474,9 +468,7 @@ async def notify(
@commands.command(aliases=["unalert"])
@checks.has_permissions(PermissionLevel.SUPPORTER)
@checks.thread_only()
- async def unnotify(
- self, ctx, *, user_or_role: Union[discord.Role, User, str.lower, None] = None
- ):
+ async def unnotify(self, ctx, *, user_or_role: Union[discord.Role, User, str.lower, None] = None):
"""
Un-notify a user, role, or yourself from a thread.
@@ -511,9 +503,7 @@ async def unnotify(
@commands.command(aliases=["sub"])
@checks.has_permissions(PermissionLevel.SUPPORTER)
@checks.thread_only()
- async def subscribe(
- self, ctx, *, user_or_role: Union[discord.Role, User, str.lower, None] = None
- ):
+ async def subscribe(self, ctx, *, user_or_role: Union[discord.Role, User, str.lower, None] = None):
"""
Notify a user, role, or yourself for every thread message received.
@@ -537,7 +527,7 @@ async def subscribe(
if mention in mentions:
embed = discord.Embed(
color=self.bot.error_color,
- description=f"{mention} is not subscribed to this thread.",
+ description=f"{mention} is already subscribed to this thread.",
)
else:
mentions.append(mention)
@@ -551,9 +541,7 @@ async def subscribe(
@commands.command(aliases=["unsub"])
@checks.has_permissions(PermissionLevel.SUPPORTER)
@checks.thread_only()
- async def unsubscribe(
- self, ctx, *, user_or_role: Union[discord.Role, User, str.lower, None] = None
- ):
+ async def unsubscribe(self, ctx, *, user_or_role: Union[discord.Role, User, str.lower, None] = None):
"""
Unsubscribe a user, role, or yourself from a thread.
@@ -638,7 +626,9 @@ def format_log_embeds(self, logs, avatar_url):
prefix = self.bot.config["log_url_prefix"].strip("/")
if prefix == "NONE":
prefix = ""
- log_url = f"{self.bot.config['log_url'].strip('/')}{'/' + prefix if prefix else ''}/{entry['key']}"
+ log_url = (
+ f"{self.bot.config['log_url'].strip('/')}{'/' + prefix if prefix else ''}/{entry['key']}"
+ )
username = entry["recipient"]["name"] + "#"
username += entry["recipient"]["discriminator"]
@@ -988,9 +978,7 @@ async def note_persistent(self, ctx, *, msg: str = ""):
async with ctx.typing():
msg = await ctx.thread.note(ctx.message, persistent=True)
await msg.pin()
- await self.bot.api.create_note(
- recipient=ctx.thread.recipient, message=ctx.message, message_id=msg.id
- )
+ await self.bot.api.create_note(recipient=ctx.thread.recipient, message=ctx.message, message_id=msg.id)
@commands.command()
@checks.has_permissions(PermissionLevel.SUPPORTER)
@@ -1053,18 +1041,23 @@ async def contact(
category = None
if user.bot:
- embed = discord.Embed(
- color=self.bot.error_color, description="Cannot start a thread with a bot."
- )
+ embed = discord.Embed(color=self.bot.error_color, description="Cannot start a thread with a bot.")
return await ctx.send(embed=embed, delete_after=3)
exists = await self.bot.threads.find(recipient=user)
if exists:
+<<<<<<< HEAD
desc = "A thread for this user already exists"
if exists.channel:
desc += f" in {exists.channel.mention}"
desc += "."
embed = discord.Embed(color=self.bot.error_color, description=desc)
+=======
+ embed = discord.Embed(
+ color=self.bot.error_color,
+ description="A thread for this user already " f"exists in {exists.channel.mention}.",
+ )
+>>>>>>> master
await ctx.channel.send(embed=embed, delete_after=3)
else:
@@ -1096,7 +1089,9 @@ async def contact(
description = f"{creator.name} has opened a Modmail thread."
em = discord.Embed(
- title="New Thread", description=description, color=self.bot.main_color,
+ title="New Thread",
+ description=description,
+ color=self.bot.main_color,
)
if self.bot.config["show_timestamp"]:
em.timestamp = datetime.utcnow()
@@ -1204,9 +1199,7 @@ async def blocked(self, ctx):
else:
embeds[0].description = "Currently there are no blocked users."
- embeds.append(
- discord.Embed(title="Blocked Roles", color=self.bot.main_color, description="")
- )
+ embeds.append(discord.Embed(title="Blocked Roles", color=self.bot.main_color, description=""))
if roles:
embed = embeds[-1]
@@ -1392,10 +1385,7 @@ async def unblock(self, ctx, *, user_or_role: Union[User, Role] = None):
mention = getattr(user_or_role, "mention", f"`{user_or_role.id}`")
name = getattr(user_or_role, "name", f"`{user_or_role.id}`")
- if (
- not isinstance(user_or_role, discord.Role)
- and str(user_or_role.id) in self.bot.blocked_users
- ):
+ if not isinstance(user_or_role, discord.Role) and str(user_or_role.id) in self.bot.blocked_users:
msg = self.bot.blocked_users.pop(str(user_or_role.id)) or ""
await self.bot.config.update()
@@ -1420,10 +1410,7 @@ async def unblock(self, ctx, *, user_or_role: Union[User, Role] = None):
color=self.bot.main_color,
description=f"{mention} is no longer blocked.",
)
- elif (
- isinstance(user_or_role, discord.Role)
- and str(user_or_role.id) in self.bot.blocked_roles
- ):
+ elif isinstance(user_or_role, discord.Role) and str(user_or_role.id) in self.bot.blocked_roles:
msg = self.bot.blocked_roles.pop(str(user_or_role.id)) or ""
await self.bot.config.update()
@@ -1520,12 +1507,8 @@ async def repair(self, ctx):
self.bot.threads, recipient, ctx.channel, other_recipients
)
thread.ready = True
- logger.info(
- "Setting current channel's topic to User ID and created new thread."
- )
- await ctx.channel.edit(
- reason="Fix broken Modmail thread", topic=f"User ID: {user_id}"
- )
+ logger.info("Setting current channel's topic to User ID and created new thread.")
+ await ctx.channel.edit(reason="Fix broken Modmail thread", topic=f"User ID: {user_id}")
return await self.bot.add_reaction(ctx.message, sent_emoji)
else:
@@ -1537,8 +1520,7 @@ async def repair(self, ctx):
if m is not None:
users = set(
filter(
- lambda member: member.name == m.group(1)
- and member.discriminator == m.group(2),
+ lambda member: member.name == m.group(1) and member.discriminator == m.group(2),
ctx.guild.members,
)
)
@@ -1568,9 +1550,13 @@ async def repair(self, ctx):
other_recipients[n] = self.bot.get_user(uid) or await self.bot.fetch_user(uid)
if recipient is None:
+<<<<<<< HEAD
self.bot.threads.cache[user.id] = thread = Thread(
self.bot.threads, user_id, ctx.channel, other_recipients
)
+=======
+ self.bot.threads.cache[user.id] = thread = Thread(self.bot.threads, user_id, ctx.channel)
+>>>>>>> master
else:
self.bot.threads.cache[user.id] = thread = Thread(
self.bot.threads, recipient, ctx.channel, other_recipients
diff --git a/cogs/plugins.py b/cogs/plugins.py
index 94a3f425c0..aab5dc8bd6 100644
--- a/cogs/plugins.py
+++ b/cogs/plugins.py
@@ -251,12 +251,8 @@ async def load_plugin(self, plugin):
if stderr:
logger.debug("[stderr]\n%s.", stderr.decode())
- logger.error(
- "Failed to download requirements for %s.", plugin.ext_string, exc_info=True
- )
- raise InvalidPluginError(
- f"Unable to download requirements: ```\n{stderr.decode()}\n```"
- )
+ logger.error("Failed to download requirements for %s.", plugin.ext_string, exc_info=True)
+ raise InvalidPluginError(f"Unable to download requirements: ```\n{stderr.decode()}\n```")
if os.path.exists(USER_SITE):
sys.path.insert(0, USER_SITE)
@@ -347,9 +343,7 @@ async def plugins_add(self, ctx, *, plugin_name: str):
return
if str(plugin) in self.bot.config["plugins"]:
- embed = discord.Embed(
- description="This plugin is already installed.", color=self.bot.error_color
- )
+ embed = discord.Embed(description="This plugin is already installed.", color=self.bot.error_color)
return await ctx.send(embed=embed)
if plugin.name in self.bot.cogs:
@@ -433,9 +427,7 @@ async def plugins_remove(self, ctx, *, plugin_name: str):
return
if str(plugin) not in self.bot.config["plugins"]:
- embed = discord.Embed(
- description="Plugin is not installed.", color=self.bot.error_color
- )
+ embed = discord.Embed(description="Plugin is not installed.", color=self.bot.error_color)
return await ctx.send(embed=embed)
if self.bot.config.get("enable_plugins"):
@@ -472,9 +464,7 @@ async def update_plugin(self, ctx, plugin_name):
return
if str(plugin) not in self.bot.config["plugins"]:
- embed = discord.Embed(
- description="Plugin is not installed.", color=self.bot.error_color
- )
+ embed = discord.Embed(description="Plugin is not installed.", color=self.bot.error_color)
return await ctx.send(embed=embed)
async with ctx.typing():
@@ -598,9 +588,7 @@ async def plugins_loaded(self, ctx):
embeds = []
for page in pages:
- embed = discord.Embed(
- title="Loaded plugins:", description=page, color=self.bot.main_color
- )
+ embed = discord.Embed(title="Loaded plugins:", description=page, color=self.bot.main_color)
embeds.append(embed)
paginator = EmbedPaginatorSession(ctx, *embeds)
await paginator.run()
@@ -641,9 +629,7 @@ async def plugins_registry(self, ctx, *, plugin_name: typing.Union[int, str] = N
matches = get_close_matches(plugin_name, self.registry.keys())
if matches:
- embed.add_field(
- name="Perhaps you meant:", value="\n".join(f"`{m}`" for m in matches)
- )
+ embed.add_field(name="Perhaps you meant:", value="\n".join(f"`{m}`" for m in matches))
return await ctx.send(embed=embed)
@@ -661,13 +647,9 @@ async def plugins_registry(self, ctx, *, plugin_name: typing.Union[int, str] = N
title=details["repository"],
)
- embed.add_field(
- name="Installation", value=f"```{self.bot.prefix}plugins add {name}```"
- )
+ embed.add_field(name="Installation", value=f"```{self.bot.prefix}plugins add {name}```")
- embed.set_author(
- name=details["title"], icon_url=details.get("icon_url"), url=plugin.link
- )
+ embed.set_author(name=details["title"], icon_url=details.get("icon_url"), url=plugin.link)
if details.get("thumbnail_url"):
embed.set_thumbnail(url=details.get("thumbnail_url"))
diff --git a/cogs/utility.py b/cogs/utility.py
index 0790274c57..db3fa8e746 100644
--- a/cogs/utility.py
+++ b/cogs/utility.py
@@ -184,9 +184,7 @@ async def send_error_message(self, error):
command = self.context.kwargs.get("command")
val = self.context.bot.snippets.get(command)
if val is not None:
- embed = discord.Embed(
- title=f"{command} is a snippet.", color=self.context.bot.main_color
- )
+ embed = discord.Embed(title=f"{command} is a snippet.", color=self.context.bot.main_color)
embed.add_field(name=f"`{command}` will send:", value=val)
return await self.get_destination().send(embed=embed)
@@ -206,9 +204,7 @@ async def send_error_message(self, error):
await self.context.bot.config.update()
else:
if len(values) == 1:
- embed = discord.Embed(
- title=f"{command} is an alias.", color=self.context.bot.main_color
- )
+ embed = discord.Embed(title=f"{command} is an alias.", color=self.context.bot.main_color)
embed.add_field(name=f"`{command}` points to:", value=values[0])
else:
embed = discord.Embed(
@@ -330,12 +326,8 @@ async def about(self, ctx):
latest = changelog.latest_version
if self.bot.version.is_prerelease:
- stable = next(
- filter(lambda v: not parse_version(v.version).is_prerelease, changelog.versions)
- )
- footer = (
- f"You are on the prerelease version • the latest version is v{stable.version}."
- )
+ stable = next(filter(lambda v: not parse_version(v.version).is_prerelease, changelog.versions))
+ footer = f"You are on the prerelease version • the latest version is v{stable.version}."
elif self.bot.version < parse_version(latest.version):
footer = f"A newer version is available v{latest.version}."
else:
@@ -356,18 +348,25 @@ async def about(self, ctx):
inline=False,
)
+ embed.add_field(
+ name="Project Sponsors",
+ value=f"Checkout the people who supported Modmail with command `{self.bot.prefix}sponsors`!",
+ inline=False,
+ )
+
embed.set_footer(text=footer)
await ctx.send(embed=embed)
- @commands.command()
+ @commands.command(aliases=["sponsor"])
@checks.has_permissions(PermissionLevel.REGULAR)
@utils.trigger_typing
async def sponsors(self, ctx):
- """Shows a list of sponsors."""
- resp = await self.bot.session.get(
+ """Shows the sponsors of this project."""
+
+ async with self.bot.session.get(
"https://raw.githubusercontent.com/kyb3r/modmail/master/SPONSORS.json"
- )
- data = loads(await resp.text())
+ ) as resp:
+ data = loads(await resp.text())
embeds = []
@@ -389,9 +388,7 @@ async def debug(self, ctx):
log_file_name = self.bot.token.split(".")[0]
with open(
- os.path.join(
- os.path.dirname(os.path.abspath(__file__)), f"../temp/{log_file_name}.log"
- ),
+ os.path.join(os.path.dirname(os.path.abspath(__file__)), f"../temp/{log_file_name}.log"),
"r+",
encoding="utf-8",
) as f:
@@ -445,9 +442,7 @@ async def debug_hastebin(self, ctx):
log_file_name = self.bot.token.split(".")[0]
with open(
- os.path.join(
- os.path.dirname(os.path.abspath(__file__)), f"../temp/{log_file_name}.log"
- ),
+ os.path.join(os.path.dirname(os.path.abspath(__file__)), f"../temp/{log_file_name}.log"),
"rb+",
encoding="utf-8",
) as f:
@@ -484,16 +479,12 @@ async def debug_clear(self, ctx):
log_file_name = self.bot.token.split(".")[0]
with open(
- os.path.join(
- os.path.dirname(os.path.abspath(__file__)), f"../temp/{log_file_name}.log"
- ),
+ os.path.join(os.path.dirname(os.path.abspath(__file__)), f"../temp/{log_file_name}.log"),
"w",
):
pass
await ctx.send(
- embed=discord.Embed(
- color=self.bot.main_color, description="Cached logs are now cleared."
- )
+ embed=discord.Embed(color=self.bot.main_color, description="Cached logs are now cleared.")
)
@commands.command(aliases=["presence"])
@@ -538,9 +529,7 @@ async def activity(self, ctx, activity_type: str.lower, *, message: str = ""):
except KeyError:
raise commands.MissingRequiredArgument(SimpleNamespace(name="activity"))
- activity, _ = await self.set_presence(
- activity_type=activity_type, activity_message=message
- )
+ activity, _ = await self.set_presence(activity_type=activity_type, activity_message=message)
self.bot.config["activity_type"] = activity.type.value
self.bot.config["activity_message"] = activity.name
@@ -605,9 +594,7 @@ async def set_presence(self, *, status=None, activity_type=None, activity_messag
url = None
activity_message = (activity_message or self.bot.config["activity_message"]).strip()
if activity_type is not None and not activity_message:
- logger.warning(
- 'No activity message found whilst activity is provided, defaults to "Modmail".'
- )
+ logger.warning('No activity message found whilst activity is provided, defaults to "Modmail".')
activity_message = "Modmail"
if activity_type == ActivityType.listening:
@@ -708,12 +695,14 @@ async def mention(self, ctx, *user_or_role: Union[discord.Role, discord.Member,
option = user_or_role[0].lower()
if option == "disable":
embed = discord.Embed(
- description=f"Disabled mention on thread creation.", color=self.bot.main_color,
+ description=f"Disabled mention on thread creation.",
+ color=self.bot.main_color,
)
self.bot.config["mention"] = None
else:
embed = discord.Embed(
- description="`mention` is reset to default.", color=self.bot.main_color,
+ description="`mention` is reset to default.",
+ color=self.bot.main_color,
)
self.bot.config.remove("mention")
await self.bot.config.update()
@@ -749,9 +738,7 @@ async def prefix(self, ctx, *, prefix=None):
"""
current = self.bot.prefix
- embed = discord.Embed(
- title="Current prefix", color=self.bot.main_color, description=f"{current}"
- )
+ embed = discord.Embed(title="Current prefix", color=self.bot.main_color, description=f"{current}")
if prefix is None:
await ctx.send(embed=embed)
@@ -788,9 +775,7 @@ async def config_options(self, ctx):
"""Return a list of valid configuration names you can change."""
embeds = []
for names in zip_longest(*(iter(sorted(self.bot.config.public_keys)),) * 15):
- description = "\n".join(
- f"`{name}`" for name in takewhile(lambda x: x is not None, names)
- )
+ description = "\n".join(f"`{name}`" for name in takewhile(lambda x: x is not None, names))
embed = discord.Embed(
title="Available configuration keys:",
color=self.bot.main_color,
@@ -908,9 +893,7 @@ async def config_help(self, ctx, key: str.lower = None):
description=f"`{key}` is an invalid key.",
)
if closest:
- embed.add_field(
- name=f"Perhaps you meant:", value="\n".join(f"`{x}`" for x in closest)
- )
+ embed.add_field(name=f"Perhaps you meant:", value="\n".join(f"`{x}`" for x in closest))
return await ctx.send(embed=embed)
config_help = self.bot.config.config_help
@@ -1403,9 +1386,7 @@ async def permissions_remove(
Do not ping `@everyone` for granting permission to everyone, use "everyone" or "all" instead.
"""
- if type_ not in {"command", "level", "override"} or (
- type_ != "override" and user_or_role is None
- ):
+ if type_ not in {"command", "level", "override"} or (type_ != "override" and user_or_role is None):
return await ctx.send_help(ctx.command)
if type_ == "override":
@@ -1568,15 +1549,9 @@ async def permissions_get(
levels.append(level.name)
mention = getattr(user_or_role, "name", getattr(user_or_role, "id", user_or_role))
- desc_cmd = (
- ", ".join(map(lambda x: f"`{x}`", cmds))
- if cmds
- else "No permission entries found."
- )
+ desc_cmd = ", ".join(map(lambda x: f"`{x}`", cmds)) if cmds else "No permission entries found."
desc_level = (
- ", ".join(map(lambda x: f"`{x}`", levels))
- if levels
- else "No permission entries found."
+ ", ".join(map(lambda x: f"`{x}`", levels)) if levels else "No permission entries found."
)
embeds = [
@@ -1601,9 +1576,7 @@ async def permissions_get(
for command in self.bot.walk_commands():
if command not in done:
done.add(command)
- level = self.bot.config["override_command_level"].get(
- command.qualified_name
- )
+ level = self.bot.config["override_command_level"].get(command.qualified_name)
if level is not None:
overrides[command.qualified_name] = level
@@ -1622,12 +1595,8 @@ async def permissions_get(
": ".join((f"`{name}`", level))
for name, level in takewhile(lambda x: x is not None, items)
)
- embed = discord.Embed(
- color=self.bot.main_color, description=description
- )
- embed.set_author(
- name="Permission Overrides", icon_url=ctx.guild.icon_url
- )
+ embed = discord.Embed(color=self.bot.main_color, description=description)
+ embed.set_author(name="Permission Overrides", icon_url=ctx.guild.icon_url)
embeds.append(embed)
session = EmbedPaginatorSession(ctx, *embeds)
@@ -1729,9 +1698,7 @@ async def oauth_whitelist(self, ctx, target: Union[discord.Role, utils.User]):
if not hasattr(target, "mention"):
target = self.bot.get_user(target.id) or self.bot.modmail_guild.get_role(target.id)
- embed.description = (
- f"{'Un-w' if removed else 'W'}hitelisted {target.mention} to view logs."
- )
+ embed.description = f"{'Un-w' if removed else 'W'}hitelisted {target.mention} to view logs."
await ctx.send(embed=embed)
@@ -1808,9 +1775,7 @@ async def autotrigger_add(self, ctx, keyword, *, command):
async def autotrigger_edit(self, ctx, keyword, *, command):
"""Edits a pre-existing trigger to automatically trigger an alias-like command"""
if keyword not in self.bot.auto_triggers:
- embed = utils.create_not_found_embed(
- keyword, self.bot.auto_triggers.keys(), "Autotrigger"
- )
+ embed = utils.create_not_found_embed(keyword, self.bot.auto_triggers.keys(), "Autotrigger")
else:
# command validation
valid = False
@@ -1896,7 +1861,11 @@ async def autotrigger_list(self, ctx):
embeds = []
for keyword in self.bot.auto_triggers:
command = self.bot.auto_triggers[keyword]
- embed = discord.Embed(title=keyword, color=self.bot.main_color, description=command,)
+ embed = discord.Embed(
+ title=keyword,
+ color=self.bot.main_color,
+ description=command,
+ )
embeds.append(embed)
if not embeds:
@@ -1919,17 +1888,13 @@ async def github(self, ctx):
data = await self.bot.api.get_user_info()
if data:
- embed = discord.Embed(
- title="GitHub", description="Current User", color=self.bot.main_color
- )
+ embed = discord.Embed(title="GitHub", description="Current User", color=self.bot.main_color)
user = data["user"]
embed.set_author(name=user["username"], icon_url=user["avatar_url"], url=user["url"])
embed.set_thumbnail(url=user["avatar_url"])
await ctx.send(embed=embed)
else:
- await ctx.send(
- embed=discord.Embed(title="Invalid Github Token", color=self.bot.error_color)
- )
+ await ctx.send(embed=discord.Embed(title="Invalid Github Token", color=self.bot.error_color))
@commands.command()
@checks.has_permissions(PermissionLevel.OWNER)
@@ -1951,16 +1916,12 @@ async def update(self, ctx, *, flag: str = ""):
)
if self.bot.version >= parse_version(latest.version) and flag.lower() != "force":
- embed = discord.Embed(
- title="Already up to date", description=desc, color=self.bot.main_color
- )
+ embed = discord.Embed(title="Already up to date", description=desc, color=self.bot.main_color)
data = await self.bot.api.get_user_info()
if data:
user = data["user"]
- embed.set_author(
- name=user["username"], icon_url=user["avatar_url"], url=user["url"]
- )
+ embed.set_author(name=user["username"], icon_url=user["avatar_url"], url=user["url"])
await ctx.send(embed=embed)
else:
if self.bot.hosting_method == HostingMethod.HEROKU:
@@ -1972,9 +1933,7 @@ async def update(self, ctx, *, flag: str = ""):
if commit_data and commit_data.get("html_url"):
embed = discord.Embed(color=self.bot.main_color)
- embed.set_footer(
- text=f"Updating Modmail v{self.bot.version} " f"-> v{latest.version}"
- )
+ embed.set_footer(text=f"Updating Modmail v{self.bot.version} " f"-> v{latest.version}")
embed.set_author(
name=user["username"] + " - Updating bot",
@@ -1996,9 +1955,7 @@ async def update(self, ctx, *, flag: str = ""):
color=self.bot.main_color,
)
embed.set_footer(text="Force update")
- embed.set_author(
- name=user["username"], icon_url=user["avatar_url"], url=user["url"]
- )
+ embed.set_author(name=user["username"], icon_url=user["avatar_url"], url=user["url"])
await ctx.send(embed=embed)
else:
# update fork if gh_token exists
@@ -2009,25 +1966,28 @@ async def update(self, ctx, *, flag: str = ""):
command = "git pull"
- proc = await asyncio.create_subprocess_shell(command, stderr=PIPE, stdout=PIPE,)
+ proc = await asyncio.create_subprocess_shell(
+ command,
+ stderr=PIPE,
+ stdout=PIPE,
+ )
err = await proc.stderr.read()
err = err.decode("utf-8").rstrip()
res = await proc.stdout.read()
res = res.decode("utf-8").rstrip()
if err and not res:
- embed = discord.Embed(
- title="Update failed", description=err, color=self.bot.error_color
- )
+ embed = discord.Embed(title="Update failed", description=err, color=self.bot.error_color)
await ctx.send(embed=embed)
elif res != "Already up to date.":
logger.info("Bot has been updated.")
- embed = discord.Embed(title="Bot has been updated", color=self.bot.main_color,)
- embed.set_footer(
- text=f"Updating Modmail v{self.bot.version} " f"-> v{latest.version}"
+ embed = discord.Embed(
+ title="Bot has been updated",
+ color=self.bot.main_color,
)
+ embed.set_footer(text=f"Updating Modmail v{self.bot.version} " f"-> v{latest.version}")
embed.description = latest.description
for name, value in latest.fields.items():
embed.add_field(name=name, value=truncate(value, 200))
@@ -2038,10 +1998,12 @@ async def update(self, ctx, *, flag: str = ""):
)
await ctx.send(embed=embed)
- await self.bot.logout()
+ return await self.bot.close()
else:
embed = discord.Embed(
- title="Already up to date", description=desc, color=self.bot.main_color,
+ title="Already up to date",
+ description=desc,
+ color=self.bot.main_color,
)
embed.set_footer(text="Force update")
await ctx.send(embed=embed)
diff --git a/core/changelog.py b/core/changelog.py
index 878a19b26c..7c9af2e1bb 100644
--- a/core/changelog.py
+++ b/core/changelog.py
@@ -65,9 +65,7 @@ def parse(self) -> None:
Parse the lines and split them into `description` and `fields`.
"""
self.description = re.match(self.DESCRIPTION_REGEX, self.lines, re.DOTALL)
- self.description = (
- self.description.group(1).strip() if self.description is not None else ""
- )
+ self.description = self.description.group(1).strip() if self.description is not None else ""
matches = re.finditer(self.ACTION_REGEX, self.lines, re.DOTALL)
for m in matches:
@@ -91,7 +89,9 @@ def embed(self) -> Embed:
"""
embed = Embed(color=self.bot.main_color, description=self.description)
embed.set_author(
- name=f"v{self.version} - Changelog", icon_url=self.bot.user.avatar_url, url=self.url,
+ name=f"v{self.version} - Changelog",
+ icon_url=self.bot.user.avatar_url,
+ url=self.url,
)
for name, value in self.fields.items():
@@ -171,7 +171,9 @@ async def from_url(cls, bot, url: str = "") -> "Changelog":
"""
# get branch via git cli if available
proc = await asyncio.create_subprocess_shell(
- "git branch --show-current", stderr=PIPE, stdout=PIPE,
+ "git branch --show-current",
+ stderr=PIPE,
+ stdout=PIPE,
)
err = await proc.stderr.read()
err = err.decode("utf-8").rstrip()
diff --git a/core/checks.py b/core/checks.py
index 74b7dc38cd..1079b55530 100644
--- a/core/checks.py
+++ b/core/checks.py
@@ -5,7 +5,9 @@
logger = getLogger(__name__)
-def has_permissions_predicate(permission_level: PermissionLevel = PermissionLevel.REGULAR,):
+def has_permissions_predicate(
+ permission_level: PermissionLevel = PermissionLevel.REGULAR,
+):
async def predicate(ctx):
return await check_permissions(ctx, ctx.command.qualified_name)
diff --git a/core/clients.py b/core/clients.py
index db4e9936b4..667faf71bd 100644
--- a/core/clients.py
+++ b/core/clients.py
@@ -305,9 +305,7 @@ async def get_log(self, channel_id: Union[str, int]) -> dict:
async def get_log_link(self, channel_id: Union[str, int]) -> str:
return NotImplemented
- async def create_log_entry(
- self, recipient: Member, channel: TextChannel, creator: Member
- ) -> str:
+ async def create_log_entry(self, recipient: Member, channel: TextChannel, creator: Member) -> str:
return NotImplemented
async def delete_log_entry(self, key: str) -> bool:
@@ -379,9 +377,9 @@ def __init__(self, bot):
except ConfigurationError as e:
logger.critical(
"Your MongoDB CONNECTION_URI might be copied wrong, try re-copying from the source again. "
- "Otherwise noted in the following message:"
+ "Otherwise noted in the following message:\n%s",
+ e,
)
- logger.critical(e)
sys.exit(0)
super().__init__(bot, db)
@@ -407,14 +405,28 @@ async def setup_indexes(self):
)
logger.debug("Successfully configured and verified database indexes.")
- async def validate_database_connection(self):
+ async def validate_database_connection(self, *, ssl_retry=True):
try:
await self.db.command("buildinfo")
except Exception as exc:
logger.critical("Something went wrong while connecting to the database.")
message = f"{type(exc).__name__}: {str(exc)}"
logger.critical(message)
-
+ if "CERTIFICATE_VERIFY_FAILED" in message and ssl_retry:
+ mongo_uri = self.bot.config["connection_uri"]
+ if mongo_uri is None:
+ mongo_uri = self.bot.config["mongo_uri"]
+ for _ in range(3):
+ logger.warning(
+ "FAILED TO VERIFY SSL CERTIFICATE, ATTEMPTING TO START WITHOUT SSL (UNSAFE)."
+ )
+ logger.warning(
+ "To fix this warning, check there's no proxies blocking SSL cert verification, "
+ 'run "Certificate.command" on MacOS, '
+ 'and check certifi is up to date "pip3 install --upgrade certifi".'
+ )
+ self.db = AsyncIOMotorClient(mongo_uri, tlsAllowInvalidCertificates=True).modmail_bot
+ return await self.validate_database_connection(ssl_retry=False)
if "ServerSelectionTimeoutError" in message:
logger.critical(
"This may have been caused by not whitelisting "
@@ -479,13 +491,9 @@ async def get_log_link(self, channel_id: Union[str, int]) -> str:
prefix = self.bot.config["log_url_prefix"].strip("/")
if prefix == "NONE":
prefix = ""
- return (
- f"{self.bot.config['log_url'].strip('/')}{'/' + prefix if prefix else ''}/{doc['key']}"
- )
+ return f"{self.bot.config['log_url'].strip('/')}{'/' + prefix if prefix else ''}/{doc['key']}"
- async def create_log_entry(
- self, recipient: Member, channel: TextChannel, creator: Member
- ) -> str:
+ async def create_log_entry(self, recipient: Member, channel: TextChannel, creator: Member) -> str:
key = secrets.token_hex(6)
await self.logs.insert_one(
@@ -536,9 +544,7 @@ async def get_config(self) -> dict:
async def update_config(self, data: dict):
toset = self.bot.config.filter_valid(data)
- unset = self.bot.config.filter_valid(
- {k: 1 for k in self.bot.config.all_keys if k not in data}
- )
+ unset = self.bot.config.filter_valid({k: 1 for k in self.bot.config.all_keys if k not in data})
if toset and unset:
return await self.db.config.update_one(
@@ -635,17 +641,13 @@ async def find_notes(self, recipient: Member):
async def update_note_ids(self, ids: dict):
for object_id, message_id in ids.items():
- await self.db.notes.update_one(
- {"_id": object_id}, {"$set": {"message_id": message_id}}
- )
+ await self.db.notes.update_one({"_id": object_id}, {"$set": {"message_id": message_id}})
async def delete_note(self, message_id: Union[int, str]):
await self.db.notes.delete_one({"message_id": str(message_id)})
async def edit_note(self, message_id: Union[int, str], message: str):
- await self.db.notes.update_one(
- {"message_id": str(message_id)}, {"$set": {"message": message}}
- )
+ await self.db.notes.update_one({"message_id": str(message_id)}, {"$set": {"message": message}})
def get_plugin_partition(self, cog):
cls_name = cog.__class__.__name__
@@ -656,7 +658,11 @@ async def update_repository(self) -> dict:
data = await user.update_repository()
return {
"data": data,
- "user": {"username": user.username, "avatar_url": user.avatar_url, "url": user.url,},
+ "user": {
+ "username": user.username,
+ "avatar_url": user.avatar_url,
+ "url": user.url,
+ },
}
async def get_user_info(self) -> dict:
diff --git a/core/config.py b/core/config.py
index 30f364622d..255c3667de 100644
--- a/core/config.py
+++ b/core/config.py
@@ -210,28 +210,18 @@ def populate_cache(self) -> dict:
# populate from env var and .env file
data.update({k.lower(): v for k, v in os.environ.items() if k.lower() in self.all_keys})
- config_json = os.path.join(
- os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "config.json"
- )
+ config_json = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "config.json")
if os.path.exists(config_json):
logger.debug("Loading envs from config.json.")
with open(config_json, "r", encoding="utf-8") as f:
# Config json should override env vars
try:
- data.update(
- {
- k.lower(): v
- for k, v in json.load(f).items()
- if k.lower() in self.all_keys
- }
- )
+ data.update({k.lower(): v for k, v in json.load(f).items() if k.lower() in self.all_keys})
except json.JSONDecodeError:
logger.critical("Failed to load config.json env values.", exc_info=True)
self._cache = data
- config_help_json = os.path.join(
- os.path.dirname(os.path.abspath(__file__)), "config_help.json"
- )
+ config_help_json = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config_help.json")
with open(config_help_json, "r", encoding="utf-8") as f:
self.config_help = dict(sorted(json.load(f).items()))
diff --git a/core/models.py b/core/models.py
index 44e75043d1..3b1e9ce481 100644
--- a/core/models.py
+++ b/core/models.py
@@ -127,9 +127,13 @@ def format(self, record):
def configure_logging(name, level=None):
global ch_debug, log_level
+<<<<<<< HEAD
ch_debug = RotatingFileHandler(
name, mode="a+", maxBytes=48000, backupCount=1, encoding="utf-8"
)
+=======
+ ch_debug = RotatingFileHandler(name, mode="a+", maxBytes=78000, backupCount=10)
+>>>>>>> master
formatter_debug = FileFormatter(
"%(asctime)s %(name)s[%(lineno)d] - %(levelname)s: %(message)s",
@@ -205,9 +209,7 @@ async def convert(self, ctx, argument):
except commands.ChannelNotFound:
def check(c):
- return isinstance(c, discord.CategoryChannel) and c.name.lower().startswith(
- argument.lower()
- )
+ return isinstance(c, discord.CategoryChannel) and c.name.lower().startswith(argument.lower())
if guild:
result = discord.utils.find(check, guild.categories)
diff --git a/core/thread.py b/core/thread.py
index 04c16661c7..46ad556f70 100644
--- a/core/thread.py
+++ b/core/thread.py
@@ -133,9 +133,7 @@ async def setup(self, *, creator=None, category=None, initial_message=None):
recipient = self.recipient
# in case it creates a channel outside of category
- overwrites = {
- self.bot.modmail_guild.default_role: discord.PermissionOverwrite(read_messages=False)
- }
+ overwrites = {self.bot.modmail_guild.default_role: discord.PermissionOverwrite(read_messages=False)}
category = category or self.bot.main_category
@@ -194,9 +192,7 @@ async def setup(self, *, creator=None, category=None, initial_message=None):
mention = self.bot.config["mention"]
async def send_genesis_message():
- info_embed = self._format_info_embed(
- recipient, log_url, log_count, self.bot.main_color
- )
+ info_embed = self._format_info_embed(recipient, log_url, log_count, self.bot.main_color)
try:
msg = await channel.send(mention, embed=info_embed)
self.bot.loop.create_task(msg.pin())
@@ -262,9 +258,7 @@ class Author:
"author": Author(),
}
message = discord.Message(state=State(), channel=None, data=data)
- ids[note["_id"]] = str(
- (await self.note(message, persistent=True, thread_creation=True)).id
- )
+ ids[note["_id"]] = str((await self.note(message, persistent=True, thread_creation=True)).id)
await self.bot.api.update_note_ids(ids)
@@ -354,16 +348,12 @@ def _format_info_embed(self, user, log_url, log_count, color):
mutual_guilds = [g for g in self.bot.guilds if user in g.members]
if member is None or len(mutual_guilds) > 1:
- embed.add_field(
- name="Mutual Server(s)", value=", ".join(g.name for g in mutual_guilds)
- )
+ embed.add_field(name="Mutual Server(s)", value=", ".join(g.name for g in mutual_guilds))
return embed
def _close_after(self, closer, silent, delete_channel, message):
- return self.bot.loop.create_task(
- self._close(closer, silent, delete_channel, message, True)
- )
+ return self.bot.loop.create_task(self._close(closer, silent, delete_channel, message, True))
async def close(
self,
@@ -396,9 +386,7 @@ async def close(
self.bot.config["closures"][str(self.id)] = items
await self.bot.config.update()
- task = self.bot.loop.call_later(
- after, self._close_after, closer, silent, delete_channel, message
- )
+ task = self.bot.loop.call_later(after, self._close_after, closer, silent, delete_channel, message)
if auto_close:
self.auto_close_task = task
@@ -407,9 +395,7 @@ async def close(
else:
await self._close(closer, silent, delete_channel, message)
- async def _close(
- self, closer, silent=False, delete_channel=True, message=None, scheduled=False
- ):
+ async def _close(self, closer, silent=False, delete_channel=True, message=None, scheduled=False):
try:
self.manager.cache.pop(self.id)
except KeyError as e:
@@ -449,7 +435,9 @@ async def _close(
prefix = self.bot.config["log_url_prefix"].strip("/")
if prefix == "NONE":
prefix = ""
- log_url = f"{self.bot.config['log_url'].strip('/')}{'/' + prefix if prefix else ''}/{log_data['key']}"
+ log_url = (
+ f"{self.bot.config['log_url'].strip('/')}{'/' + prefix if prefix else ''}/{log_data['key']}"
+ )
if log_data["title"]:
sneak_peak = log_data["title"]
@@ -497,7 +485,8 @@ async def _close(
# Thread closed message
embed = discord.Embed(
- title=self.bot.config["thread_close_title"], color=self.bot.error_color,
+ title=self.bot.config["thread_close_title"],
+ color=self.bot.error_color,
)
if self.bot.config["show_timestamp"]:
embed.timestamp = datetime.utcnow()
@@ -557,9 +546,7 @@ async def _restart_close_timer(self):
human_time = human_timedelta(dt=reset_time)
if self.bot.config.get("thread_auto_close_silently"):
- return await self.close(
- closer=self.bot.user, silent=True, after=int(seconds), auto_close=True
- )
+ return await self.close(closer=self.bot.user, silent=True, after=int(seconds), auto_close=True)
# Grab message
close_message = self.bot.formatter.format(
@@ -575,9 +562,7 @@ async def _restart_close_timer(self):
time_marker_regex,
)
- await self.close(
- closer=self.bot.user, after=int(seconds), message=close_message, auto_close=True
- )
+ await self.close(closer=self.bot.user, after=int(seconds), message=close_message, auto_close=True)
async def find_linked_messages(
self,
@@ -587,11 +572,7 @@ async def find_linked_messages(
note: bool = True,
) -> typing.Tuple[discord.Message, typing.Optional[discord.Message]]:
if message1 is not None:
- if (
- not message1.embeds
- or not message1.embeds[0].author.url
- or message1.author != self.bot.user
- ):
+ if not message1.embeds or not message1.embeds[0].author.url or message1.author != self.bot.user:
raise ValueError("Malformed thread message.")
elif message_id is not None:
@@ -628,10 +609,7 @@ async def find_linked_messages(
and message1.embeds[0].color
and (
message1.embeds[0].color.value == self.bot.mod_color
- or (
- either_direction
- and message1.embeds[0].color.value == self.bot.recipient_color
- )
+ or (either_direction and message1.embeds[0].color.value == self.bot.recipient_color)
)
and message1.embeds[0].author.url.split("#")[-1].isdigit()
and message1.author == self.bot.user
@@ -745,13 +723,9 @@ async def edit_dm_message(self, message: discord.Message, content: str) -> None:
embed = linked_message.embeds[0]
embed.add_field(name="**Edited, former message:**", value=embed.description)
embed.description = content
- await asyncio.gather(
- self.bot.api.edit_message(message.id, content), linked_message.edit(embed=embed)
- )
+ await asyncio.gather(self.bot.api.edit_message(message.id, content), linked_message.edit(embed=embed))
- async def note(
- self, message: discord.Message, persistent=False, thread_creation=False
- ) -> None:
+ async def note(self, message: discord.Message, persistent=False, thread_creation=False) -> None:
if not message.content and not message.attachments:
raise MissingRequiredArgument(SimpleNamespace(name="msg"))
@@ -764,16 +738,12 @@ async def note(
)
self.bot.loop.create_task(
- self.bot.api.append_log(
- message, message_id=msg.id, channel_id=self.channel.id, type_="system"
- )
+ self.bot.api.append_log(message, message_id=msg.id, channel_id=self.channel.id, type_="system")
)
return msg
- async def reply(
- self, message: discord.Message, anonymous: bool = False, plain: bool = False
- ) -> None:
+ async def reply(self, message: discord.Message, anonymous: bool = False, plain: bool = False) -> None:
if not message.content and not message.attachments:
raise MissingRequiredArgument(SimpleNamespace(name="msg"))
if not any(g.get_member(self.id) for g in self.bot.guilds):
@@ -814,7 +784,10 @@ async def reply(
)
tasks.append(
message.channel.send(
- embed=discord.Embed(color=self.bot.error_color, description=description,)
+ embed=discord.Embed(
+ color=self.bot.error_color,
+ description=description,
+ )
)
)
else:
@@ -862,9 +835,7 @@ async def send(
thread_creation: bool = False,
) -> None:
- self.bot.loop.create_task(
- self._restart_close_timer()
- ) # Start or restart thread auto close
+ self.bot.loop.create_task(self._restart_close_timer()) # Start or restart thread auto close
if self.close_task is not None:
# cancel closing if a thread message is sent.
@@ -1004,9 +975,7 @@ async def send(
file_upload_count = 1
for url, filename, _ in attachments:
- embed.add_field(
- name=f"File upload ({file_upload_count})", value=f"[{filename}]({url})"
- )
+ embed.add_field(name=f"File upload ({file_upload_count})", value=f"[{filename}]({url})")
file_upload_count += 1
if from_mod:
@@ -1065,9 +1034,7 @@ async def send(
files = []
for i in embed.fields:
if "Image" in i.name:
- async with self.bot.session.get(
- i.field[i.field.find("http") : -1]
- ) as resp:
+ async with self.bot.session.get(i.field[i.field.find("http") : -1]) as resp:
stream = io.BytesIO(await resp.read())
files.append(discord.File(stream))
@@ -1169,6 +1136,7 @@ async def find(
logger.warning("Thread for %s cancelled.", recipient)
return thread
else:
+<<<<<<< HEAD
if not thread.cancelled and (
not thread.channel or not self.bot.get_channel(thread.channel.id)
):
@@ -1176,6 +1144,13 @@ async def find(
"Found existing thread for %s but the channel is invalid.", recipient_id
)
await thread.close(closer=self.bot.user, silent=True, delete_channel=False)
+=======
+ if not thread.channel or not self.bot.get_channel(thread.channel.id):
+ logger.warning("Found existing thread for %s but the channel is invalid.", recipient_id)
+ self.bot.loop.create_task(
+ thread.close(closer=self.bot.user, silent=True, delete_channel=False)
+ )
+>>>>>>> master
thread = None
else:
channel = discord.utils.find(
@@ -1249,10 +1224,17 @@ async def create(
if thread.channel and self.bot.get_channel(thread.channel.id):
logger.warning("Found an existing thread for %s, abort creating.", recipient)
return thread
+<<<<<<< HEAD
logger.warning(
"Found an existing thread for %s, closing previous thread.", recipient
)
await thread.close(closer=self.bot.user, silent=True, delete_channel=False)
+=======
+ logger.warning("Found an existing thread for %s, closing previous thread.", recipient)
+ self.bot.loop.create_task(
+ thread.close(closer=self.bot.user, silent=True, delete_channel=False)
+ )
+>>>>>>> master
thread = Thread(self, recipient)
@@ -1322,15 +1304,20 @@ async def remove_reactions():
for emoji in emojis:
await confirm.remove_reaction(emoji, self.bot.user)
await asyncio.sleep(0.2)
+<<<<<<< HEAD
self.bot.loop.create_task(remove_reactions())
if thread.cancelled:
del self.cache[recipient.id]
return thread
+=======
+ await confirm.remove_reaction(deny_emoji, self.bot.user)
+ await destination.send(embed=discord.Embed(title="Cancelled", color=self.bot.error_color))
+ del self.cache[recipient.id]
+ return thread
+>>>>>>> master
- self.bot.loop.create_task(
- thread.setup(creator=creator, category=category, initial_message=message)
- )
+ self.bot.loop.create_task(thread.setup(creator=creator, category=category, initial_message=message))
return thread
async def find_or_create(self, recipient) -> Thread:
diff --git a/core/time.py b/core/time.py
index 331e26349f..bdec8d2549 100644
--- a/core/time.py
+++ b/core/time.py
@@ -57,9 +57,7 @@ def __init__(self, argument):
if not status.hasTime:
# replace it with the current time
- dt = dt.replace(
- hour=now.hour, minute=now.minute, second=now.second, microsecond=now.microsecond
- )
+ dt = dt.replace(hour=now.hour, minute=now.minute, second=now.second, microsecond=now.microsecond)
self.dt = dt
self._past = dt < now
diff --git a/core/utils.py b/core/utils.py
index b95200cdfe..e80e298931 100644
--- a/core/utils.py
+++ b/core/utils.py
@@ -379,8 +379,7 @@ def format_channel_name(bot, author, exclude_channel=None, force_null=False):
name = "null"
name = new_name = (
- "".join(l for l in name if l not in string.punctuation and l.isprintable())
- or "null"
+ "".join(l for l in name if l not in string.punctuation and l.isprintable()) or "null"
) + f"-{author.discriminator}"
counter = 1
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000000..d3745c9b4c
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,28 @@
+version: "3.7"
+services:
+ bot:
+ image: kyb3rr/modmail
+ restart: always
+ env_file:
+ - .env
+ environment:
+ - CONNECTION_URI=mongodb://mongo
+ depends_on:
+ - mongo
+ logviewer:
+ image: kyb3rr/logviewer
+ restart: always
+ depends_on:
+ - mongo
+ environment:
+ - MONGO_URI=mongodb://mongo
+ ports:
+ - 80:8000
+ mongo:
+ image: mongo
+ restart: always
+ volumes:
+ - mongodb:/data/db
+
+volumes:
+ mongodb:
diff --git a/plugins/registry.json b/plugins/registry.json
index b74ff1f989..a9f565a013 100644
--- a/plugins/registry.json
+++ b/plugins/registry.json
@@ -1,13 +1,4 @@
{
- "profanity-filter": {
- "repository": "kyb3r/modmail-plugins",
- "branch": "master",
- "description": "Checks for profanity in a message using machine learning and deletes it.",
- "bot_version": "2.20.1",
- "title": "Profanity Filter Plugin",
- "icon_url": "https://i.imgur.com/951szZ3.jpg",
- "thumbnail_url": "https://i.imgur.com/951szZ3.jpg"
- },
"dragory-migrate": {
"repository": "kyb3r/modmail-plugins",
"branch": "master",
diff --git a/poetry.lock b/poetry.lock
deleted file mode 100644
index 4aa8248546..0000000000
--- a/poetry.lock
+++ /dev/null
@@ -1,455 +0,0 @@
-[[package]]
-category = "main"
-description = "Async http client/server framework (asyncio)"
-name = "aiohttp"
-optional = false
-python-versions = ">=3.5.3"
-version = "3.6.2"
-
-[package.dependencies]
-async-timeout = ">=3.0,<4.0"
-attrs = ">=17.3.0"
-chardet = ">=2.0,<4.0"
-multidict = ">=4.5,<5.0"
-yarl = ">=1.0,<2.0"
-
-[[package]]
-category = "dev"
-description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
-name = "appdirs"
-optional = false
-python-versions = "*"
-version = "1.4.4"
-
-[[package]]
-category = "dev"
-description = "An abstract syntax tree for Python with inference support."
-name = "astroid"
-optional = false
-python-versions = ">=3.5"
-version = "2.4.1"
-
-[package.dependencies]
-lazy-object-proxy = ">=1.4.0,<1.5.0"
-six = ">=1.12,<2.0"
-wrapt = ">=1.11,<2.0"
-
-[package.dependencies.typed-ast]
-python = "<3.8"
-version = ">=1.4.0,<1.5"
-
-[[package]]
-category = "main"
-description = "Timeout context manager for asyncio programs"
-name = "async-timeout"
-optional = false
-python-versions = ">=3.5.3"
-version = "3.0.1"
-
-[[package]]
-category = "main"
-description = "Classes Without Boilerplate"
-name = "attrs"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "19.3.0"
-
-[[package]]
-category = "dev"
-description = "Security oriented static analyser for python code."
-name = "bandit"
-optional = false
-python-versions = "*"
-version = "1.6.2"
-
-[package.dependencies]
-GitPython = ">=1.0.1"
-PyYAML = ">=3.13"
-colorama = ">=0.3.9"
-six = ">=1.10.0"
-stevedore = ">=1.20.0"
-
-[[package]]
-category = "dev"
-description = "The uncompromising code formatter."
-name = "black"
-optional = false
-python-versions = ">=3.6"
-version = "19.10b0"
-
-[package.dependencies]
-appdirs = "*"
-attrs = ">=18.1.0"
-click = ">=6.5"
-pathspec = ">=0.6,<1"
-regex = "*"
-toml = ">=0.9.4"
-typed-ast = ">=1.4.0"
-
-[[package]]
-category = "main"
-description = "Universal encoding detector for Python 2 and 3"
-name = "chardet"
-optional = false
-python-versions = "*"
-version = "3.0.4"
-
-[[package]]
-category = "dev"
-description = "Composable command line interface toolkit"
-name = "click"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "7.1.2"
-
-[[package]]
-category = "main"
-description = "Cross-platform colored terminal text."
-name = "colorama"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "0.4.3"
-
-[[package]]
-category = "main"
-description = "A Python wrapper for the Discord API"
-name = "discord.py"
-optional = false
-python-versions = ">=3.5.3"
-version = "1.3.3"
-
-[package.dependencies]
-aiohttp = ">=3.6.0,<3.7.0"
-websockets = ">=6.0,<7.0 || >7.0,<8.0 || >8.0,<8.0.1 || >8.0.1,<9.0"
-
-[[package]]
-category = "main"
-description = "DNS toolkit"
-name = "dnspython"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "1.16.0"
-
-[[package]]
-category = "main"
-description = "Emoji for Python"
-name = "emoji"
-optional = false
-python-versions = "*"
-version = "0.5.4"
-
-[[package]]
-category = "main"
-description = "Backport of the concurrent.futures package from Python 3.2"
-name = "futures"
-optional = true
-python-versions = "*"
-version = "3.1.1"
-
-[[package]]
-category = "dev"
-description = "Git Object Database"
-name = "gitdb"
-optional = false
-python-versions = ">=3.4"
-version = "4.0.5"
-
-[package.dependencies]
-smmap = ">=3.0.1,<4"
-
-[[package]]
-category = "dev"
-description = "Python Git Library"
-name = "gitpython"
-optional = false
-python-versions = ">=3.4"
-version = "3.1.3"
-
-[package.dependencies]
-gitdb = ">=4.0.1,<5"
-
-[[package]]
-category = "main"
-description = "Internationalized Domain Names in Applications (IDNA)"
-name = "idna"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "2.9"
-
-[[package]]
-category = "main"
-description = "An ISO 8601 date/time/duration parser and formatter"
-name = "isodate"
-optional = false
-python-versions = "*"
-version = "0.6.0"
-
-[package.dependencies]
-six = "*"
-
-[[package]]
-category = "dev"
-description = "A Python utility / library to sort Python imports."
-name = "isort"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "4.3.21"
-
-[[package]]
-category = "dev"
-description = "A fast and thorough lazy object proxy."
-name = "lazy-object-proxy"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "1.4.3"
-
-[[package]]
-category = "dev"
-description = "McCabe checker, plugin for flake8"
-name = "mccabe"
-optional = false
-python-versions = "*"
-version = "0.6.1"
-
-[[package]]
-category = "main"
-description = "Non-blocking MongoDB driver for Tornado or asyncio"
-name = "motor"
-optional = true
-python-versions = "*"
-version = "2.1.0"
-
-[package.dependencies]
-futures = "*"
-pymongo = ">=3.10,<4"
-
-[[package]]
-category = "main"
-description = "multidict implementation"
-name = "multidict"
-optional = false
-python-versions = ">=3.5"
-version = "4.7.6"
-
-[[package]]
-category = "main"
-description = "Convert data to their natural (human-readable) format"
-name = "natural"
-optional = false
-python-versions = "*"
-version = "0.2.0"
-
-[package.dependencies]
-six = "*"
-
-[[package]]
-category = "main"
-description = "Parse human-readable date/time text."
-name = "parsedatetime"
-optional = false
-python-versions = "*"
-version = "2.6"
-
-[[package]]
-category = "dev"
-description = "Utility library for gitignore style pattern matching of file paths."
-name = "pathspec"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "0.8.0"
-
-[[package]]
-category = "dev"
-description = "Python Build Reasonableness"
-name = "pbr"
-optional = false
-python-versions = "*"
-version = "5.4.5"
-
-[[package]]
-category = "dev"
-description = "python code static checker"
-name = "pylint"
-optional = false
-python-versions = ">=3.5.*"
-version = "2.5.2"
-
-[package.dependencies]
-astroid = ">=2.4.0,<=2.5"
-colorama = "*"
-isort = ">=4.2.5,<5"
-mccabe = ">=0.6,<0.7"
-toml = ">=0.7.1"
-
-[[package]]
-category = "main"
-description = "Python driver for MongoDB "
-name = "pymongo"
-optional = true
-python-versions = "*"
-version = "3.10.1"
-
-[[package]]
-category = "main"
-description = "Extensions to the standard Python datetime module"
-name = "python-dateutil"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
-version = "2.8.1"
-
-[package.dependencies]
-six = ">=1.5"
-
-[[package]]
-category = "main"
-description = "Add .env support to your django/flask apps in development and deployments"
-name = "python-dotenv"
-optional = false
-python-versions = "*"
-version = "0.10.5"
-
-[[package]]
-category = "dev"
-description = "YAML parser and emitter for Python"
-name = "pyyaml"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "5.3.1"
-
-[[package]]
-category = "dev"
-description = "Alternative regular expression module, to replace re."
-name = "regex"
-optional = false
-python-versions = "*"
-version = "2020.6.7"
-
-[[package]]
-category = "main"
-description = "Python 2 and 3 compatibility utilities"
-name = "six"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
-version = "1.15.0"
-
-[[package]]
-category = "dev"
-description = "A pure Python implementation of a sliding window memory map manager"
-name = "smmap"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "3.0.4"
-
-[[package]]
-category = "dev"
-description = "Manage dynamic plugins for Python applications"
-name = "stevedore"
-optional = false
-python-versions = ">=3.6"
-version = "2.0.0"
-
-[package.dependencies]
-pbr = ">=2.0.0,<2.1.0 || >2.1.0"
-
-[[package]]
-category = "dev"
-description = "Python Library for Tom's Obvious, Minimal Language"
-name = "toml"
-optional = false
-python-versions = "*"
-version = "0.10.1"
-
-[[package]]
-category = "dev"
-description = "a fork of Python 2 and 3 ast modules with type comment support"
-name = "typed-ast"
-optional = false
-python-versions = "*"
-version = "1.4.1"
-
-[[package]]
-category = "main"
-description = "Fast implementation of asyncio event loop on top of libuv"
-name = "uvloop"
-optional = false
-python-versions = "*"
-version = "0.14.0"
-
-[[package]]
-category = "main"
-description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
-name = "websockets"
-optional = false
-python-versions = ">=3.6.1"
-version = "8.1"
-
-[[package]]
-category = "dev"
-description = "Module for decorators, wrappers and monkey patching."
-name = "wrapt"
-optional = false
-python-versions = "*"
-version = "1.12.1"
-
-[[package]]
-category = "main"
-description = "Yet another URL library"
-name = "yarl"
-optional = false
-python-versions = ">=3.5"
-version = "1.4.2"
-
-[package.dependencies]
-idna = ">=2.0"
-multidict = ">=4.0"
-
-[extras]
-mongodb = ["motor"]
-
-[metadata]
-content-hash = "68d5c15e62c4bf5f65fd3b0a9a2586b15557f724c3de5b756534bacd52cbfe40"
-python-versions = "^3.7"
-
-[metadata.hashes]
-aiohttp = ["1e984191d1ec186881ffaed4581092ba04f7c61582a177b187d3a2f07ed9719e", "259ab809ff0727d0e834ac5e8a283dc5e3e0ecc30c4d80b3cd17a4139ce1f326", "2f4d1a4fdce595c947162333353d4a44952a724fba9ca3205a3df99a33d1307a", "32e5f3b7e511aa850829fbe5aa32eb455e5534eaa4b1ce93231d00e2f76e5654", "344c780466b73095a72c616fac5ea9c4665add7fc129f285fbdbca3cccf4612a", "460bd4237d2dbecc3b5ed57e122992f60188afe46e7319116da5eb8a9dfedba4", "4c6efd824d44ae697814a2a85604d8e992b875462c6655da161ff18fd4f29f17", "50aaad128e6ac62e7bf7bd1f0c0a24bc968a0c0590a726d5a955af193544bcec", "6206a135d072f88da3e71cc501c59d5abffa9d0bb43269a6dcd28d66bfafdbdd", "65f31b622af739a802ca6fd1a3076fd0ae523f8485c52924a89561ba10c49b48", "ae55bac364c405caa23a4f2d6cfecc6a0daada500274ffca4a9230e7129eac59", "b778ce0c909a2653741cb4b1ac7015b5c130ab9c897611df43ae6a58523cb965"]
-appdirs = ["7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", "a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"]
-astroid = ["4c17cea3e592c21b6e222f673868961bad77e1f985cb1694ed077475a89229c1", "d8506842a3faf734b81599c8b98dcc423de863adcc1999248480b18bd31a0f38"]
-async-timeout = ["0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", "4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"]
-attrs = ["08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", "f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"]
-bandit = ["336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952", "41e75315853507aa145d62a78a2a6c5e3240fe14ee7c601459d0df9418196065"]
-black = ["1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b", "c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"]
-chardet = ["84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", "fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"]
-click = ["d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a", "dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"]
-colorama = ["7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff", "e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"]
-"discord.py" = ["406871b06d86c3dc49fba63238519f28628dac946fef8a0e22988ff58ec05580", "ad00e34c72d2faa8db2157b651d05f3c415d7d05078e7e41dc9e8dc240051beb"]
-dnspython = ["36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01", "f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"]
-emoji = ["60652d3a2dcee5b8af8acb097c31776fb6d808027aeb7221830f72cdafefc174"]
-futures = ["3a44f286998ae64f0cc083682fcfec16c406134a81a589a5de445d7bb7c2751b", "51ecb45f0add83c806c68e4b06106f90db260585b25ef2abfcda0bd95c0132fd", "c4884a65654a7c45435063e14ae85280eb1f111d94e542396717ba9828c4337f"]
-gitdb = ["91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac", "c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"]
-gitpython = ["e107af4d873daed64648b4f4beb89f89f0cfbe3ef558fc7821ed2331c2f8da1a", "ef1d60b01b5ce0040ad3ec20bc64f783362d41fa0822a2742d3586e1f49bb8ac"]
-idna = ["7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb", "a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"]
-isodate = ["2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8", "aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81"]
-isort = ["54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", "6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"]
-lazy-object-proxy = ["0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d", "194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449", "1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08", "4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a", "48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50", "5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd", "59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239", "8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb", "9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea", "9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e", "97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156", "9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142", "a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442", "a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62", "ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db", "cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531", "d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383", "d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a", "eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357", "efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4", "f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"]
-mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"]
-motor = ["599719bc6dcddc3b9ea4e09659fb0073d5fadcc24735999b2902f48cef33f909", "756c587985d166166e644ccd36fb8b586fb987eb42fc0fc60cce9a3d76d809b4", "97b4fc0a00a84df30f866d18693c503eef46c7642f75218a2c44d74d835be38a"]
-multidict = ["1ece5a3369835c20ed57adadc663400b5525904e53bae59ec854a5d36b39b21a", "275ca32383bc5d1894b6975bb4ca6a7ff16ab76fa622967625baeebcf8079000", "3750f2205b800aac4bb03b5ae48025a64e474d2c6cc79547988ba1d4122a09e2", "4538273208e7294b2659b1602490f4ed3ab1c8cf9dbdd817e0e9db8e64be2507", "5141c13374e6b25fe6bf092052ab55c0c03d21bd66c94a0e3ae371d3e4d865a5", "51a4d210404ac61d32dada00a50ea7ba412e6ea945bbe992e4d7a595276d2ec7", "5cf311a0f5ef80fe73e4f4c0f0998ec08f954a6ec72b746f3c179e37de1d210d", "6513728873f4326999429a8b00fc7ceddb2509b01d5fd3f3be7881a257b8d463", "7388d2ef3c55a8ba80da62ecfafa06a1c097c18032a501ffd4cabbc52d7f2b19", "9456e90649005ad40558f4cf51dbb842e32807df75146c6d940b6f5abb4a78f3", "c026fe9a05130e44157b98fea3ab12969e5b60691a276150db9eda71710cd10b", "d14842362ed4cf63751648e7672f7174c9818459d169231d03c56e84daf90b7c", "e0d072ae0f2a179c375f67e3da300b47e1a83293c554450b29c900e50afaae87", "f07acae137b71af3bb548bd8da720956a3bc9f9a0b87733e0899226a2317aeb7", "fbb77a75e529021e7c4a8d4e823d88ef4d23674a202be4f5addffc72cbb91430", "fcfbb44c59af3f8ea984de67ec7c306f618a3ec771c2843804069917a8f2e255", "feed85993dbdb1dbc29102f50bca65bdc68f2c0c8d352468c25b54874f23c39d"]
-natural = ["18c83662d2d33fd7e6eee4e3b0d7366e1ce86225664e3127a2aaf0a3233f7df2"]
-parsedatetime = ["4cb368fbb18a0b7231f4d76119165451c8d2e35951455dfee97c62a87b04d455", "cb96edd7016872f58479e35879294258c71437195760746faffedb692aef000b"]
-pathspec = ["7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0", "da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"]
-pbr = ["07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c", "579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"]
-pylint = ["b95e31850f3af163c2283ed40432f053acbc8fc6eba6a069cb518d9dbf71848c", "dd506acce0427e9e08fb87274bcaa953d38b50a58207170dbf5b36cf3e16957b"]
-pymongo = ["01b4e10027aef5bb9ecefbc26f5df3368ce34aef81df43850f701e716e3fe16d", "0fc5aa1b1acf7f61af46fe0414e6a4d0c234b339db4c03a63da48599acf1cbfc", "1396eb7151e0558b1f817e4b9d7697d5599e5c40d839a9f7270bd90af994ad82", "18e84a3ec5e73adcb4187b8e5541b2ad61d716026ed9863267e650300d8bea33", "19adf2848b80cb349b9891cc854581bbf24c338be9a3260e73159bdeb2264464", "20ee0475aa2ba437b0a14806f125d696f90a8433d820fb558fdd6f052acde103", "26798795097bdeb571f13942beef7e0b60125397811c75b7aa9214d89880dd1d", "26e707a4eb851ec27bb969b5f1413b9b2eac28fe34271fa72329100317ea7c73", "2a3c7ad01553b27ec553688a1e6445e7f40355fb37d925c11fcb50b504e367f8", "2f07b27dbf303ea53f4147a7922ce91a26b34a0011131471d8aaf73151fdee9a", "316f0cf543013d0c085e15a2c8abe0db70f93c9722c0f99b6f3318ff69477d70", "31d11a600eea0c60de22c8bdcb58cda63c762891facdcb74248c36713240987f", "334ef3ffd0df87ea83a0054454336159f8ad9c1b389e19c0032d9cb8410660e6", "358ba4693c01022d507b96a980ded855a32dbdccc3c9331d0667be5e967f30ed", "3a6568bc53103df260f5c7d2da36dffc5202b9a36c85540bba1836a774943794", "444bf2f44264578c4085bb04493bfed0e5c1b4fe7c2704504d769f955cc78fe4", "47a00b22c52ee59dffc2aad02d0bbfb20c26ec5b8de8900492bf13ad6901cf35", "4c067db43b331fc709080d441cb2e157114fec60749667d12186cc3fc8e7a951", "4c092310f804a5d45a1bcaa4191d6d016c457b6ed3982a622c35f729ff1c7f6b", "53b711b33134e292ef8499835a3df10909c58df53a2a0308f598c432e9a62892", "568d6bee70652d8a5af1cd3eec48b4ca1696fb1773b80719ebbd2925b72cb8f6", "56fa55032782b7f8e0bf6956420d11e2d4e9860598dfe9c504edec53af0fc372", "5a2c492680c61b440272341294172fa3b3751797b1ab983533a770e4fb0a67ac", "61235cc39b5b2f593086d1d38f3fc130b2d125bd8fc8621d35bc5b6bdeb92bd2", "619ac9aaf681434b4d4718d1b31aa2f0fce64f2b3f8435688fcbdc0c818b6c54", "6238ac1f483494011abde5286282afdfacd8926659e222ba9b74c67008d3a58c", "63752a72ca4d4e1386278bd43d14232f51718b409e7ac86bcf8810826b531113", "6fdc5ccb43864065d40dd838437952e9e3da9821b7eac605ba46ada77f846bdf", "7abc3a6825a346fa4621a6f63e3b662bbb9e0f6ffc32d30a459d695f20fb1a8b", "7aef381bb9ae8a3821abd7f9d4d93978dbd99072b48522e181baeffcd95b56ae", "80df3caf251fe61a3f0c9614adc6e2bfcffd1cd3345280896766712fb4b4d6d7", "95f970f34b59987dee6f360d2e7d30e181d58957b85dff929eee4423739bd151", "993257f6ca3cde55332af1f62af3e04ca89ce63c08b56a387cdd46136c72f2fa", "9c0a57390549affc2b5dda24a38de03a5c7cbc58750cd161ff5d106c3c6eec80", "a0794e987d55d2f719cc95fcf980fc62d12b80e287e6a761c4be14c60bd9fecc", "a3b98121e68bf370dd8ea09df67e916f93ea95b52fc010902312168c4d1aff5d", "a60756d55f0887023b3899e6c2923ba5f0042fb11b1d17810b4e07395404f33e", "a676bd2fbc2309092b9bbb0083d35718b5420af3a42135ebb1e4c3633f56604d", "a732838c78554c1257ff2492f5c8c4c7312d0aecd7f732149e255f3749edd5ee", "ad3dc88dfe61f0f1f9b99c6bc833ea2f45203a937a18f0d2faa57c6952656012", "ae65d65fde4135ef423a2608587c9ef585a3551fc2e4e431e7c7e527047581be", "b070a4f064a9edb70f921bfdc270725cff7a78c22036dd37a767c51393fb956f", "b6da85949aa91e9f8c521681344bd2e163de894a5492337fba8b05c409225a4f", "bbf47110765b2a999803a7de457567389253f8670f7daafb98e059c899ce9764", "bd9c1e6f92b4888ae3ef7ae23262c513b962f09f3fb3b48581dde5df7d7a860a", "c06b3f998d2d7160db58db69adfb807d2ec307e883e2f17f6b87a1ef6c723f11", "c318fb70542be16d3d4063cde6010b1e4d328993a793529c15a619251f517c39", "c4aef42e5fa4c9d5a99f751fb79caa880dac7eaf8a65121549318b984676a1b7", "c9ca545e93a9c2a3bdaa2e6e21f7a43267ff0813e8055adf2b591c13164c0c57", "da2c3220eb55c4239dd8b982e213da0b79023cac59fe54ca09365f2bc7e4ad32", "dd8055da300535eefd446b30995c0813cc4394873c9509323762a93e97c04c03", "e2b46e092ea54b732d98c476720386ff2ccd126de1e52076b470b117bff7e409", "e334c4f39a2863a239d38b5829e442a87f241a92da9941861ee6ec5d6380b7fe", "e5c54f04ca42bbb5153aec5d4f2e3d9f81e316945220ac318abd4083308143f5", "f4d06764a06b137e48db6d569dc95614d9d225c89842c885669ee8abc9f28c7a", "f96333f9d2517c752c20a35ff95de5fc2763ac8cdb1653df0f6f45d281620606"]
-python-dateutil = ["73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", "75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"]
-python-dotenv = ["440c7c23d53b7d352f9c94d6f70860242c2f071cf5c029dd661ccb22d64ae42b", "f254bfd0c970d64ccbb6c9ebef3667ab301a71473569c991253a481f1c98dddc"]
-pyyaml = ["06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97", "240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76", "4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2", "69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648", "73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf", "74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f", "7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2", "95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee", "b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d", "cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", "d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"]
-regex = ["150125da109fccdcc8fec3b0b386b2a5d6ca7cff076f8b622486d1ca868b0c10", "163bc0805e46acfa098dfc8c0b07f371577d505f603e48afc425ff475cdac3a5", "20c513893ff80bdbe4b4ce11ea2e93d49481f05b270595d82af69ffc402010a6", "21fc17cb868c4264f0813f992f46f9ae6fc8c309d4741091de4153bd1f6a6176", "2c928bc8e0c453d73dffa3193a6e37ee752ea36df0dd4601e21024d98274dfad", "2d9beca70e36f9c60d679e108c5fe49f3d4da79d13a13f91e5e759443bd954f9", "5735f26cacdb50b3d6d35ebf8fdeb504bd8b381e2d079d2d9f12ce534fc14ecd", "6edc5c190248d3b612f2cca45448cf8ebc3621d41afcd1c5708853cbb1dbb3b3", "7606dba82435429641efe4fbc580574942f89cf2b9c5c1f8bc1eab2bacbf7e8b", "8d1ee3796795e609ef7a3a5a35eaf4728038d986aa12c06b3fd1b92ee81911f4", "8d9bb2d90e23c51aacbc58c1a11320f49b335cd67a91986cdbebcc3e843e4de8", "97d414c41f19fd2362e493810caa8445c05e0a2d63a14081c972aad66284a8d2", "9e37502817225ee99d91d8418f5119e98c380b00e772d06915690c05290f32ee", "af7209b2fcc79ee2b0ad4ea080d70bb748450ec4f282cc9e864861e469b1072e", "c0849b0864ff451f04c8afb5fc28e9ed592262e03debdd227cf0f53e04a55dcd", "c4ac9215650688e78dea29b46adbdafb7b85058eebe92ef6ea848e14466c915f", "dcda6d4e1bbfc939b177c237aee41c9678eaaf71df482688f8986e8251e12345", "dd8501b8d9ea1aba53c4bc7d47bc72933f9b4213d534cf400f16c1431f51c8ba", "ec0e509ed1877ff1cbc6f0864689bb60384a303502c4d72d9a635f8a4676fd3f", "f6c8c3f56fef719180464855346e6e80971b86dfd9e5a0e356664b5baca53072", "ffd4f80602490a309064cf2b203e220d581c51660e01055c64bf5da450485ee6"]
-six = ["30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", "8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"]
-smmap = ["54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4", "9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"]
-stevedore = ["001e90cd704be6470d46cc9076434e2d0d566c1379187e7013eb296d3a6032d9", "471c920412265cc809540ae6fb01f3f02aba89c79bbc7091372f4745a50f9691"]
-toml = ["926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f", "bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"]
-typed-ast = ["0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", "0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", "249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", "24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", "269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", "4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", "498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", "4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", "6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", "715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", "73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", "8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", "8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", "aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", "bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", "c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", "d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", "d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", "d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", "fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", "fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"]
-uvloop = ["08b109f0213af392150e2fe6f81d33261bb5ce968a288eb698aad4f46eb711bd", "123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e", "4315d2ec3ca393dd5bc0b0089d23101276778c304d42faff5dc4579cb6caef09", "4544dcf77d74f3a84f03dd6278174575c44c67d7165d4c42c71db3fdc3860726", "afd5513c0ae414ec71d24f6f123614a80f3d27ca655a4fcf6cabe50994cc1891", "b4f591aa4b3fa7f32fb51e2ee9fea1b495eb75b0b3c8d0ca52514ad675ae63f7", "bcac356d62edd330080aed082e78d4b580ff260a677508718f88016333e2c9c5", "e7514d7a48c063226b7d06617cbb12a14278d4323a065a8d46a7962686ce2e95", "f07909cd9fc08c52d294b1570bba92186181ca01fe3dc9ffba68955273dd7362"]
-websockets = ["0e4fb4de42701340bd2353bb2eee45314651caa6ccee80dbd5f5d5978888fed5", "1d3f1bf059d04a4e0eb4985a887d49195e15ebabc42364f4eb564b1d065793f5", "20891f0dddade307ffddf593c733a3fdb6b83e6f9eef85908113e628fa5a8308", "295359a2cc78736737dd88c343cd0747546b2174b5e1adc223824bcaf3e164cb", "2db62a9142e88535038a6bcfea70ef9447696ea77891aebb730a333a51ed559a", "3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c", "3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170", "3ef56fcc7b1ff90de46ccd5a687bbd13a3180132268c4254fc0fa44ecf4fc422", "4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8", "5c01fd846263a75bc8a2b9542606927cfad57e7282965d96b93c387622487485", "5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f", "751a556205d8245ff94aeef23546a1113b1dd4f6e4d102ded66c39b99c2ce6c8", "7ff46d441db78241f4c6c27b3868c9ae71473fe03341340d2dfdbe8d79310acc", "965889d9f0e2a75edd81a07592d0ced54daa5b0785f57dc429c378edbcffe779", "9b248ba3dd8a03b1a10b19efe7d4f7fa41d158fdaa95e2cf65af5a7b95a4f989", "9bef37ee224e104a413f0780e29adb3e514a5b698aabe0d969a6ba426b8435d1", "c1ec8db4fac31850286b7cd3b9c0e1b944204668b8eb721674916d4e28744092", "c8a116feafdb1f84607cb3b14aa1418424ae71fee131642fc568d21423b51824", "ce85b06a10fc65e6143518b96d3dca27b081a740bae261c2fb20375801a9d56d", "d705f8aeecdf3262379644e4b55107a3b55860eb812b673b28d0fbc347a60c55", "e898a0863421650f0bebac8ba40840fc02258ef4714cb7e1fd76b6a6354bda36", "f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b"]
-wrapt = ["b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"]
-yarl = ["0c2ab325d33f1b824734b3ef51d4d54a54e0e7a23d13b86974507602334c2cce", "0ca2f395591bbd85ddd50a82eb1fde9c1066fafe888c5c7cc1d810cf03fd3cc6", "2098a4b4b9d75ee352807a95cdf5f10180db903bc5b7270715c6bbe2551f64ce", "25e66e5e2007c7a39541ca13b559cd8ebc2ad8fe00ea94a2aad28a9b1e44e5ae", "26d7c90cb04dee1665282a5d1a998defc1a9e012fdca0f33396f81508f49696d", "308b98b0c8cd1dfef1a0311dc5e38ae8f9b58349226aa0533f15a16717ad702f", "3ce3d4f7c6b69c4e4f0704b32eca8123b9c58ae91af740481aa57d7857b5e41b", "58cd9c469eced558cd81aa3f484b2924e8897049e06889e8ff2510435b7ef74b", "5b10eb0e7f044cf0b035112446b26a3a2946bca9d7d7edb5e54a2ad2f6652abb", "6faa19d3824c21bcbfdfce5171e193c8b4ddafdf0ac3f129ccf0cdfcb083e462", "944494be42fa630134bf907714d40207e646fd5a94423c90d5b514f7b0713fea", "a161de7e50224e8e3de6e184707476b5a989037dcb24292b391a3d66ff158e70", "a4844ebb2be14768f7994f2017f70aca39d658a96c786211be5ddbe1c68794c1", "c2b509ac3d4b988ae8769901c66345425e361d518aecbe4acbfc2567e416626a", "c9959d49a77b0e07559e579f38b2f3711c2b8716b8410b320bf9713013215a1b", "d8cdee92bc930d8b09d8bd2043cedd544d9c8bd7436a77678dd602467a993080", "e15199cdb423316e15f108f51249e44eb156ae5dba232cb73be555324a1d49c2"]
diff --git a/pyproject.toml b/pyproject.toml
index f41c8484fd..4bc1a22707 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,8 +1,8 @@
[tool.black]
-line-length = 99
-target-version = ['py37']
+line-length = "110"
+target-version = ['py39']
include = '\.pyi?$'
-exclude = '''
+extend-exclude = '''
(
/(
\.eggs
@@ -19,6 +19,7 @@ exclude = '''
)
'''
+<<<<<<< HEAD
[tool.poetry]
name = 'Modmail'
version = '3.10.0-dev3'
@@ -33,26 +34,10 @@ readme = 'README.md'
repository = 'https://github.com/kyb3r/modmail'
homepage = 'https://github.com/kyb3r/modmail'
keywords = ['discord', 'modmail']
+=======
+[tool.pylint.messages_control]
+disable = "C0330, C0326"
+>>>>>>> master
-[tool.poetry.dependencies]
-python = "^3.7"
-"discord.py" = "discord.py==1.6.0"
-uvloop = {version = ">=0.12.0", markers = "sys_platform != 'win32'"}
-python-dotenv = ">=0.10.3"
-parsedatetime = "^2.6"
-dnspython = "^1.16"
-isodate = "^0.6.0"
-natural = "^0.2.0"
-motor = {version = "^2.1", optional = true}
-emoji = "^0.5.4"
-python-dateutil = "^2.8"
-colorama = "^0.4.3"
-aiohttp = ">=3.6.0,<3.7.0"
-
-[tool.poetry.dev-dependencies]
-black = {version = "=19.10b0", allow-prereleases = true}
-pylint = "^2.4"
-bandit = "^1.6"
-
-[tool.poetry.extras]
-mongodb = ["motor"]
+[tool.pylint.format]
+max-line-length = "110"
diff --git a/requirements.min.txt b/requirements.min.txt
deleted file mode 100644
index d756599661..0000000000
--- a/requirements.min.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-# Generated as of March, 2021
-# This is the bare minimum requirements.txt for running Modmail.
-# To install requirements.txt run: pip install -r requirements.min.txt
-
-aiohttp==3.6.2
-discord.py==1.6.0
-dnspython==1.16.0
-emoji==0.5.4
-isodate==0.6.0
-motor==2.1.0
-natural==0.2.0
-parsedatetime==2.6
-pymongo==3.10.1
-python-dateutil==2.8.1
-python-dotenv==0.14.0
-websockets==8.1
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000..d802cc0c46
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,29 @@
+#
+# These requirements were autogenerated by pipenv
+# To regenerate from the project's Pipfile, run:
+#
+# pipenv lock --requirements
+#
+
+-i https://pypi.org/simple
+aiohttp==3.7.4.post0
+async-timeout==3.0.1; python_full_version >= '3.5.3'
+attrs==21.2.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
+chardet==4.0.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
+colorama==0.4.4
+discord.py==1.7.3
+dnspython==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
+emoji==1.2.0
+idna==3.2; python_version >= '3.5'
+isodate==0.6.0
+motor==2.4.0
+multidict==5.1.0; python_version >= '3.6'
+natural==0.2.0
+parsedatetime==2.6
+pymongo[srv]==3.11.4
+python-dateutil==2.8.1
+python-dotenv==0.18.0
+six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
+typing-extensions==3.10.0.0
+uvloop==0.15.2; sys_platform != 'win32'
+yarl==1.6.3; python_version >= '3.6'
diff --git a/runtime.txt b/runtime.txt
deleted file mode 100644
index 87665291b8..0000000000
--- a/runtime.txt
+++ /dev/null
@@ -1 +0,0 @@
-python-3.9.4