initial checkin mid-refactoring of the threadodo bot.
This commit is contained in:
parent
d82db83c5a
commit
1337621516
|
@ -160,3 +160,4 @@ cython_debug/
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
|
||||||
|
*creds.json
|
||||||
|
|
1
LICENSE
1
LICENSE
|
@ -230,3 +230,4 @@ The hypothetical commands `show w' and `show c' should show the appropriate part
|
||||||
You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <http://www.gnu.org/licenses/>.
|
You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
# twitter-wiki-bot
|
# wiki-postbot
|
||||||
|
|
||||||
|
Bot to add tweets using an extended wikilink syntax to the wiki
|
||||||
|
|
||||||
|
Starting with twitter, but then will add masto
|
||||||
|
|
||||||
Bot to add tweets using an extended wikilink syntax to the wiki!
|
|
|
@ -0,0 +1,838 @@
|
||||||
|
[[package]]
|
||||||
|
name = "atomicwrites"
|
||||||
|
version = "1.4.0"
|
||||||
|
description = "Atomic file writes."
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "attrs"
|
||||||
|
version = "21.4.0"
|
||||||
|
description = "Classes Without Boilerplate"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
|
||||||
|
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
|
||||||
|
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
|
||||||
|
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "brotli"
|
||||||
|
version = "1.0.9"
|
||||||
|
description = "Python bindings for the Brotli compression library"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "brotlicffi"
|
||||||
|
version = "1.0.9.2"
|
||||||
|
description = "Python CFFI bindings to the Brotli library"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
cffi = ">=1.0.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "certifi"
|
||||||
|
version = "2022.6.15"
|
||||||
|
description = "Python package for providing Mozilla's CA Bundle."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cffi"
|
||||||
|
version = "1.15.0"
|
||||||
|
description = "Foreign Function Interface for Python calling C code."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pycparser = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "charset-normalizer"
|
||||||
|
version = "2.0.12"
|
||||||
|
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
unicode_backport = ["unicodedata2"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.5"
|
||||||
|
description = "Cross-platform colored terminal text."
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "commonmark"
|
||||||
|
version = "0.9.1"
|
||||||
|
description = "Python parser for the CommonMark Markdown spec"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cssselect2"
|
||||||
|
version = "0.6.0"
|
||||||
|
description = "CSS selectors for Python ElementTree"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
tinycss2 = "*"
|
||||||
|
webencodings = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
doc = ["sphinx", "sphinx-rtd-theme"]
|
||||||
|
test = ["pytest", "pytest-cov", "pytest-flake8", "pytest-isort", "coverage"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fonttools"
|
||||||
|
version = "4.33.3"
|
||||||
|
description = "Tools to manipulate font files"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
brotli = {version = ">=1.0.1", optional = true, markers = "platform_python_implementation == \"CPython\" and extra == \"woff\""}
|
||||||
|
brotlicffi = {version = ">=0.8.0", optional = true, markers = "platform_python_implementation != \"CPython\" and extra == \"woff\""}
|
||||||
|
zopfli = {version = ">=0.1.4", optional = true, markers = "extra == \"woff\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "uharfbuzz (>=0.23.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=14.0.0)", "xattr"]
|
||||||
|
graphite = ["lz4 (>=1.7.4.2)"]
|
||||||
|
interpolatable = ["scipy", "munkres"]
|
||||||
|
lxml = ["lxml (>=4.0,<5)"]
|
||||||
|
pathops = ["skia-pathops (>=0.5.0)"]
|
||||||
|
plot = ["matplotlib"]
|
||||||
|
repacker = ["uharfbuzz (>=0.23.0)"]
|
||||||
|
symfont = ["sympy"]
|
||||||
|
type1 = ["xattr"]
|
||||||
|
ufo = ["fs (>=2.2.0,<3)"]
|
||||||
|
unicode = ["unicodedata2 (>=14.0.0)"]
|
||||||
|
woff = ["zopfli (>=0.1.4)", "brotlicffi (>=0.8.0)", "brotli (>=1.0.1)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "html5lib"
|
||||||
|
version = "1.1"
|
||||||
|
description = "HTML parser based on the WHATWG HTML specification"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
six = ">=1.9"
|
||||||
|
webencodings = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
all = ["genshi", "chardet (>=2.2)", "lxml"]
|
||||||
|
chardet = ["chardet (>=2.2)"]
|
||||||
|
genshi = ["genshi"]
|
||||||
|
lxml = ["lxml"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "3.3"
|
||||||
|
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iniconfig"
|
||||||
|
version = "1.1.1"
|
||||||
|
description = "iniconfig: brain-dead simple config-ini parsing"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oauthlib"
|
||||||
|
version = "3.2.0"
|
||||||
|
description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
rsa = ["cryptography (>=3.0.0)"]
|
||||||
|
signals = ["blinker (>=1.4.0)"]
|
||||||
|
signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "21.3"
|
||||||
|
description = "Core utilities for Python packages"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parse"
|
||||||
|
version = "1.19.0"
|
||||||
|
description = "parse() is the opposite of format()"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pillow"
|
||||||
|
version = "9.1.1"
|
||||||
|
description = "Python Imaging Library (Fork)"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinx-rtd-theme (>=1.0)", "sphinxext-opengraph"]
|
||||||
|
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pluggy"
|
||||||
|
version = "1.0.0"
|
||||||
|
description = "plugin and hook calling mechanisms for python"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["pre-commit", "tox"]
|
||||||
|
testing = ["pytest", "pytest-benchmark"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "py"
|
||||||
|
version = "1.11.0"
|
||||||
|
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycparser"
|
||||||
|
version = "2.21"
|
||||||
|
description = "C parser in Python"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydyf"
|
||||||
|
version = "0.2.0"
|
||||||
|
description = "A low-level PDF generator."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
doc = ["sphinx", "sphinx-rtd-theme"]
|
||||||
|
test = ["pytest", "pytest-xdist", "pytest-flake8", "pytest-isort", "pytest-cov", "coverage", "pillow"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pygments"
|
||||||
|
version = "2.12.0"
|
||||||
|
description = "Pygments is a syntax highlighting package written in Python."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pypandoc"
|
||||||
|
version = "1.8.1"
|
||||||
|
description = "Thin wrapper for pandoc."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyparsing"
|
||||||
|
version = "3.0.9"
|
||||||
|
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6.8"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
diagrams = ["railroad-diagrams", "jinja2"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyphen"
|
||||||
|
version = "0.12.0"
|
||||||
|
description = "Pure Python module to hyphenate text"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
doc = ["sphinx", "sphinx-rtd-theme"]
|
||||||
|
test = ["pytest", "pytest-cov", "pytest-flake8", "pytest-isort", "coverage"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest"
|
||||||
|
version = "7.1.2"
|
||||||
|
description = "pytest: simple powerful testing with Python"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
|
||||||
|
attrs = ">=19.2.0"
|
||||||
|
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||||
|
iniconfig = "*"
|
||||||
|
packaging = "*"
|
||||||
|
pluggy = ">=0.12,<2.0"
|
||||||
|
py = ">=1.8.2"
|
||||||
|
tomli = ">=1.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "requests"
|
||||||
|
version = "2.28.0"
|
||||||
|
description = "Python HTTP for Humans."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7, <4"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
certifi = ">=2017.4.17"
|
||||||
|
charset-normalizer = ">=2.0.0,<2.1.0"
|
||||||
|
idna = ">=2.5,<4"
|
||||||
|
urllib3 = ">=1.21.1,<1.27"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||||
|
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "requests-oauthlib"
|
||||||
|
version = "1.3.1"
|
||||||
|
description = "OAuthlib authentication support for Requests."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
oauthlib = ">=3.0.0"
|
||||||
|
requests = ">=2.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rich"
|
||||||
|
version = "12.4.4"
|
||||||
|
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6.3,<4.0.0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
commonmark = ">=0.9.0,<0.10.0"
|
||||||
|
pygments = ">=2.6.0,<3.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "six"
|
||||||
|
version = "1.16.0"
|
||||||
|
description = "Python 2 and 3 compatibility utilities"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinycss2"
|
||||||
|
version = "1.1.1"
|
||||||
|
description = "A tiny CSS parser"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
webencodings = ">=0.4"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
doc = ["sphinx", "sphinx-rtd-theme"]
|
||||||
|
test = ["pytest", "pytest-cov", "pytest-flake8", "pytest-isort", "coverage"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomli"
|
||||||
|
version = "2.0.1"
|
||||||
|
description = "A lil' TOML parser"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tweepy"
|
||||||
|
version = "4.10.0"
|
||||||
|
description = "Twitter library for Python"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
oauthlib = ">=3.2.0,<4"
|
||||||
|
requests = ">=2.27.0,<3"
|
||||||
|
requests-oauthlib = ">=1.2.0,<2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
async = ["aiohttp (>=3.7.3,<4)", "async-lru (>=1.0.3,<2)"]
|
||||||
|
dev = ["coverage (>=4.4.2)", "coveralls (>=2.1.0)", "tox (>=3.21.0)"]
|
||||||
|
socks = ["requests[socks] (>=2.27.0,<3)"]
|
||||||
|
test = ["vcrpy (>=1.10.3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urllib3"
|
||||||
|
version = "1.26.9"
|
||||||
|
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"]
|
||||||
|
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
||||||
|
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "weasyprint"
|
||||||
|
version = "55.0"
|
||||||
|
description = "The Awesome Document Factory"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
cffi = ">=0.6"
|
||||||
|
cssselect2 = ">=0.1"
|
||||||
|
fonttools = {version = ">=4.0.0", extras = ["woff"]}
|
||||||
|
html5lib = ">=1.1"
|
||||||
|
Pillow = ">=4.0.0"
|
||||||
|
pydyf = ">=0.0.3"
|
||||||
|
Pyphen = ">=0.9.1"
|
||||||
|
tinycss2 = ">=1.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
doc = ["sphinx", "sphinx-rtd-theme"]
|
||||||
|
test = ["pytest", "pytest-cov", "pytest-flake8", "pytest-isort", "coverage"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webencodings"
|
||||||
|
version = "0.5.1"
|
||||||
|
description = "Character encoding aliases for legacy web content"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zopfli"
|
||||||
|
version = "0.2.1"
|
||||||
|
description = "Zopfli module for python"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
test = ["pytest"]
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
lock-version = "1.1"
|
||||||
|
python-versions = "^3.9"
|
||||||
|
content-hash = "423cdca5ac87cd46ad86f1a5ac17ae17330ad736b226edfa90b6723e5b230674"
|
||||||
|
|
||||||
|
[metadata.files]
|
||||||
|
atomicwrites = [
|
||||||
|
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
|
||||||
|
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
|
||||||
|
]
|
||||||
|
attrs = [
|
||||||
|
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
|
||||||
|
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
|
||||||
|
]
|
||||||
|
brotli = [
|
||||||
|
{file = "Brotli-1.0.9-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:268fe94547ba25b58ebc724680609c8ee3e5a843202e9a381f6f9c5e8bdb5c70"},
|
||||||
|
{file = "Brotli-1.0.9-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:c2415d9d082152460f2bd4e382a1e85aed233abc92db5a3880da2257dc7daf7b"},
|
||||||
|
{file = "Brotli-1.0.9-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5913a1177fc36e30fcf6dc868ce23b0453952c78c04c266d3149b3d39e1410d6"},
|
||||||
|
{file = "Brotli-1.0.9-cp27-cp27m-win32.whl", hash = "sha256:afde17ae04d90fbe53afb628f7f2d4ca022797aa093e809de5c3cf276f61bbfa"},
|
||||||
|
{file = "Brotli-1.0.9-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7cb81373984cc0e4682f31bc3d6be9026006d96eecd07ea49aafb06897746452"},
|
||||||
|
{file = "Brotli-1.0.9-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:db844eb158a87ccab83e868a762ea8024ae27337fc7ddcbfcddd157f841fdfe7"},
|
||||||
|
{file = "Brotli-1.0.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9744a863b489c79a73aba014df554b0e7a0fc44ef3f8a0ef2a52919c7d155031"},
|
||||||
|
{file = "Brotli-1.0.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a72661af47119a80d82fa583b554095308d6a4c356b2a554fdc2799bc19f2a43"},
|
||||||
|
{file = "Brotli-1.0.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ee83d3e3a024a9618e5be64648d6d11c37047ac48adff25f12fa4226cf23d1c"},
|
||||||
|
{file = "Brotli-1.0.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:19598ecddd8a212aedb1ffa15763dd52a388518c4550e615aed88dc3753c0f0c"},
|
||||||
|
{file = "Brotli-1.0.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:44bb8ff420c1d19d91d79d8c3574b8954288bdff0273bf788954064d260d7ab0"},
|
||||||
|
{file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e23281b9a08ec338469268f98f194658abfb13658ee98e2b7f85ee9dd06caa91"},
|
||||||
|
{file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3496fc835370da351d37cada4cf744039616a6db7d13c430035e901443a34daa"},
|
||||||
|
{file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83bb06a0192cccf1eb8d0a28672a1b79c74c3a8a5f2619625aeb6f28b3a82bb"},
|
||||||
|
{file = "Brotli-1.0.9-cp310-cp310-win32.whl", hash = "sha256:26d168aac4aaec9a4394221240e8a5436b5634adc3cd1cdf637f6645cecbf181"},
|
||||||
|
{file = "Brotli-1.0.9-cp310-cp310-win_amd64.whl", hash = "sha256:622a231b08899c864eb87e85f81c75e7b9ce05b001e59bbfbf43d4a71f5f32b2"},
|
||||||
|
{file = "Brotli-1.0.9-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:c83aa123d56f2e060644427a882a36b3c12db93727ad7a7b9efd7d7f3e9cc2c4"},
|
||||||
|
{file = "Brotli-1.0.9-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:6b2ae9f5f67f89aade1fab0f7fd8f2832501311c363a21579d02defa844d9296"},
|
||||||
|
{file = "Brotli-1.0.9-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:68715970f16b6e92c574c30747c95cf8cf62804569647386ff032195dc89a430"},
|
||||||
|
{file = "Brotli-1.0.9-cp35-cp35m-win32.whl", hash = "sha256:defed7ea5f218a9f2336301e6fd379f55c655bea65ba2476346340a0ce6f74a1"},
|
||||||
|
{file = "Brotli-1.0.9-cp35-cp35m-win_amd64.whl", hash = "sha256:88c63a1b55f352b02c6ffd24b15ead9fc0e8bf781dbe070213039324922a2eea"},
|
||||||
|
{file = "Brotli-1.0.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:503fa6af7da9f4b5780bb7e4cbe0c639b010f12be85d02c99452825dd0feef3f"},
|
||||||
|
{file = "Brotli-1.0.9-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:40d15c79f42e0a2c72892bf407979febd9cf91f36f495ffb333d1d04cebb34e4"},
|
||||||
|
{file = "Brotli-1.0.9-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:93130612b837103e15ac3f9cbacb4613f9e348b58b3aad53721d92e57f96d46a"},
|
||||||
|
{file = "Brotli-1.0.9-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87fdccbb6bb589095f413b1e05734ba492c962b4a45a13ff3408fa44ffe6479b"},
|
||||||
|
{file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:6d847b14f7ea89f6ad3c9e3901d1bc4835f6b390a9c71df999b0162d9bb1e20f"},
|
||||||
|
{file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:495ba7e49c2db22b046a53b469bbecea802efce200dffb69b93dd47397edc9b6"},
|
||||||
|
{file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:4688c1e42968ba52e57d8670ad2306fe92e0169c6f3af0089be75bbac0c64a3b"},
|
||||||
|
{file = "Brotli-1.0.9-cp36-cp36m-win32.whl", hash = "sha256:61a7ee1f13ab913897dac7da44a73c6d44d48a4adff42a5701e3239791c96e14"},
|
||||||
|
{file = "Brotli-1.0.9-cp36-cp36m-win_amd64.whl", hash = "sha256:1c48472a6ba3b113452355b9af0a60da5c2ae60477f8feda8346f8fd48e3e87c"},
|
||||||
|
{file = "Brotli-1.0.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3b78a24b5fd13c03ee2b7b86290ed20efdc95da75a3557cc06811764d5ad1126"},
|
||||||
|
{file = "Brotli-1.0.9-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:9d12cf2851759b8de8ca5fde36a59c08210a97ffca0eb94c532ce7b17c6a3d1d"},
|
||||||
|
{file = "Brotli-1.0.9-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6c772d6c0a79ac0f414a9f8947cc407e119b8598de7621f39cacadae3cf57d12"},
|
||||||
|
{file = "Brotli-1.0.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29d1d350178e5225397e28ea1b7aca3648fcbab546d20e7475805437bfb0a130"},
|
||||||
|
{file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7bbff90b63328013e1e8cb50650ae0b9bac54ffb4be6104378490193cd60f85a"},
|
||||||
|
{file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ec1947eabbaf8e0531e8e899fc1d9876c179fc518989461f5d24e2223395a9e3"},
|
||||||
|
{file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12effe280b8ebfd389022aa65114e30407540ccb89b177d3fbc9a4f177c4bd5d"},
|
||||||
|
{file = "Brotli-1.0.9-cp37-cp37m-win32.whl", hash = "sha256:f909bbbc433048b499cb9db9e713b5d8d949e8c109a2a548502fb9aa8630f0b1"},
|
||||||
|
{file = "Brotli-1.0.9-cp37-cp37m-win_amd64.whl", hash = "sha256:97f715cf371b16ac88b8c19da00029804e20e25f30d80203417255d239f228b5"},
|
||||||
|
{file = "Brotli-1.0.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e16eb9541f3dd1a3e92b89005e37b1257b157b7256df0e36bd7b33b50be73bcb"},
|
||||||
|
{file = "Brotli-1.0.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:160c78292e98d21e73a4cc7f76a234390e516afcd982fa17e1422f7c6a9ce9c8"},
|
||||||
|
{file = "Brotli-1.0.9-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b663f1e02de5d0573610756398e44c130add0eb9a3fc912a09665332942a2efb"},
|
||||||
|
{file = "Brotli-1.0.9-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5b6ef7d9f9c38292df3690fe3e302b5b530999fa90014853dcd0d6902fb59f26"},
|
||||||
|
{file = "Brotli-1.0.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a674ac10e0a87b683f4fa2b6fa41090edfd686a6524bd8dedbd6138b309175c"},
|
||||||
|
{file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e2d9e1cbc1b25e22000328702b014227737756f4b5bf5c485ac1d8091ada078b"},
|
||||||
|
{file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b336c5e9cf03c7be40c47b5fd694c43c9f1358a80ba384a21969e0b4e66a9b17"},
|
||||||
|
{file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:85f7912459c67eaab2fb854ed2bc1cc25772b300545fe7ed2dc03954da638649"},
|
||||||
|
{file = "Brotli-1.0.9-cp38-cp38-win32.whl", hash = "sha256:35a3edbe18e876e596553c4007a087f8bcfd538f19bc116917b3c7522fca0429"},
|
||||||
|
{file = "Brotli-1.0.9-cp38-cp38-win_amd64.whl", hash = "sha256:269a5743a393c65db46a7bb982644c67ecba4b8d91b392403ad8a861ba6f495f"},
|
||||||
|
{file = "Brotli-1.0.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2aad0e0baa04517741c9bb5b07586c642302e5fb3e75319cb62087bd0995ab19"},
|
||||||
|
{file = "Brotli-1.0.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5cb1e18167792d7d21e21365d7650b72d5081ed476123ff7b8cac7f45189c0c7"},
|
||||||
|
{file = "Brotli-1.0.9-cp39-cp39-manylinux1_i686.whl", hash = "sha256:16d528a45c2e1909c2798f27f7bf0a3feec1dc9e50948e738b961618e38b6a7b"},
|
||||||
|
{file = "Brotli-1.0.9-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:56d027eace784738457437df7331965473f2c0da2c70e1a1f6fdbae5402e0389"},
|
||||||
|
{file = "Brotli-1.0.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bf919756d25e4114ace16a8ce91eb340eb57a08e2c6950c3cebcbe3dff2a5e7"},
|
||||||
|
{file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e4c4e92c14a57c9bd4cb4be678c25369bf7a092d55fd0866f759e425b9660806"},
|
||||||
|
{file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e48f4234f2469ed012a98f4b7874e7f7e173c167bed4934912a29e03167cf6b1"},
|
||||||
|
{file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9ed4c92a0665002ff8ea852353aeb60d9141eb04109e88928026d3c8a9e5433c"},
|
||||||
|
{file = "Brotli-1.0.9-cp39-cp39-win32.whl", hash = "sha256:cfc391f4429ee0a9370aa93d812a52e1fee0f37a81861f4fdd1f4fb28e8547c3"},
|
||||||
|
{file = "Brotli-1.0.9-cp39-cp39-win_amd64.whl", hash = "sha256:854c33dad5ba0fbd6ab69185fec8dab89e13cda6b7d191ba111987df74f38761"},
|
||||||
|
{file = "Brotli-1.0.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9749a124280a0ada4187a6cfd1ffd35c350fb3af79c706589d98e088c5044267"},
|
||||||
|
{file = "Brotli-1.0.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:76ffebb907bec09ff511bb3acc077695e2c32bc2142819491579a695f77ffd4d"},
|
||||||
|
{file = "Brotli-1.0.9.zip", hash = "sha256:4d1b810aa0ed773f81dceda2cc7b403d01057458730e309856356d4ef4188438"},
|
||||||
|
]
|
||||||
|
brotlicffi = [
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:408ec4359f9763280d5c4e0ad29c51d1240b25fdd18719067e972163b4125b98"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2e4629f7690ded66c8818715c6d4dd6a7ff6a4f10fad6186fe99850f781ce210"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:137c4635edcdf593de5ce9d0daa596bf499591b16b8fca5fd72a490deb54b2ee"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:af8a1b7bcfccf9c41a3c8654994d6a81821fdfe4caddcfe5045bfda936546ca3"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9078432af4785f35ab3840587eed7fb131e3fc77eb2a739282b649b343c584dd"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7bb913d5bf3b4ce2ec59872711dc9faaff5f320c3c3827cada2d8a7b793a7753"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:16a0c9392a1059e2e62839fbd037d2e7e03c8ae5da65e9746f582464f7fab1bb"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:94d2810efc5723f1447b332223b197466190518a3eeca93b9f357efb5b22c6dc"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:9e70f3e20f317d70912b10dbec48b29114d3dbd0e9d88475cb328e6c086f0546"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:586f0ea3c2eed455d5f2330b9ab4a591514c8de0ee53d445645efcfbf053c69f"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp35-abi3-manylinux1_i686.whl", hash = "sha256:4454c3baedc277fd6e65f983e3eb8e77f4bc15060f69370a0201746e2edeca81"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:52c1c12dad6eb1d44213a0a76acf5f18f64653bd801300bef5e2f983405bdde5"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:21cd400d24b344c218d8e32b394849e31b7c15784667575dbda9f65c46a64b0a"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:71061f8bc86335b652e442260c4367b782a92c6e295cf5a10eff84c7d19d8cf5"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:15e0db52c56056be6310fc116b3d7c6f34185594e261f23790b2fb6489998363"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp35-abi3-win32.whl", hash = "sha256:551305703d12a2dd1ae43d3dde35dee20b1cb49b5796279d4d34e2c6aec6be4d"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-cp35-abi3-win_amd64.whl", hash = "sha256:2be4fb8a7cb482f226af686cd06d2a2cab164ccdf99e460f8e3a5ec9a5337da2"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:8e7221d8a084d32d15c7b58e0ce0573972375c5038423dbe83f217cfe512e680"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:75a46bc5ed2753e1648cc211dcb2c1ac66116038766822dc104023f67ff4dfd8"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:1e27c43ef72a278f9739b12b2df80ee72048cd4cbe498f8bbe08aaaa67a5d5c8"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp27-pypy_73-win32.whl", hash = "sha256:feb942814285bdc5e97efc77a04e48283c17dfab9ea082d79c0a7b9e53ef1eab"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a6208d82c3172eeeb3be83ed4efd5831552c7cd47576468e50fcf0fb23fcf97f"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:408c810c599786fb806556ff17e844a903884e6370ca400bcec7fa286149f39c"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:a73099858ee343e8801710a08be8d194f47715ff21e98d92a19ac461058f52d1"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp36-pypy36_pp73-win32.whl", hash = "sha256:916b790f967a18a595e61f218c252f83718ac91f24157d622cf0fa710cd26ab7"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba4a00263af40e875ec3d6c7f623cbf8c795b55705da18c64ec36b6bf0848bc5"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp37-pypy37_pp73-manylinux1_x86_64.whl", hash = "sha256:df78aa47741122b0d5463f1208b7bb18bc9706dee5152d9f56e0ead4865015cd"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:9030cd5099252d16bfa4e22659c84a89c102e94f8e81d30764788b72e2d7cfb7"},
|
||||||
|
{file = "brotlicffi-1.0.9.2-pp37-pypy37_pp73-win32.whl", hash = "sha256:7e72978f4090a161885b114f87b784f538dcb77dafc6602592c1cf39ae8d243d"},
|
||||||
|
{file = "brotlicffi-1.0.9.2.tar.gz", hash = "sha256:0c248a68129d8fc6a217767406c731e498c3e19a7be05ea0a90c3c86637b7d96"},
|
||||||
|
]
|
||||||
|
certifi = [
|
||||||
|
{file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"},
|
||||||
|
{file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"},
|
||||||
|
]
|
||||||
|
cffi = [
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"},
|
||||||
|
{file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"},
|
||||||
|
{file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"},
|
||||||
|
{file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"},
|
||||||
|
{file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"},
|
||||||
|
{file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"},
|
||||||
|
{file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"},
|
||||||
|
{file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"},
|
||||||
|
]
|
||||||
|
charset-normalizer = [
|
||||||
|
{file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"},
|
||||||
|
{file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"},
|
||||||
|
]
|
||||||
|
colorama = [
|
||||||
|
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
|
||||||
|
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
|
||||||
|
]
|
||||||
|
commonmark = [
|
||||||
|
{file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
|
||||||
|
{file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
|
||||||
|
]
|
||||||
|
cssselect2 = [
|
||||||
|
{file = "cssselect2-0.6.0-py3-none-any.whl", hash = "sha256:3a83b2a68370c69c9cd3fcb88bbfaebe9d22edeef2c22d1ff3e1ed9c7fa45ed8"},
|
||||||
|
{file = "cssselect2-0.6.0.tar.gz", hash = "sha256:5b5d6dea81a5eb0c9ca39f116c8578dd413778060c94c1f51196371618909325"},
|
||||||
|
]
|
||||||
|
fonttools = [
|
||||||
|
{file = "fonttools-4.33.3-py3-none-any.whl", hash = "sha256:f829c579a8678fa939a1d9e9894d01941db869de44390adb49ce67055a06cc2a"},
|
||||||
|
{file = "fonttools-4.33.3.zip", hash = "sha256:c0fdcfa8ceebd7c1b2021240bd46ef77aa8e7408cf10434be55df52384865f8e"},
|
||||||
|
]
|
||||||
|
html5lib = [
|
||||||
|
{file = "html5lib-1.1-py2.py3-none-any.whl", hash = "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d"},
|
||||||
|
{file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"},
|
||||||
|
]
|
||||||
|
idna = [
|
||||||
|
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
|
||||||
|
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
|
||||||
|
]
|
||||||
|
iniconfig = [
|
||||||
|
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
||||||
|
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
||||||
|
]
|
||||||
|
oauthlib = [
|
||||||
|
{file = "oauthlib-3.2.0-py3-none-any.whl", hash = "sha256:6db33440354787f9b7f3a6dbd4febf5d0f93758354060e802f6c06cb493022fe"},
|
||||||
|
{file = "oauthlib-3.2.0.tar.gz", hash = "sha256:23a8208d75b902797ea29fd31fa80a15ed9dc2c6c16fe73f5d346f83f6fa27a2"},
|
||||||
|
]
|
||||||
|
packaging = [
|
||||||
|
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||||
|
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||||
|
]
|
||||||
|
parse = [
|
||||||
|
{file = "parse-1.19.0.tar.gz", hash = "sha256:9ff82852bcb65d139813e2a5197627a94966245c897796760a3a2a8eb66f020b"},
|
||||||
|
]
|
||||||
|
pillow = [
|
||||||
|
{file = "Pillow-9.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:42dfefbef90eb67c10c45a73a9bc1599d4dac920f7dfcbf4ec6b80cb620757fe"},
|
||||||
|
{file = "Pillow-9.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffde4c6fabb52891d81606411cbfaf77756e3b561b566efd270b3ed3791fde4e"},
|
||||||
|
{file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c857532c719fb30fafabd2371ce9b7031812ff3889d75273827633bca0c4602"},
|
||||||
|
{file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59789a7d06c742e9d13b883d5e3569188c16acb02eeed2510fd3bfdbc1bd1530"},
|
||||||
|
{file = "Pillow-9.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d45dbe4b21a9679c3e8b3f7f4f42a45a7d3ddff8a4a16109dff0e1da30a35b2"},
|
||||||
|
{file = "Pillow-9.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e9ed59d1b6ee837f4515b9584f3d26cf0388b742a11ecdae0d9237a94505d03a"},
|
||||||
|
{file = "Pillow-9.1.1-cp310-cp310-win32.whl", hash = "sha256:b3fe2ff1e1715d4475d7e2c3e8dabd7c025f4410f79513b4ff2de3d51ce0fa9c"},
|
||||||
|
{file = "Pillow-9.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5b650dbbc0969a4e226d98a0b440c2f07a850896aed9266b6fedc0f7e7834108"},
|
||||||
|
{file = "Pillow-9.1.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:0b4d5ad2cd3a1f0d1df882d926b37dbb2ab6c823ae21d041b46910c8f8cd844b"},
|
||||||
|
{file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9370d6744d379f2de5d7fa95cdbd3a4d92f0b0ef29609b4b1687f16bc197063d"},
|
||||||
|
{file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b761727ed7d593e49671d1827044b942dd2f4caae6e51bab144d4accf8244a84"},
|
||||||
|
{file = "Pillow-9.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a66fe50386162df2da701b3722781cbe90ce043e7d53c1fd6bd801bca6b48d4"},
|
||||||
|
{file = "Pillow-9.1.1-cp37-cp37m-win32.whl", hash = "sha256:2b291cab8a888658d72b575a03e340509b6b050b62db1f5539dd5cd18fd50578"},
|
||||||
|
{file = "Pillow-9.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1d4331aeb12f6b3791911a6da82de72257a99ad99726ed6b63f481c0184b6fb9"},
|
||||||
|
{file = "Pillow-9.1.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8844217cdf66eabe39567118f229e275f0727e9195635a15e0e4b9227458daaf"},
|
||||||
|
{file = "Pillow-9.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b6617221ff08fbd3b7a811950b5c3f9367f6e941b86259843eab77c8e3d2b56b"},
|
||||||
|
{file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20d514c989fa28e73a5adbddd7a171afa5824710d0ab06d4e1234195d2a2e546"},
|
||||||
|
{file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:088df396b047477dd1bbc7de6e22f58400dae2f21310d9e2ec2933b2ef7dfa4f"},
|
||||||
|
{file = "Pillow-9.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53c27bd452e0f1bc4bfed07ceb235663a1df7c74df08e37fd6b03eb89454946a"},
|
||||||
|
{file = "Pillow-9.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3f6c1716c473ebd1649663bf3b42702d0d53e27af8b64642be0dd3598c761fb1"},
|
||||||
|
{file = "Pillow-9.1.1-cp38-cp38-win32.whl", hash = "sha256:c67db410508b9de9c4694c57ed754b65a460e4812126e87f5052ecf23a011a54"},
|
||||||
|
{file = "Pillow-9.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:f054b020c4d7e9786ae0404278ea318768eb123403b18453e28e47cdb7a0a4bf"},
|
||||||
|
{file = "Pillow-9.1.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:c17770a62a71718a74b7548098a74cd6880be16bcfff5f937f900ead90ca8e92"},
|
||||||
|
{file = "Pillow-9.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3f6a6034140e9e17e9abc175fc7a266a6e63652028e157750bd98e804a8ed9a"},
|
||||||
|
{file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f372d0f08eff1475ef426344efe42493f71f377ec52237bf153c5713de987251"},
|
||||||
|
{file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09e67ef6e430f90caa093528bd758b0616f8165e57ed8d8ce014ae32df6a831d"},
|
||||||
|
{file = "Pillow-9.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66daa16952d5bf0c9d5389c5e9df562922a59bd16d77e2a276e575d32e38afd1"},
|
||||||
|
{file = "Pillow-9.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d78ca526a559fb84faaaf84da2dd4addef5edb109db8b81677c0bb1aad342601"},
|
||||||
|
{file = "Pillow-9.1.1-cp39-cp39-win32.whl", hash = "sha256:55e74faf8359ddda43fee01bffbc5bd99d96ea508d8a08c527099e84eb708f45"},
|
||||||
|
{file = "Pillow-9.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:7c150dbbb4a94ea4825d1e5f2c5501af7141ea95825fadd7829f9b11c97aaf6c"},
|
||||||
|
{file = "Pillow-9.1.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:769a7f131a2f43752455cc72f9f7a093c3ff3856bf976c5fb53a59d0ccc704f6"},
|
||||||
|
{file = "Pillow-9.1.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:488f3383cf5159907d48d32957ac6f9ea85ccdcc296c14eca1a4e396ecc32098"},
|
||||||
|
{file = "Pillow-9.1.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b525a356680022b0af53385944026d3486fc8c013638cf9900eb87c866afb4c"},
|
||||||
|
{file = "Pillow-9.1.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6e760cf01259a1c0a50f3c845f9cad1af30577fd8b670339b1659c6d0e7a41dd"},
|
||||||
|
{file = "Pillow-9.1.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4165205a13b16a29e1ac57efeee6be2dfd5b5408122d59ef2145bc3239fa340"},
|
||||||
|
{file = "Pillow-9.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937a54e5694684f74dcbf6e24cc453bfc5b33940216ddd8f4cd8f0f79167f765"},
|
||||||
|
{file = "Pillow-9.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:baf3be0b9446a4083cc0c5bb9f9c964034be5374b5bc09757be89f5d2fa247b8"},
|
||||||
|
{file = "Pillow-9.1.1.tar.gz", hash = "sha256:7502539939b53d7565f3d11d87c78e7ec900d3c72945d4ee0e2f250d598309a0"},
|
||||||
|
]
|
||||||
|
pluggy = [
|
||||||
|
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
|
||||||
|
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
|
||||||
|
]
|
||||||
|
py = [
|
||||||
|
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
||||||
|
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||||
|
]
|
||||||
|
pycparser = [
|
||||||
|
{file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
|
||||||
|
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
|
||||||
|
]
|
||||||
|
pydyf = [
|
||||||
|
{file = "pydyf-0.2.0-py3-none-any.whl", hash = "sha256:f0468bc644d3a5b0a7072d0d92bd5c024cf4beede0df56100d9919a59f15e1f0"},
|
||||||
|
{file = "pydyf-0.2.0.tar.gz", hash = "sha256:06ebc18b4de29fc1450ae49dd142ecd26bd7ba09d0b1919e365fbc3d8af8a622"},
|
||||||
|
]
|
||||||
|
pygments = [
|
||||||
|
{file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"},
|
||||||
|
{file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"},
|
||||||
|
]
|
||||||
|
pypandoc = [
|
||||||
|
{file = "pypandoc-1.8.1-py3-none-any.whl", hash = "sha256:3d7eda399f9169f16106362c55a8f12f30ab0575cfd2cdc6e1856b214cc4c38c"},
|
||||||
|
{file = "pypandoc-1.8.1.tar.gz", hash = "sha256:8c1b651d338e8441843b991835f59d561a8473cfe63f0126d330fdb3cb518809"},
|
||||||
|
]
|
||||||
|
pyparsing = [
|
||||||
|
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
|
||||||
|
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
|
||||||
|
]
|
||||||
|
pyphen = [
|
||||||
|
{file = "pyphen-0.12.0-py3-none-any.whl", hash = "sha256:459020cd320eb200c0c5ba46b98b2278fd34c5546f520fdcd2ce5f8d733eb994"},
|
||||||
|
{file = "pyphen-0.12.0.tar.gz", hash = "sha256:b7d3dfc24b6f2178cdb2b1757ace0bd5d222de3e62c28d22ac578c5f22a13e9b"},
|
||||||
|
]
|
||||||
|
pytest = [
|
||||||
|
{file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"},
|
||||||
|
{file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"},
|
||||||
|
]
|
||||||
|
requests = [
|
||||||
|
{file = "requests-2.28.0-py3-none-any.whl", hash = "sha256:bc7861137fbce630f17b03d3ad02ad0bf978c844f3536d0edda6499dafce2b6f"},
|
||||||
|
{file = "requests-2.28.0.tar.gz", hash = "sha256:d568723a7ebd25875d8d1eaf5dfa068cd2fc8194b2e483d7b1f7c81918dbec6b"},
|
||||||
|
]
|
||||||
|
requests-oauthlib = [
|
||||||
|
{file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"},
|
||||||
|
{file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"},
|
||||||
|
]
|
||||||
|
rich = [
|
||||||
|
{file = "rich-12.4.4-py3-none-any.whl", hash = "sha256:d2bbd99c320a2532ac71ff6a3164867884357da3e3301f0240090c5d2fdac7ec"},
|
||||||
|
{file = "rich-12.4.4.tar.gz", hash = "sha256:4c586de507202505346f3e32d1363eb9ed6932f0c2f63184dea88983ff4971e2"},
|
||||||
|
]
|
||||||
|
six = [
|
||||||
|
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||||
|
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||||
|
]
|
||||||
|
tinycss2 = [
|
||||||
|
{file = "tinycss2-1.1.1-py3-none-any.whl", hash = "sha256:fe794ceaadfe3cf3e686b22155d0da5780dd0e273471a51846d0a02bc204fec8"},
|
||||||
|
{file = "tinycss2-1.1.1.tar.gz", hash = "sha256:b2e44dd8883c360c35dd0d1b5aad0b610e5156c2cb3b33434634e539ead9d8bf"},
|
||||||
|
]
|
||||||
|
tomli = [
|
||||||
|
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||||
|
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||||
|
]
|
||||||
|
tweepy = [
|
||||||
|
{file = "tweepy-4.10.0-py3-none-any.whl", hash = "sha256:f0abbd234a588e572f880f99a094ac321217ff3eade6c0eca118ed6db8e2cf0a"},
|
||||||
|
{file = "tweepy-4.10.0.tar.gz", hash = "sha256:7f92574920c2f233663fff154745fc2bb0d10aedc23617379a912d8e4fefa399"},
|
||||||
|
]
|
||||||
|
urllib3 = [
|
||||||
|
{file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"},
|
||||||
|
{file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"},
|
||||||
|
]
|
||||||
|
weasyprint = [
|
||||||
|
{file = "weasyprint-55.0-py3-none-any.whl", hash = "sha256:6a5008b3e1152498f206b2d0791b3e161f507607e31ca42b307cb31b49795462"},
|
||||||
|
{file = "weasyprint-55.0.tar.gz", hash = "sha256:ea5d5f2f159262e38b6e85939d8510e9735a47751a9647c9eaa93c22ced86230"},
|
||||||
|
]
|
||||||
|
webencodings = [
|
||||||
|
{file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"},
|
||||||
|
{file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"},
|
||||||
|
]
|
||||||
|
zopfli = [
|
||||||
|
{file = "zopfli-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f61ecd57bc47684c44a60e8cecb8e67f633cf238f30cc255627e172119ad72d"},
|
||||||
|
{file = "zopfli-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a8ca5b541544a7b959fdf5a8f614c52a31002e4be489663d835aadeef3473cb0"},
|
||||||
|
{file = "zopfli-0.2.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bbcdbfe93dad34f0e30f166092ffdf95e564e415b29732a6f6a52def7bb1c4d3"},
|
||||||
|
{file = "zopfli-0.2.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c829c577f976b05e4ec583da4f48f31448db97b9f7b65c438d45ba7893aa2a7"},
|
||||||
|
{file = "zopfli-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28a103434694ce35cbe4f2380e18077052a78f1a0de061b3c8f1bd35b54c2822"},
|
||||||
|
{file = "zopfli-0.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8a40d9d113902aea0de370dce115051cf9cae4767b50af4fdde66d931b9bcae5"},
|
||||||
|
{file = "zopfli-0.2.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d8457452a9151b56f17bbb9af57a4764fb41958ab84bf808e3296aefb6e61bca"},
|
||||||
|
{file = "zopfli-0.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b882f85b13c47eb19e7f07bccac7564701424ed5ec6d7ba8886ad6de04110e21"},
|
||||||
|
{file = "zopfli-0.2.1-cp310-cp310-win32.whl", hash = "sha256:e9091778e9e0dbbded72c389eace553153102acc9da560870d9d0845c8547a8d"},
|
||||||
|
{file = "zopfli-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:7e2b47662632809d7035f4fc16edbe141c4538158ad74eb3c47532b8bedb8277"},
|
||||||
|
{file = "zopfli-0.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ba4001a8c798a9bb2a59bb30284acd604e0c702477dce69b7fde35a50e55a95b"},
|
||||||
|
{file = "zopfli-0.2.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fa38b9bb6636fd11b3348dfd6aee4839e71145c3aebc76de4ba44886ec9fd6e"},
|
||||||
|
{file = "zopfli-0.2.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:58b2bd497273e1344098370d959f837ec1d18bae9bfafad8f4e4a2802cbbf049"},
|
||||||
|
{file = "zopfli-0.2.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:51537999c2114a68b1c0fac8f7ab2a05e4251d778b568213f1666f04feb79e1c"},
|
||||||
|
{file = "zopfli-0.2.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:38b1928a5fc5c706ec90aa833ffb5f4512bf886fe41c1b30a95edf7fb09544d6"},
|
||||||
|
{file = "zopfli-0.2.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7b189d80aeedb986d226e966df9e13fe8ccc28352d9d5c6c1bd3ac208aa79769"},
|
||||||
|
{file = "zopfli-0.2.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f04a2cf50797dfa6fa954dd24de533f471542aa1923b89381a046a936bcbdcc5"},
|
||||||
|
{file = "zopfli-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:3663d25419476b9e999e12ab8f6f5f8d39079bf536947da2cb5f3e45491db6f4"},
|
||||||
|
{file = "zopfli-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:fe9c9276edafb8746c01be15e5d702dcdab41062e2f7fb8af1dd8fa51a18b717"},
|
||||||
|
{file = "zopfli-0.2.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:338c7b2bba06ff60a73f724b7e1c8a16a5aebe9155edf58cf69b4ff7cb0b46f6"},
|
||||||
|
{file = "zopfli-0.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dbf30730f169bbe77b2b6e000bf8b486559e8a36e6ab82f2471d75be4661e6bc"},
|
||||||
|
{file = "zopfli-0.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d067f39d72f364ae94a118df3b4cf2db8a9f53625f497ad0f04bf91ea8720db0"},
|
||||||
|
{file = "zopfli-0.2.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0190633ca26568f6fa810af9b7c108279d5f565a8aca1224333ff732f565086d"},
|
||||||
|
{file = "zopfli-0.2.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:faf26674e52a957b8fd76e955b6d89215265f4b8c7e13abf834c84a8e23def9d"},
|
||||||
|
{file = "zopfli-0.2.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:683c2d521553aa8ca4526c911d419d37223db298f76048ce920aded18ae060cb"},
|
||||||
|
{file = "zopfli-0.2.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0f45111b31f32aef070be180433fec5de548dc87caf92c5c304d1e3642b12815"},
|
||||||
|
{file = "zopfli-0.2.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b25540fee3d54e0fb627f911f7e1bed79611ea09aa048708777a34f6f1ac9b70"},
|
||||||
|
{file = "zopfli-0.2.1-cp38-cp38-win32.whl", hash = "sha256:cfffa5ad327585754f811fd49518d7170d200ba7888c49ae8629ae94c6c4a77d"},
|
||||||
|
{file = "zopfli-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:95a7ca4571797375b1fa924858cda344767621ef70a43b1b2c0b116e275f42b2"},
|
||||||
|
{file = "zopfli-0.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5ffcdc5ee695da73990f7806f8f1dd9a6d99d338bbe54d08fb3aaa55c9603e27"},
|
||||||
|
{file = "zopfli-0.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2442b99067229d786aa9f9b86976db1ba9602c1b204f361d2901d1bbcaca3441"},
|
||||||
|
{file = "zopfli-0.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:890a83502bb5dff27b1e2b829f8b879d9b7c1383d20a68dc13f0de71da4ff604"},
|
||||||
|
{file = "zopfli-0.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ee224ec851b4b53042ff6ad6e81712c8c9aa18396396acb024fe5a65c6bb8f1"},
|
||||||
|
{file = "zopfli-0.2.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a9def54c90edd112f785b07a812005ab374e7d0aaf50ecac900ca0c51adab3e7"},
|
||||||
|
{file = "zopfli-0.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9e123bfb16cf86ef5abda375012a97c7d00d989b3519d785ca298326f671a81b"},
|
||||||
|
{file = "zopfli-0.2.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c5d722b2bfde6dbfbda548e7f6b5b50b57ee06f334b055be24d9bbcdbee60e84"},
|
||||||
|
{file = "zopfli-0.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:29357c34b8de35c05dd04d8706393bfa09b2dd8bb7a331cc5e98e2b8d39d2efd"},
|
||||||
|
{file = "zopfli-0.2.1-cp39-cp39-win32.whl", hash = "sha256:fd917247bb0489c924d74186075cf0a2d7d06b3b1413197f9f6ee8fcbd0263a0"},
|
||||||
|
{file = "zopfli-0.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:2cd55bf9952884f3c0a3a32f95e5ba5fb0e1f371c9b1a99ed41351c1e00f4700"},
|
||||||
|
{file = "zopfli-0.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0f052a07a6fb6b7bf87ed30a099187597eb594a8a573a4426c16a6a852a05d86"},
|
||||||
|
{file = "zopfli-0.2.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c993919cd01ea5c4b0134908bbd59321d9bdbb9085aa30c538fa1289745fe52f"},
|
||||||
|
{file = "zopfli-0.2.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:37071a3dd5ec0c7f27a1f440d6f50ed8171665e7e3b6ae9a6228e6c48d21570c"},
|
||||||
|
{file = "zopfli-0.2.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:c9b9f73d99080ca2d79600683b8be3395d46a386b4e1d351c6ed6dc261d267e9"},
|
||||||
|
{file = "zopfli-0.2.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:195209711463a399f0c252b34042d8027f3b41dcb646fc112551cfaef507eab4"},
|
||||||
|
{file = "zopfli-0.2.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8bc92b4008854afa465d647be5ae51b01788ec47cfd10a362dcc865ff898c473"},
|
||||||
|
{file = "zopfli-0.2.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:aa18771d1d76c09d2ec2c859b6c55fdad29d2511549b4225437194aca102ad3c"},
|
||||||
|
{file = "zopfli-0.2.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:aa11904718fd27b2ccadf0ac88c1ca0b96ba67ad0c3c2bd584f85de060d04534"},
|
||||||
|
{file = "zopfli-0.2.1.zip", hash = "sha256:e5263d2806e2c1ccb23f52b2972a235d31d42f22f3fa3032cc9aded51e9bf2c6"},
|
||||||
|
]
|
|
@ -0,0 +1,25 @@
|
||||||
|
[tool.poetry]
|
||||||
|
name = "wiki-postbot"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add posts to the wiki!"
|
||||||
|
authors = ["sneakers-the-rat <JLSaunders987@gmail.com>"]
|
||||||
|
license = "GPL-3.0"
|
||||||
|
packages = [
|
||||||
|
{ include="wiki_postbot" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.poetry.scripts]
|
||||||
|
wikipostbot = "wiki_postbot.main:main"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.9"
|
||||||
|
tweepy = "^4.10.0"
|
||||||
|
rich = "^12.4.4"
|
||||||
|
parse = "^1.19.0"
|
||||||
|
|
||||||
|
[tool.poetry.dev-dependencies]
|
||||||
|
pytest = "^7.1.2"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core>=1.0.0"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
|
@ -0,0 +1,29 @@
|
||||||
|
from wiki_postbot.bot import WikiPostBot
|
||||||
|
from wiki_postbot.actions import commands
|
||||||
|
import pytest
|
||||||
|
from tweepy import Tweet, StreamResponse
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
['test_str', 'test_res'],
|
||||||
|
[
|
||||||
|
(
|
||||||
|
'@threadodo_bot identify\nname: Myname T. Identifier\norcid: 101001010101010',
|
||||||
|
{'username': 'threadodo_bot', 'command': 'identify',
|
||||||
|
'args': {
|
||||||
|
'name': 'Myname T. Identifier',
|
||||||
|
'orcid': '101001010101010'
|
||||||
|
}}
|
||||||
|
)
|
||||||
|
] )
|
||||||
|
|
||||||
|
def test_parse_identity(test_str, test_res):
|
||||||
|
bot = WikiPostBot()
|
||||||
|
response = StreamResponse(Tweet({'text':test_str, 'id':'1095'}), {}, {}, {})
|
||||||
|
id = commands.Identify(bot)
|
||||||
|
|
||||||
|
assert id.check(response)
|
||||||
|
|
||||||
|
params = id.parse(response)
|
||||||
|
|
||||||
|
assert params.__dict__ == test_res
|
|
@ -0,0 +1 @@
|
||||||
|
from wiki_postbot.bot import WikiPostBot
|
|
@ -0,0 +1,2 @@
|
||||||
|
from wiki_postbot.actions.action import Action
|
||||||
|
from wiki_postbot.actions.checks import Mentioned
|
|
@ -0,0 +1,61 @@
|
||||||
|
import sys
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
import typing
|
||||||
|
from typing import Optional, Union, Tuple, List, Dict
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from tweepy import Response
|
||||||
|
|
||||||
|
if typing.TYPE_CHECKING:
|
||||||
|
from wiki_postbot.bot import WikiPostBot
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Result:
|
||||||
|
ok:bool
|
||||||
|
"""
|
||||||
|
Whether the action completed successfully
|
||||||
|
"""
|
||||||
|
log: Optional[str] = None
|
||||||
|
"""
|
||||||
|
Message to log
|
||||||
|
"""
|
||||||
|
reply: Optional[str] = None
|
||||||
|
"""
|
||||||
|
Message to reply with
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Action(ABC):
|
||||||
|
|
||||||
|
def __init__(self, bot: 'WikiPostBot'):
|
||||||
|
super(Action, self).__init__()
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
#@abstractmethod
|
||||||
|
def do(self, response:Response) -> Result:
|
||||||
|
"""
|
||||||
|
Encapsulate the other actions and uh do the action!
|
||||||
|
Returns:
|
||||||
|
:
|
||||||
|
"""
|
||||||
|
|
||||||
|
#@abstractmethod
|
||||||
|
def check(self, response:Response) -> bool:
|
||||||
|
"""
|
||||||
|
Check if the condition of this action is met
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
#@abstractmethod
|
||||||
|
def get(self, response:Response) -> typing.Any:
|
||||||
|
"""
|
||||||
|
If this action sets something, get its value.
|
||||||
|
|
||||||
|
Eg. if this action sets a
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
from wiki_postbot.actions.action import Action, Result
|
||||||
|
from wiki_postbot.patterns import WIKILINK
|
||||||
|
from tweepy import Response
|
||||||
|
import re
|
||||||
|
|
||||||
|
class Check(Action):
|
||||||
|
"""
|
||||||
|
Base class for actions that check something about the tagged message
|
||||||
|
to see if we should handle it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class Mentioned(Check):
|
||||||
|
"""
|
||||||
|
Check that we have been directly mentioned in the message
|
||||||
|
"""
|
||||||
|
|
||||||
|
def do(self, response:Response) -> Result:
|
||||||
|
mentioned_users = [u['username'] == self.bot.username for u in response.data.entities.get('mentions', [])]
|
||||||
|
result = Result(ok=any(mentioned_users))
|
||||||
|
if not result.ok:
|
||||||
|
result.log = "Mentioned, but not directly mentioned"
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
class Wikilink(Check):
|
||||||
|
"""
|
||||||
|
Check if a post contains a wikilink
|
||||||
|
"""
|
||||||
|
pattern = WIKILINK
|
||||||
|
"""
|
||||||
|
stolen from the agora bot
|
||||||
|
https://github.com/flancian/agora-bridge/blob/9cfe0a41e55bba4f628875ecf0c8fefd3ad509fd/bots/twitter/agora-bot.py#L48
|
||||||
|
"""
|
||||||
|
|
||||||
|
def do(self, response:Response) -> Result:
|
||||||
|
wikilinks = self.pattern.findall(response.data.text)
|
||||||
|
if len(wikilinks)>0:
|
||||||
|
return Result(ok=True, log=f"Found wikilinks: {wikilinks}")
|
||||||
|
else:
|
||||||
|
return Result(ok=False, log="No wikilinks found")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
import pdb
|
||||||
|
import sys
|
||||||
|
import typing
|
||||||
|
from typing import Optional, Union, Tuple, List, Dict
|
||||||
|
from wiki_postbot.actions.action import Action, Result
|
||||||
|
from wiki_postbot.logger import init_logger
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import re
|
||||||
|
|
||||||
|
from tweepy import Response, StreamResponse
|
||||||
|
import parse
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Command_Params:
|
||||||
|
username: str
|
||||||
|
command: str
|
||||||
|
args: Optional[dict]
|
||||||
|
|
||||||
|
class Command(Action):
|
||||||
|
"""
|
||||||
|
An action invoked by tweeting at the bot and telling it to do something
|
||||||
|
"""
|
||||||
|
name:str
|
||||||
|
command_str = r"@(?P<username>\S{1,})\s*(?P<command>\w*)"
|
||||||
|
arg_str = r"^(\w*?):\s*(.*)"
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Arguments:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(Command, self).__init__(*args, **kwargs)
|
||||||
|
self.logger = init_logger('wiki_postbot.action.command.'+self.name, self.bot.basedir)
|
||||||
|
self.command_pattern = re.compile(self.command_str)
|
||||||
|
self.arg_pattern = re.compile(self.arg_str, re.MULTILINE)
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse(cls, tweet:Union[str, Response]) -> Union[None, Command_Params]:
|
||||||
|
if isinstance(tweet, (Response, StreamResponse)):
|
||||||
|
tweet = tweet.data.text
|
||||||
|
command_pattern = re.compile(cls.command_str)
|
||||||
|
arg_pattern = re.compile(cls.arg_str, re.MULTILINE)
|
||||||
|
|
||||||
|
command_tup = command_pattern.findall(tweet)
|
||||||
|
command_tup = [c for c in command_tup if len(c) == 2 and len(c[0])>0 and len(c[1])>0]
|
||||||
|
|
||||||
|
if len(command_tup) == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
else:
|
||||||
|
param_dict = {'username': command_tup[0][0], 'command': command_tup[0][1]}
|
||||||
|
|
||||||
|
args = arg_pattern.findall(tweet)
|
||||||
|
if args is not None:
|
||||||
|
param_dict['args'] = dict(args)
|
||||||
|
|
||||||
|
return Command_Params(**param_dict)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def check(self, response:Response) -> bool:
|
||||||
|
"""
|
||||||
|
Check if the response has a first line like::
|
||||||
|
|
||||||
|
@{bot.username}: {Command.name}
|
||||||
|
|
||||||
|
|
||||||
|
Args:
|
||||||
|
response:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool
|
||||||
|
"""
|
||||||
|
# like
|
||||||
|
# "{@
|
||||||
|
|
||||||
|
# split into lines
|
||||||
|
lines = str(response.data.text).split('\n')
|
||||||
|
test_str = lines[0].strip()
|
||||||
|
self.logger.debug(f"Testing string: {test_str}")
|
||||||
|
|
||||||
|
command_tup = self.command_pattern.findall(test_str)
|
||||||
|
command_tup = [c for c in command_tup if len(c) == 2 and len(c[0]) > 0 and len(c[1]) > 0]
|
||||||
|
|
||||||
|
if len(command_tup) == 0:
|
||||||
|
parse_res = None
|
||||||
|
|
||||||
|
else:
|
||||||
|
parse_res = {'username': command_tup[0][0], 'command': command_tup[0][1]}
|
||||||
|
|
||||||
|
self.logger.debug(f"parse result: {parse_res}")
|
||||||
|
if parse_res is None:
|
||||||
|
self.logger.debug('parse match was None')
|
||||||
|
return False
|
||||||
|
|
||||||
|
if parse_res['username'] == self.bot.username and \
|
||||||
|
parse_res['command'] == self.name:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get(self, response:Response) -> Union[Command_Params, None]:
|
||||||
|
"""Get the value of a command
|
||||||
|
|
||||||
|
Response must have the 'user_id' expansion
|
||||||
|
"""
|
||||||
|
matched = self.bot.client.search_recent_tweets(
|
||||||
|
f"from:{response.includes['users'][0]['username']} @{self.bot.username} \"{self.name}\"",
|
||||||
|
user_auth=True)
|
||||||
|
self.logger.debug("matched get request")
|
||||||
|
self.logger.debug(matched)
|
||||||
|
if matched.data is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
all_params = [self.parse(d.text) for d in matched.data]
|
||||||
|
found_params = [p for p in all_params if len(p.args)>0]
|
||||||
|
if len(found_params)>0:
|
||||||
|
return found_params[0]
|
||||||
|
else:
|
||||||
|
return all_params[0]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def arg_dict(self, tweet:Union[str, Response]) -> dict:
|
||||||
|
"""
|
||||||
|
Get arguments given to this command
|
||||||
|
"""
|
||||||
|
if isinstance(tweet, Response):
|
||||||
|
tweet = tweet.data.text
|
||||||
|
|
||||||
|
return dict(self.arg_pattern.findall(tweet))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def example(cls) -> str:
|
||||||
|
ex_str = f"@<bot> {cls.name}"
|
||||||
|
keys = [f"{key}:" for key in cls.Arguments.__dataclass_fields__.keys()]
|
||||||
|
ex_str = "\n".join([ex_str, *keys])
|
||||||
|
return ex_str
|
||||||
|
|
||||||
|
|
||||||
|
class Identify(Command):
|
||||||
|
name="identify"
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Arguments:
|
||||||
|
name: str
|
||||||
|
affiliation: Optional[str]
|
||||||
|
orcid: Optional[str]
|
||||||
|
|
||||||
|
def do(self, response:Response) -> Result:
|
||||||
|
params = self.parse(response)
|
||||||
|
if len(params.args) == 0:
|
||||||
|
id = self.get(response)
|
||||||
|
|
||||||
|
if id is None or len(id.args)==0:
|
||||||
|
reply = "No Identity Found! Set one by tweeting:\n"+self.example()
|
||||||
|
log = "Help message given"
|
||||||
|
else:
|
||||||
|
reply = "Previous Identity Found: \n" + "\n".join([f"{key}: {val}" for key, val in id.args.items()])
|
||||||
|
log = "previous identity given"
|
||||||
|
else:
|
||||||
|
reply = "Identity registered! This will be used to identify all threads from your username. If you need to update or remove your identity, delete this tweet, your information is not stored anywhere else."
|
||||||
|
log = f"Identity registered"
|
||||||
|
return Result(ok=True, reply=reply, log=log)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
"""
|
||||||
|
Actions triggered by inline text content
|
||||||
|
"""
|
||||||
|
from typing import List, Optional
|
||||||
|
from wiki_postbot.actions import Action
|
||||||
|
|
||||||
|
class Inline(Action):
|
||||||
|
"""
|
||||||
|
An action triggered by the content of a tweet
|
||||||
|
"""
|
||||||
|
|
||||||
|
class WikiLink(Inline):
|
||||||
|
"""
|
||||||
|
Detect a wikilink and add it to the wiki!
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(WikiLink, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
self.wikilinks = None # type: Optional[List[str]]
|
||||||
|
|
||||||
|
def check(self, response: Response) -> bool:
|
||||||
|
"""
|
||||||
|
Check if the condition of this action is met
|
||||||
|
"""
|
||||||
|
wikilinks = self.pattern.findall(response.data.text)
|
||||||
|
if len(wikilinks)>0:
|
||||||
|
return Result(ok=True, log=f"Found wikilinks: {wikilinks}")
|
||||||
|
else:
|
||||||
|
return Result(ok=False, log="No wikilinks found")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def do(self, response: Response) -> Result:
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
|
||||||
|
# @abstractmethod
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
from pathlib import Path
|
||||||
|
import logging
|
||||||
|
import tweepy
|
||||||
|
import typing
|
||||||
|
import pdb
|
||||||
|
from typing import List, Optional, Type
|
||||||
|
|
||||||
|
from wiki_postbot.creds import Creds, Zenodo_Creds
|
||||||
|
from wiki_postbot.thread import Thread
|
||||||
|
from wiki_postbot.logger import init_logger
|
||||||
|
from wiki_postbot.actions import checks, commands
|
||||||
|
if typing.TYPE_CHECKING:
|
||||||
|
from wiki_postbot.actions import Action
|
||||||
|
|
||||||
|
|
||||||
|
class WikiPostBot(tweepy.StreamingClient):
|
||||||
|
check_classes = [checks.Wikilink] # type: List[Type[checks.Check]]
|
||||||
|
#command_classes = [commands.Identify] # type: List[Type[commands.Command]]
|
||||||
|
command_classes = []
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
creds:Path = Path('twitter_creds.json'),
|
||||||
|
wiki_creds:Path = Path('wiki_creds.json'),
|
||||||
|
username:str='wikibot3k',
|
||||||
|
following:Optional[List[str]]=None,
|
||||||
|
basedir:Path=Path().home()/"wiki_postbot",
|
||||||
|
loglevel="DEBUG",
|
||||||
|
debug:bool = False
|
||||||
|
):
|
||||||
|
|
||||||
|
self._creds = None
|
||||||
|
self._wiki_creds = None
|
||||||
|
self._client = None
|
||||||
|
self.basedir=Path(basedir)
|
||||||
|
|
||||||
|
self.creds_path = Path(creds)
|
||||||
|
self.wiki_creds_path = Path(wiki_creds)
|
||||||
|
self.username = username
|
||||||
|
self.debug = debug
|
||||||
|
self.following = following
|
||||||
|
self.logger = init_logger('wiki_postbot.bot', basedir, loglevel=loglevel)
|
||||||
|
|
||||||
|
super(WikiPostBot, self).__init__(self.creds.bearer_token)
|
||||||
|
|
||||||
|
self.add_rules(self.rule)
|
||||||
|
|
||||||
|
self.checks = [cls(self) for cls in self.check_classes]
|
||||||
|
self.commands = [cls(self) for cls in self.command_classes]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rule(self) -> tweepy.StreamRule:
|
||||||
|
"""
|
||||||
|
StreamRule for accounts we're following or if we're mentioned
|
||||||
|
"""
|
||||||
|
rule = f"@{self.username}"
|
||||||
|
if self.following is not None:
|
||||||
|
following = [f'from:{user}' for user in self.following]
|
||||||
|
rule = ' OR '.join([*following, rule])
|
||||||
|
return tweepy.StreamRule(rule)
|
||||||
|
|
||||||
|
|
||||||
|
def on_response(self, response:tweepy.Response):
|
||||||
|
"""
|
||||||
|
Check if the tweet has a wikilink in it
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.debug:
|
||||||
|
pdb.set_trace()
|
||||||
|
|
||||||
|
self.logger.info(f'Mentioned: {response.data.text}')
|
||||||
|
|
||||||
|
|
||||||
|
# Do checks to see if we should do anything!
|
||||||
|
for check in self.checks:
|
||||||
|
res = check.do(response)
|
||||||
|
if not res.ok:
|
||||||
|
if res.log:
|
||||||
|
self.logger.info(res.log)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Determine what action we should do!
|
||||||
|
for command in self.commands:
|
||||||
|
if command.check(response):
|
||||||
|
self.logger.info(f"Given Command {command.name}")
|
||||||
|
res = command.do(response)
|
||||||
|
if res.log:
|
||||||
|
self.logger.debug(res.log)
|
||||||
|
if res.reply:
|
||||||
|
self.reply(response, res.reply)
|
||||||
|
return
|
||||||
|
|
||||||
|
# TODO: move this to a command class
|
||||||
|
# thread = Thread.from_tweet(self.creds, response)
|
||||||
|
# self.logger.info('thread received')
|
||||||
|
# try:
|
||||||
|
# pdf = thread.to_pdf()
|
||||||
|
# self.logger.info('pdf created')
|
||||||
|
# depo = post_pdf(pdf, thread, self.zenodo_creds)
|
||||||
|
# self.logger.info('posted pdf')
|
||||||
|
# self.logger.debug(depo)
|
||||||
|
#
|
||||||
|
# finally:
|
||||||
|
# pdf.unlink()
|
||||||
|
#
|
||||||
|
# self.reply_completed(response, depo)
|
||||||
|
|
||||||
|
|
||||||
|
def reply_completed(self, response: tweepy.Response, deposit:Deposition):
|
||||||
|
|
||||||
|
self.client.create_tweet(text=f"The preprint of your thread is ready: {deposit.doi_url} - {deposit.title}",
|
||||||
|
in_reply_to_tweet_id=response.data.id)
|
||||||
|
self.logger.info('replied')
|
||||||
|
|
||||||
|
def reply(self, response: tweepy.Response, text:str):
|
||||||
|
self.client.create_tweet(text=text,
|
||||||
|
in_reply_to_tweet_id=response.data.id)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def run(self, threaded:bool=False):
|
||||||
|
self.logger.debug('starting')
|
||||||
|
self.filter(threaded=threaded,
|
||||||
|
tweet_fields=[
|
||||||
|
"in_reply_to_user_id",
|
||||||
|
"author_id",
|
||||||
|
"created_at",
|
||||||
|
"conversation_id",
|
||||||
|
"entities",
|
||||||
|
"referenced_tweets"
|
||||||
|
],
|
||||||
|
expansions=[
|
||||||
|
'author_id'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.logger.debug('stopped')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client(self) -> tweepy.Client:
|
||||||
|
if self._client is None:
|
||||||
|
self._client = tweepy.Client(
|
||||||
|
consumer_key=self.creds.api_key,
|
||||||
|
consumer_secret=self.creds.api_secret,
|
||||||
|
access_token=self.creds.access_token,
|
||||||
|
access_token_secret=self.creds.access_secret)
|
||||||
|
return self._client
|
||||||
|
|
||||||
|
@property
|
||||||
|
def creds(self) -> Creds:
|
||||||
|
if self._creds is None:
|
||||||
|
self._creds = Creds.from_json(self.creds_path)
|
||||||
|
return self._creds
|
||||||
|
|
||||||
|
@property
|
||||||
|
def wiki_creds(self) -> Zenodo_Creds:
|
||||||
|
if self._wiki_creds is None:
|
||||||
|
self._wiki_creds = Zenodo_Creds.from_json(self.wiki_creds_path)
|
||||||
|
return self._wiki_creds
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
"""
|
||||||
|
No, not the actual creds. and dont go lookin for em in the git history cuz they aint in there neither
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
import typing
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Creds:
|
||||||
|
api_key: str
|
||||||
|
api_secret: str
|
||||||
|
bearer_token: str
|
||||||
|
access_token: typing.Optional[str]
|
||||||
|
access_secret: typing.Optional[str]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, path:Path) -> 'Creds':
|
||||||
|
with open(path, 'r') as jfile:
|
||||||
|
creds = json.load(jfile)
|
||||||
|
return Creds(**creds)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Zenodo_Creds:
|
||||||
|
access_token:str
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, path:Path) -> 'Zenodo_Creds':
|
||||||
|
with open(path, 'r') as jfile:
|
||||||
|
creds = json.load(jfile)
|
||||||
|
return Zenodo_Creds(**creds)
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import logging
|
||||||
|
from rich.logging import RichHandler
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
import typing
|
||||||
|
from typing import Optional, Union, Tuple, List, Dict, Literal
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
|
||||||
|
def init_logger(
|
||||||
|
name:Optional[str]=None,
|
||||||
|
basedir:Optional[Path]=None,
|
||||||
|
loglevel:str='DEBUG',
|
||||||
|
loglevel_disk:Optional[str]=None
|
||||||
|
):
|
||||||
|
if name is None:
|
||||||
|
name = 'wiki_postbot'
|
||||||
|
else:
|
||||||
|
if not name.startswith('wiki_postbot'):
|
||||||
|
name = '.'.join(['wiki_postbot', name])
|
||||||
|
|
||||||
|
if loglevel_disk is None:
|
||||||
|
loglevel_disk = loglevel
|
||||||
|
|
||||||
|
logger = logging.getLogger(name)
|
||||||
|
logger.setLevel(loglevel)
|
||||||
|
|
||||||
|
|
||||||
|
if basedir is not None:
|
||||||
|
logger.addHandler(_file_handler(basedir, name, loglevel_disk))
|
||||||
|
|
||||||
|
logger.addHandler(_rich_handler())
|
||||||
|
return logger
|
||||||
|
|
||||||
|
|
||||||
|
def _file_handler(basedir:Path, name:str, loglevel:str="DEBUG") -> RotatingFileHandler:
|
||||||
|
filename = Path(basedir) / '.'.join([name, 'log'])
|
||||||
|
basedir.mkdir(parents=True, exist_ok=True)
|
||||||
|
file_handler = RotatingFileHandler(
|
||||||
|
str(filename),
|
||||||
|
mode='a',
|
||||||
|
maxBytes=2 ** 24,
|
||||||
|
backupCount=5
|
||||||
|
)
|
||||||
|
file_formatter = logging.Formatter("[%(asctime)s] %(levelname)s [%(name)s]: %(message)s")
|
||||||
|
file_handler.setLevel(loglevel)
|
||||||
|
file_handler.setFormatter(file_formatter)
|
||||||
|
return file_handler
|
||||||
|
|
||||||
|
def _rich_handler() -> RichHandler:
|
||||||
|
rich_handler = RichHandler(rich_tracebacks=True, markup=True)
|
||||||
|
rich_formatter = logging.Formatter(
|
||||||
|
"[bold green]\[%(name)s][/bold green] %(message)s",
|
||||||
|
datefmt='[%y-%m-%dT%H:%M:%S]'
|
||||||
|
)
|
||||||
|
rich_handler.setFormatter(rich_formatter)
|
||||||
|
return rich_handler
|
|
@ -0,0 +1,26 @@
|
||||||
|
import argparse
|
||||||
|
from wiki_postbot.bot import WikiPostBot
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(description="Run a wiki_postbot bot!")
|
||||||
|
parser.add_argument('--creds', type=Path, help="Location of twitter credentials .json file",
|
||||||
|
default=Path('twitter_creds.json'))
|
||||||
|
parser.add_argument('--wiki_creds', type=Path, help="Path to wiki credentials .json file",
|
||||||
|
default=Path('wiki_creds.json'))
|
||||||
|
parser.add_argument('-u', '--username', type=str, help="Username of our bot",
|
||||||
|
default="wikibot3k")
|
||||||
|
parser.add_argument('-b', '--basedir', help="Base directory to store files",
|
||||||
|
type=Path, default=Path().home() / "wiki_postbot")
|
||||||
|
parser.add_argument('-l', '--loglevel', type=str, help="Loglevel for wiki_postbot bot, DEBUG, INFO, WARNING, or ERROR",
|
||||||
|
default='DEBUG')
|
||||||
|
parser.add_argument('-d', '--debug', action='store_true', help="Debug responses from bot")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parse_args()
|
||||||
|
tt = WikiPostBot(**args.__dict__)
|
||||||
|
tt.run()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -0,0 +1,6 @@
|
||||||
|
"""
|
||||||
|
Regex patterns
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
|
||||||
|
WIKILINK = re.compile(r'\[\[(.*?)\]\]', re.IGNORECASE)
|
|
@ -0,0 +1,372 @@
|
||||||
|
|
||||||
|
/*stolen from https://github.com/CourtBouillon/weasyprint-samples/blob/master/report/report.css*/
|
||||||
|
|
||||||
|
@page {
|
||||||
|
@top-left {
|
||||||
|
background: #fbc847;
|
||||||
|
content: counter(page);
|
||||||
|
height: 1cm;
|
||||||
|
text-align: center;
|
||||||
|
width: 1cm;
|
||||||
|
}
|
||||||
|
@top-center {
|
||||||
|
background: #fbc847;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
height: .05cm;
|
||||||
|
opacity: .5;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
@top-right {
|
||||||
|
content: string(heading);
|
||||||
|
font-size: 9pt;
|
||||||
|
height: 1cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@page :blank {
|
||||||
|
@top-left { background: none; content: '' }
|
||||||
|
@top-center { content: none }
|
||||||
|
@top-right { content: none }
|
||||||
|
}
|
||||||
|
@page no-chapter {
|
||||||
|
@top-left { background: none; content: none }
|
||||||
|
@top-center { content: none }
|
||||||
|
@top-right { content: none }
|
||||||
|
}
|
||||||
|
@page :first {
|
||||||
|
background: url(report-cover.jpg) no-repeat center;
|
||||||
|
background-size: cover;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
@page chapter {
|
||||||
|
background: #fbc847;
|
||||||
|
margin: 0;
|
||||||
|
@top-left { content: none }
|
||||||
|
@top-center { content: none }
|
||||||
|
@top-right { content: none }
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
color: #393939;
|
||||||
|
font-family: Fira Sans;
|
||||||
|
font-size: 11pt;
|
||||||
|
font-weight: 300;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #fbc847;
|
||||||
|
font-size: 38pt;
|
||||||
|
margin: 5cm 2cm 0 2cm;
|
||||||
|
page: no-chapter;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
h2, h3, h4 {
|
||||||
|
color: black;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 28pt;
|
||||||
|
string-set: heading content();
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 15pt;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
font-size: 13pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cover {
|
||||||
|
align-content: space-between;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: 297mm;
|
||||||
|
}
|
||||||
|
#cover address {
|
||||||
|
background: #fbc847;
|
||||||
|
flex: 1 50%;
|
||||||
|
margin: 0 -2cm;
|
||||||
|
padding: 1cm 0;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
#cover address:first-of-type {
|
||||||
|
padding-left: 3cm;
|
||||||
|
}
|
||||||
|
#contents {
|
||||||
|
break-before: right;
|
||||||
|
break-after: left;
|
||||||
|
page: no-chapter;
|
||||||
|
}
|
||||||
|
#contents h2 {
|
||||||
|
font-size: 20pt;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-bottom: 3cm;
|
||||||
|
}
|
||||||
|
#contents h3 {
|
||||||
|
font-weight: 500;
|
||||||
|
margin: 3em 0 1em;
|
||||||
|
}
|
||||||
|
#contents h3::before {
|
||||||
|
background: #fbc847;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
height: .08cm;
|
||||||
|
margin-bottom: .25cm;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#contents ul {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
#contents ul li {
|
||||||
|
border-top: .25pt solid #c1c1c1;
|
||||||
|
margin: .25cm 0;
|
||||||
|
padding-top: .25cm;
|
||||||
|
}
|
||||||
|
#contents ul li::before {
|
||||||
|
color: #fbc847;
|
||||||
|
content: '• ';
|
||||||
|
font-size: 40pt;
|
||||||
|
line-height: 16pt;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
#contents ul li a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration-line: inherit;
|
||||||
|
}
|
||||||
|
#contents ul li a::before {
|
||||||
|
content: target-text(attr(href));
|
||||||
|
}
|
||||||
|
#contents ul li a::after {
|
||||||
|
color: #fbc847;
|
||||||
|
content: target-counter(attr(href), page);
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#columns section {
|
||||||
|
columns: 2;
|
||||||
|
column-gap: 1cm;
|
||||||
|
padding-top: 1cm;
|
||||||
|
}
|
||||||
|
#columns section p {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
#columns section p:first-of-type {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
#skills h3 {
|
||||||
|
background: #fbc847;
|
||||||
|
margin: 0 -3cm 1cm;
|
||||||
|
padding: 1cm 1cm 1cm 3cm;
|
||||||
|
width: 21cm;
|
||||||
|
}
|
||||||
|
#skills section {
|
||||||
|
padding: .5cm 0;
|
||||||
|
}
|
||||||
|
#skills section#table-content::before {
|
||||||
|
background: url(table-content.svg) no-repeat center #fbc847;
|
||||||
|
background-size: 50%;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
height: 2cm;
|
||||||
|
margin-right: .5cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#skills section#heading::before {
|
||||||
|
background: url(heading.svg) no-repeat center #fbc847;
|
||||||
|
background-size: 50%;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
height: 2cm;
|
||||||
|
margin-right: .5cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#skills section#multi-columns::before {
|
||||||
|
background: url(multi-columns.svg) no-repeat center #fbc847;
|
||||||
|
background-size: 50%;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
height: 2cm;
|
||||||
|
margin-right: .5cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#skills section#internal-links::before {
|
||||||
|
background: url(internal-links.svg) no-repeat center #fbc847;
|
||||||
|
background-size: 50%;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
height: 2cm;
|
||||||
|
margin-right: .5cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#skills section#style::before {
|
||||||
|
background: url(style.svg) no-repeat center #fbc847;
|
||||||
|
background-size: 50%;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
height: 2cm;
|
||||||
|
margin-right: .5cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#skills section h4 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#skills section p {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#offers {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
#offers h2, #offers h3 {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#offers section {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
#offers section h4 {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
#offers section ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
#offers section ul li:not(:last-of-type) {
|
||||||
|
margin: .5cm 0;
|
||||||
|
}
|
||||||
|
#offers section p {
|
||||||
|
background: #fbc847;
|
||||||
|
display: block;
|
||||||
|
font-size: 15pt;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: .25cm 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#chapter {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 297mm;
|
||||||
|
justify-content: center;
|
||||||
|
page: chapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
#typography section {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 1cm 0;
|
||||||
|
}
|
||||||
|
#typography section h4 {
|
||||||
|
border-top: 1pt solid;
|
||||||
|
flex: 1 25%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#typography section h4 + * {
|
||||||
|
flex: 1 75%;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: .5cm;
|
||||||
|
}
|
||||||
|
#typography section p {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
#typography section ul {
|
||||||
|
line-height: 2;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
#typography section#small-caps p {
|
||||||
|
font-variant: small-caps;
|
||||||
|
}
|
||||||
|
#typography section#ligatures dl {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
#typography section#ligatures dl dt {
|
||||||
|
font-weight: 400;
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
#typography section#ligatures dl dd {
|
||||||
|
flex: 1 70%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#typography section#ligatures .none {
|
||||||
|
font-variant-ligatures: none;
|
||||||
|
}
|
||||||
|
#typography section#ligatures .common {
|
||||||
|
font-variant-ligatures: common-ligatures;
|
||||||
|
}
|
||||||
|
#typography section#ligatures .discretionary {
|
||||||
|
font-variant-ligatures: discretionary-ligatures;
|
||||||
|
}
|
||||||
|
#typography section#ligatures .contextual {
|
||||||
|
font-variant-ligatures: contextual;
|
||||||
|
}
|
||||||
|
#typography section#numbers dl {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
#typography section#numbers dl dt {
|
||||||
|
font-weight: 400;
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
#typography section#numbers dl dd {
|
||||||
|
flex: 1 70%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#typography section#numbers #fractions {
|
||||||
|
font-variant-numeric: diagonal-fractions;
|
||||||
|
}
|
||||||
|
#typography section#numbers #ordinals {
|
||||||
|
font-variant-numeric: ordinal;
|
||||||
|
}
|
||||||
|
#typography section#numbers #slashed {
|
||||||
|
font-variant-numeric: slashed-zero;
|
||||||
|
}
|
||||||
|
#typography section#numbers #super {
|
||||||
|
font-variant-position: super;
|
||||||
|
}
|
||||||
|
#typography section#numbers #sub {
|
||||||
|
font-variant-position: sub;
|
||||||
|
}
|
||||||
|
#typography section#figures dl {
|
||||||
|
columns: 4;
|
||||||
|
}
|
||||||
|
#typography section#figures dl dt {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
#typography section#figures dl dd {
|
||||||
|
display: flex;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#typography section#figures dl dd ul {
|
||||||
|
padding: 0 1em 0 0;
|
||||||
|
}
|
||||||
|
#typography section#figures #oldstyle {
|
||||||
|
font-variant-numeric: oldstyle-nums;
|
||||||
|
}
|
||||||
|
#typography section#figures #tabular {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
#typography section#figures #old-tabular {
|
||||||
|
font-variant-numeric: oldstyle-nums tabular-nums;
|
||||||
|
}
|
|
@ -0,0 +1,390 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title></title>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
/*stolen from https://github.com/CourtBouillon/weasyprint-samples/blob/master/report/report.css*/
|
||||||
|
|
||||||
|
@page {
|
||||||
|
@top-left {
|
||||||
|
background: #fbc847;
|
||||||
|
content: counter(page);
|
||||||
|
height: 1cm;
|
||||||
|
text-align: center;
|
||||||
|
width: 1cm;
|
||||||
|
}
|
||||||
|
@top-center {
|
||||||
|
background: #fbc847;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
height: .05cm;
|
||||||
|
opacity: .5;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
@top-right {
|
||||||
|
content: string(heading);
|
||||||
|
font-size: 9pt;
|
||||||
|
height: 1cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@page :blank {
|
||||||
|
@top-left { background: none; content: '' }
|
||||||
|
@top-center { content: none }
|
||||||
|
@top-right { content: none }
|
||||||
|
}
|
||||||
|
@page no-chapter {
|
||||||
|
@top-left { background: none; content: none }
|
||||||
|
@top-center { content: none }
|
||||||
|
@top-right { content: none }
|
||||||
|
}
|
||||||
|
@page chapter {
|
||||||
|
background: #fbc847;
|
||||||
|
margin: 0;
|
||||||
|
@top-left { content: none }
|
||||||
|
@top-center { content: none }
|
||||||
|
@top-right { content: none }
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
color: #393939;
|
||||||
|
font-family: Fira Sans;
|
||||||
|
font-size: 11pt;
|
||||||
|
font-weight: 300;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*h1 {*/
|
||||||
|
/* color: #fbc847;*/
|
||||||
|
/* font-size: 38pt;*/
|
||||||
|
/* margin: 5cm 2cm 0 2cm;*/
|
||||||
|
/* page: no-chapter;*/
|
||||||
|
/* width: 100%;*/
|
||||||
|
/*}*/
|
||||||
|
h1, h2, h3, h4 {
|
||||||
|
color: black;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 36pt;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 28pt;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 15pt;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
font-size: 13pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cover {
|
||||||
|
align-content: space-between;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: 297mm;
|
||||||
|
}
|
||||||
|
#cover address {
|
||||||
|
background: #fbc847;
|
||||||
|
flex: 1 50%;
|
||||||
|
margin: 0 -2cm;
|
||||||
|
padding: 1cm 0;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
#cover address:first-of-type {
|
||||||
|
padding-left: 3cm;
|
||||||
|
}
|
||||||
|
#contents {
|
||||||
|
break-before: right;
|
||||||
|
break-after: left;
|
||||||
|
page: no-chapter;
|
||||||
|
}
|
||||||
|
#contents h2 {
|
||||||
|
font-size: 20pt;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-bottom: 3cm;
|
||||||
|
}
|
||||||
|
#contents h3 {
|
||||||
|
font-weight: 500;
|
||||||
|
margin: 3em 0 1em;
|
||||||
|
}
|
||||||
|
#contents h3::before {
|
||||||
|
background: #fbc847;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
height: .08cm;
|
||||||
|
margin-bottom: .25cm;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#contents ul {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
#contents ul li {
|
||||||
|
border-top: .25pt solid #c1c1c1;
|
||||||
|
margin: .25cm 0;
|
||||||
|
padding-top: .25cm;
|
||||||
|
}
|
||||||
|
#contents ul li::before {
|
||||||
|
color: #fbc847;
|
||||||
|
content: '• ';
|
||||||
|
font-size: 40pt;
|
||||||
|
line-height: 16pt;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
#contents ul li a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration-line: inherit;
|
||||||
|
}
|
||||||
|
#contents ul li a::before {
|
||||||
|
content: target-text(attr(href));
|
||||||
|
}
|
||||||
|
#contents ul li a::after {
|
||||||
|
color: #fbc847;
|
||||||
|
content: target-counter(attr(href), page);
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#columns section {
|
||||||
|
columns: 2;
|
||||||
|
column-gap: 1cm;
|
||||||
|
padding-top: 1cm;
|
||||||
|
}
|
||||||
|
#columns section p {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
#columns section p:first-of-type {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
#skills h3 {
|
||||||
|
background: #fbc847;
|
||||||
|
margin: 0 -3cm 1cm;
|
||||||
|
padding: 1cm 1cm 1cm 3cm;
|
||||||
|
width: 21cm;
|
||||||
|
}
|
||||||
|
#skills section {
|
||||||
|
padding: .5cm 0;
|
||||||
|
}
|
||||||
|
#skills section#table-content::before {
|
||||||
|
background: url(table-content.svg) no-repeat center #fbc847;
|
||||||
|
background-size: 50%;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
height: 2cm;
|
||||||
|
margin-right: .5cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#skills section#heading::before {
|
||||||
|
background: url(heading.svg) no-repeat center #fbc847;
|
||||||
|
background-size: 50%;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
height: 2cm;
|
||||||
|
margin-right: .5cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#skills section#multi-columns::before {
|
||||||
|
background: url(multi-columns.svg) no-repeat center #fbc847;
|
||||||
|
background-size: 50%;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
height: 2cm;
|
||||||
|
margin-right: .5cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#skills section#internal-links::before {
|
||||||
|
background: url(internal-links.svg) no-repeat center #fbc847;
|
||||||
|
background-size: 50%;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
height: 2cm;
|
||||||
|
margin-right: .5cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#skills section#style::before {
|
||||||
|
background: url(style.svg) no-repeat center #fbc847;
|
||||||
|
background-size: 50%;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
height: 2cm;
|
||||||
|
margin-right: .5cm;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 2cm;
|
||||||
|
}
|
||||||
|
#skills section h4 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#skills section p {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#offers {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
#offers h2, #offers h3 {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#offers section {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
#offers section h4 {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
#offers section ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
#offers section ul li:not(:last-of-type) {
|
||||||
|
margin: .5cm 0;
|
||||||
|
}
|
||||||
|
#offers section p {
|
||||||
|
background: #fbc847;
|
||||||
|
display: block;
|
||||||
|
font-size: 15pt;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: .25cm 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#chapter {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 297mm;
|
||||||
|
justify-content: center;
|
||||||
|
page: chapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
#typography section {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 1cm 0;
|
||||||
|
}
|
||||||
|
#typography section h4 {
|
||||||
|
border-top: 1pt solid;
|
||||||
|
flex: 1 25%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#typography section h4 + * {
|
||||||
|
flex: 1 75%;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: .5cm;
|
||||||
|
}
|
||||||
|
#typography section p {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
#typography section ul {
|
||||||
|
line-height: 2;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
#typography section#small-caps p {
|
||||||
|
font-variant: small-caps;
|
||||||
|
}
|
||||||
|
#typography section#ligatures dl {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
#typography section#ligatures dl dt {
|
||||||
|
font-weight: 400;
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
#typography section#ligatures dl dd {
|
||||||
|
flex: 1 70%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#typography section#ligatures .none {
|
||||||
|
font-variant-ligatures: none;
|
||||||
|
}
|
||||||
|
#typography section#ligatures .common {
|
||||||
|
font-variant-ligatures: common-ligatures;
|
||||||
|
}
|
||||||
|
#typography section#ligatures .discretionary {
|
||||||
|
font-variant-ligatures: discretionary-ligatures;
|
||||||
|
}
|
||||||
|
#typography section#ligatures .contextual {
|
||||||
|
font-variant-ligatures: contextual;
|
||||||
|
}
|
||||||
|
#typography section#numbers dl {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
#typography section#numbers dl dt {
|
||||||
|
font-weight: 400;
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
#typography section#numbers dl dd {
|
||||||
|
flex: 1 70%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#typography section#numbers #fractions {
|
||||||
|
font-variant-numeric: diagonal-fractions;
|
||||||
|
}
|
||||||
|
#typography section#numbers #ordinals {
|
||||||
|
font-variant-numeric: ordinal;
|
||||||
|
}
|
||||||
|
#typography section#numbers #slashed {
|
||||||
|
font-variant-numeric: slashed-zero;
|
||||||
|
}
|
||||||
|
#typography section#numbers #super {
|
||||||
|
font-variant-position: super;
|
||||||
|
}
|
||||||
|
#typography section#numbers #sub {
|
||||||
|
font-variant-position: sub;
|
||||||
|
}
|
||||||
|
#typography section#figures dl {
|
||||||
|
columns: 4;
|
||||||
|
}
|
||||||
|
#typography section#figures dl dt {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
#typography section#figures dl dd {
|
||||||
|
display: flex;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#typography section#figures dl dd ul {
|
||||||
|
padding: 0 1em 0 0;
|
||||||
|
}
|
||||||
|
#typography section#figures #oldstyle {
|
||||||
|
font-variant-numeric: oldstyle-nums;
|
||||||
|
}
|
||||||
|
#typography section#figures #tabular {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
#typography section#figures #old-tabular {
|
||||||
|
font-variant-numeric: oldstyle-nums tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<meta name="description" content="Report example">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<article id="columns">
|
||||||
|
|
||||||
|
$body$
|
||||||
|
|
||||||
|
</article>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,103 @@
|
||||||
|
from wiki_postbot.creds import Creds
|
||||||
|
import tweepy
|
||||||
|
import typing
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
import pypandoc
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Author:
|
||||||
|
username: str
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
class Thread:
|
||||||
|
def __init__(self,
|
||||||
|
tweets: typing.List[tweepy.tweet.Tweet],
|
||||||
|
responses: typing.List[tweepy.Response]
|
||||||
|
):
|
||||||
|
self.tweets = tweets
|
||||||
|
self.responses = responses
|
||||||
|
self.pdf = None
|
||||||
|
self.sort()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self) -> str:
|
||||||
|
"""
|
||||||
|
Text from all the tweets in a thread, double new lines between each
|
||||||
|
|
||||||
|
also replacing any @'s with markdown links to profiles i guess
|
||||||
|
"""
|
||||||
|
text = "\n\n".join([t.text for t in self.tweets])
|
||||||
|
# make @'s links
|
||||||
|
text = re.sub(r"@([\w\d_]{1,})", r"[@\1](https://twitter.com/\1)", text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
@property
|
||||||
|
def author(self) -> Author:
|
||||||
|
return Author(
|
||||||
|
"@" + self.responses[0].includes['users'][0].username,
|
||||||
|
self.responses[0].includes['users'][0].name,
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def title(self) -> str:
|
||||||
|
return f"{self.author.name}'s thread - {self.tweets[0].created_at.strftime('%y-%m-%d %H:%M')}"
|
||||||
|
|
||||||
|
def sort(self):
|
||||||
|
"""
|
||||||
|
sort order of tweets
|
||||||
|
"""
|
||||||
|
self.tweets = sorted(self.tweets, key=lambda x: x.created_at)
|
||||||
|
self.responses = sorted(self.responses, key=lambda x: x.data.created_at)
|
||||||
|
|
||||||
|
|
||||||
|
def to_pdf(self, output_file:typing.Optional[Path]=None,
|
||||||
|
) -> Path:
|
||||||
|
if output_file is None:
|
||||||
|
output_file = Path('.') / f"{self.tweets[0].author_id}_{self.tweets[0].created_at.isoformat()}.pdf"
|
||||||
|
|
||||||
|
pypandoc.convert_text(
|
||||||
|
self.text, to="html", format="md",
|
||||||
|
outputfile=str(output_file),
|
||||||
|
extra_args = [
|
||||||
|
'--pdf-engine=weasyprint',
|
||||||
|
f'--data-dir={Path(__file__).parent}',
|
||||||
|
'--template=./template.html',
|
||||||
|
])
|
||||||
|
self.pdf = output_file
|
||||||
|
return output_file
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_tweet(cls,
|
||||||
|
creds:Creds,
|
||||||
|
response:tweepy.Response,
|
||||||
|
limit:int=100) -> 'Thread':
|
||||||
|
"""
|
||||||
|
Starting with the mentioned tweet, get all of the tweets in a thread in order
|
||||||
|
"""
|
||||||
|
tweet = response.data
|
||||||
|
client = tweepy.Client(creds.bearer_token)
|
||||||
|
tweets = [tweet]
|
||||||
|
responses = [response]
|
||||||
|
while tweet.referenced_tweets is not None and len(tweet.referenced_tweets)>0 and len(tweets)<=limit:
|
||||||
|
replied = [t.id for t in tweet.referenced_tweets if t.type=="replied_to"]
|
||||||
|
if len(replied)==0:
|
||||||
|
# top tweet was qt
|
||||||
|
break
|
||||||
|
replied = replied[0]
|
||||||
|
response = client.get_tweet(id=replied, tweet_fields=[
|
||||||
|
"referenced_tweets",
|
||||||
|
"author_id",
|
||||||
|
"created_at"
|
||||||
|
], expansions=[
|
||||||
|
'author_id'
|
||||||
|
])
|
||||||
|
tweet = response.data
|
||||||
|
tweets.append(tweet)
|
||||||
|
responses.append(response)
|
||||||
|
|
||||||
|
return Thread(tweets, responses)
|
Loading…
Reference in New Issue