Fix markdown cropping (#128)

* fixed error log

* changed telegram publisher to use HTML format

* fixed dataclass update issue

* docker: Add python-telegram-bot.

* docker: mobilizon-reshare: Reenable non deterministic tests.

Co-authored-by: Giacomo Leidi <goodoldpaul@autistici.org>
This commit is contained in:
Simone Robutti 2022-01-18 01:39:00 +01:00 committed by GitHub
parent 434438fd20
commit 5804b55dd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 341 additions and 86 deletions

View File

@ -12,8 +12,10 @@
#:use-module (gnu packages openstack)
#:use-module (gnu packages python-build)
#:use-module (gnu packages python-check)
#:use-module (gnu packages python-crypto)
#:use-module (gnu packages python-web)
#:use-module (gnu packages python-xyz)
#:use-module (gnu packages qt)
#:use-module (gnu packages time)
#:use-module (ice-9 popen)
#:use-module (ice-9 rdelim)
@ -203,6 +205,130 @@ Facebook authentication.")
"This package provides a database migrations tool for Tortoise ORM.")
(license #f)))
(define-public python-pytest-tornado5
(package
(name "python-pytest-tornado5")
(version "2.0.0")
(source
(origin
(method url-fetch)
(uri (pypi-uri "pytest-tornado5" version))
(sha256
(base32 "0qb62jw2w0xr6y942yp0qxiy755bismjfpnxaxjjm05gy2pymr8d"))))
(build-system python-build-system)
(propagated-inputs (list python-pytest python-tornado))
(home-page "https://github.com/vidartf/pytest-tornado")
(synopsis
"Fixtures and markers to simplify testing of Tornado applications")
(description
"This package provides a @code{py.test} plugin providing fixtures and markers to
simplify testing of asynchronous tornado applications.")
(license license:asl2.0)))
(define-public python-rethinkdb
(package
(name "python-rethinkdb")
(version "2.4.8")
(source
(origin
(method url-fetch)
(uri (pypi-uri "rethinkdb" version))
(sha256
(base32 "1vmap0la5j8xpigyp5bqph9cb6dskyw76y37n3vb16l9rlmsfxcz"))))
(build-system python-build-system)
(arguments
`(#:tests? #f))
(propagated-inputs (list python-six))
(home-page "https://github.com/RethinkDB/rethinkdb-python")
(synopsis "Python driver library for the RethinkDB database server.")
(description "Python driver library for the RethinkDB database server.")
(license #f)))
(define-public python-apscheduler
(package
(name "python-apscheduler")
(version "3.8.1")
(source
(origin
(method url-fetch)
(uri (pypi-uri "APScheduler" version))
(sha256
(base32 "0m93bz9qpw6iwhay68bwljjcfyzcbh2rq0lc2yp4iamxrzml9wsw"))))
(build-system python-build-system)
(arguments
`(#:phases
(modify-phases %standard-phases
(replace 'check
(lambda* (#:key tests? #:allow-other-keys)
(when tests?
;; FIXME: Currently python-kazoo fails to build.
(delete-file "tests/test_jobstores.py")
(invoke "pytest")))))))
(propagated-inputs
(list python-pytz
python-setuptools
python-six
python-tzlocal))
(native-inputs
(list python-mock
python-pyqt
python-twisted
python-gevent
python-setuptools-scm
python-sqlalchemy
python-redis
python-pymongo
python-rethinkdb
python-pytest
python-pytest-asyncio
python-pytest-cov
python-pytest-tornado5))
(home-page "https://github.com/agronholm/apscheduler")
(synopsis "In-process task scheduler with Cron-like capabilities")
(description "In-process task scheduler with Cron-like capabilities")
(license license:expat)))
(define-public python-apscheduler-3.6.3
(package (inherit python-apscheduler)
(version "3.6.3")
(source
(origin
(method url-fetch)
(uri (pypi-uri "APScheduler" version))
(sha256
(base32 "0i72qpqgrgq6bb9vwsac46m7bqb6mq92g5nf2gydmfvgxng25d9v"))))))
(define-public python-telegram-bot
(package
(name "python-telegram-bot")
(version "13.10")
(source
(origin
(method url-fetch)
(uri (pypi-uri "python-telegram-bot" version))
(sha256
(base32 "0ghyq044s0zi67hxwxdjjfvh37wr86pi5kmpq7harx11311mbifj"))))
(build-system python-build-system)
(arguments
;; FIXME: Most tests require network access. Some of them can
;; be run from the git repository but many still fail due
;; to vendoring of a seemingly heavily patched urllib3.
`(#:tests? #f))
(native-inputs
(list python-beautifulsoup4
python-pytest
python-flaky))
(propagated-inputs
(list python-apscheduler-3.6.3
python-cachetools
python-certifi
python-pytz
python-tornado-6))
(home-page "https://python-telegram-bot.org/")
(synopsis "We have made you a wrapper you can't refuse")
(description "We have made you a wrapper you can't refuse")
(license #f)))
(define-public mobilizon-reshare.git
(let ((source-version (with-input-from-file
(string-append %source-dir
@ -236,9 +362,8 @@ Facebook authentication.")
(when tests?
(invoke "python" "-m" "pytest"
;; This test fails because of the unvendoring
;; of toml from dynaconf and
;; because they depend on system timezone.
"-k" "not test_get_settings_failure_invalid_toml and not test_format_event"))))
;; of toml from dynaconf.
"-k" "not test_get_settings_failure_invalid_toml"))))
(add-before 'sanity-check 'set-dummy-config
(lambda _
;; This is needed to prevent the tool from
@ -268,6 +393,7 @@ Facebook authentication.")
python-jinja2
python-markdownify
python-requests
python-telegram-bot
python-tweepy
python-tortoise-orm))
(home-page

View File

@ -11,7 +11,7 @@ from jinja2 import Environment, FileSystemLoader, Template
from mobilizon_reshare.config.config import get_settings
from mobilizon_reshare.event.event import MobilizonEvent
from mobilizon_reshare.models.publication import Publication as PublicationModel
from .exceptions import PublisherError, InvalidAttribute
from .exceptions import InvalidAttribute
JINJA_ENV = Environment(loader=FileSystemLoader("/"))
@ -34,7 +34,7 @@ class LoggerMixin:
def _log_critical(self, msg, *args, **kwargs):
self.__log(logging.CRITICAL, msg, *args, **kwargs)
def __log(self, level, msg, raise_error: PublisherError = None, *args, **kwargs):
def __log(self, level, msg, raise_error: type = None, *args, **kwargs):
method = inspect.currentframe().f_back.f_back.f_code.co_name
logger.log(level, f"{self}.{method}(): {msg}", *args, **kwargs)
if raise_error is not None:
@ -91,13 +91,9 @@ class AbstractPlatform(ABC, LoggerMixin, ConfLoaderMixin):
"""
Sends a message to the target channel
"""
message = self._preprocess_message(message)
response = self._send(message, event)
self._validate_response(response)
def _preprocess_message(self, message: str):
return message
@abstractmethod
def _validate_response(self, response):
raise NotImplementedError # pragma: no cover
@ -146,7 +142,9 @@ class AbstractEventFormatter(LoggerMixin, ConfLoaderMixin):
Retrieves a message from the event itself.
"""
event = self._preprocess_event(event)
return event.format(self.get_message_template())
message = event.format(self.get_message_template())
message = self._preprocess_message(message)
return message
def get_message_template(self) -> Template:
"""
@ -175,6 +173,9 @@ class AbstractEventFormatter(LoggerMixin, ConfLoaderMixin):
event = self._preprocess_event(event)
return event.format(self.get_recap_fragment_template())
def _preprocess_message(self, message: str):
return message
@dataclass
class BasePublication:

View File

@ -1,12 +1,11 @@
import re
from typing import Optional
import pkg_resources
import requests
from bs4 import BeautifulSoup
from requests import Response
from mobilizon_reshare.event.event import MobilizonEvent
from mobilizon_reshare.formatting.description import html_to_markdown
from mobilizon_reshare.publishers.abstract import (
AbstractEventFormatter,
AbstractPlatform,
@ -33,42 +32,6 @@ class TelegramFormatter(AbstractEventFormatter):
)
_conf = ("publisher", "telegram")
_escape_characters = [
"-",
".",
"(",
"!",
")",
">",
"<",
">",
"{",
"}",
]
@staticmethod
def restore_links(message: str) -> str:
"""The escape_message function should ignore actually valid links that involve square brackets and parenthesis.
This function de-escapes actual links without altering other escaped square brackets and parenthesis"""
def build_link(match):
result = match.group(0)
for character in TelegramFormatter._escape_characters:
result = result.replace("\\" + character, character)
return result
return re.sub(r"\[(\w*)]\\\(([\w\-/\\.:]*)\\\)", build_link, message,)
@staticmethod
def escape_message(message: str) -> str:
"""Escape message to comply with Telegram standards"""
for character in TelegramFormatter._escape_characters:
message = message.replace(character, "\\" + character)
# Telegram doesn't use headers so # can be removed
message = message.replace("#", r"")
return TelegramFormatter.restore_links(message)
def _validate_event(self, event: MobilizonEvent) -> None:
description = event.description
@ -76,13 +39,38 @@ class TelegramFormatter(AbstractEventFormatter):
self._log_error("No description was found", raise_error=InvalidEvent)
def _validate_message(self, message: str) -> None:
if len(message) >= 4096:
if (
len("".join(BeautifulSoup(message, "html.parser").findAll(text=True)))
>= 4096
):
self._log_error("Message is too long", raise_error=InvalidMessage)
def _preprocess_event(self, event: MobilizonEvent):
event.description = html_to_markdown(event.description)
event.name = html_to_markdown(event.name)
return event
def _preprocess_message(self, message: str) -> str:
html = BeautifulSoup(message, "html.parser")
# replacing paragraphs
for tag in html.findAll(["p", "br"]):
tag.append("\n")
tag.replaceWithChildren()
# replacing headers
for tag in html.findAll(["h1", "h2", "h3"]):
if tag.text: # only if they are not empty
tag.name = "b"
tag.insert_after("\n")
tag.insert_before("\n")
else:
tag.decompose()
# removing lists
for tag in html.findAll("ul"):
tag.unwrap()
# replacing list elements with dots
for tag in html.findAll(["li"]):
tag.insert(0, "")
tag.unwrap()
# cleaning html trailing whitespace
for tag in html.findAll("a"):
tag["href"] = tag["href"].replace(" ", "").strip().lstrip()
return str(html)
class TelegramPlatform(AbstractPlatform):
@ -92,9 +80,6 @@ class TelegramPlatform(AbstractPlatform):
name = "telegram"
def _preprocess_message(self, message: str):
return TelegramFormatter.escape_message(message)
def validate_credentials(self):
res = requests.get(f"https://api.telegram.org/bot{self.conf.token}/getMe")
data = self._validate_response(res)
@ -107,11 +92,7 @@ class TelegramPlatform(AbstractPlatform):
def _send(self, message: str, event: Optional[MobilizonEvent] = None) -> Response:
return requests.post(
url=f"https://api.telegram.org/bot{self.conf.token}/sendMessage",
json={
"chat_id": self.conf.chat_id,
"text": message,
"parse_mode": "markdownv2",
},
json={"chat_id": self.conf.chat_id, "text": message, "parse_mode": "html"},
)
def _validate_response(self, res):

View File

@ -1,8 +1,8 @@
*{{ name }}*
<strong>{{ name }}</strong>
🕒 {{ begin_datetime.format('DD MMMM, HH:mm') }} - {{ end_datetime.format('DD MMMM, HH:mm') }}
{% if location %}📍 {{ location }}{% endif %}
{{ description }}
[Link]({{mobilizon_link}})
<a href="{{mobilizon_link}}">Link</a>

View File

@ -1,3 +1,4 @@
import dataclasses
from functools import partial
from typing import Iterable, Optional
from uuid import UUID
@ -167,7 +168,9 @@ async def build_publications(event: MobilizonEvent) -> list[EventPublication]:
await event_model.build_publication_by_publisher_name(name)
for name in get_active_publishers()
]
return list(EventPublication.from_orm(m, event) for m in models)
return list(
EventPublication.from_orm(m, dataclasses.replace(event)) for m in models
)
@atomic(CONNECTION_NAME)

166
poetry.lock generated
View File

@ -36,6 +36,32 @@ category = "main"
optional = false
python-versions = "*"
[[package]]
name = "apscheduler"
version = "3.6.3"
description = "In-process task scheduler with Cron-like capabilities"
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
pytz = "*"
six = ">=1.4.0"
tzlocal = ">=1.2"
[package.extras]
asyncio = ["trollius"]
doc = ["sphinx", "sphinx-rtd-theme"]
gevent = ["gevent"]
mongodb = ["pymongo (>=2.8)"]
redis = ["redis (>=3.0)"]
rethinkdb = ["rethinkdb (>=2.4.0)"]
sqlalchemy = ["sqlalchemy (>=0.8)"]
testing = ["pytest", "pytest-cov", "pytest-tornado5", "mock", "pytest-asyncio (<0.6)", "pytest-asyncio"]
tornado = ["tornado (>=4.3)"]
twisted = ["twisted"]
zookeeper = ["kazoo"]
[[package]]
name = "arrow"
version = "1.1.1"
@ -92,6 +118,14 @@ soupsieve = {version = ">1.2", markers = "python_version >= \"3.0\""}
html5lib = ["html5lib"]
lxml = ["lxml"]
[[package]]
name = "cachetools"
version = "4.2.2"
description = "Extensible memoizing collections and decorators"
category = "main"
optional = false
python-versions = "~=3.5"
[[package]]
name = "certifi"
version = "2021.10.8"
@ -391,6 +425,26 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
[package.dependencies]
six = ">=1.5"
[[package]]
name = "python-telegram-bot"
version = "13.10"
description = "We have made you a wrapper you can't refuse"
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
APScheduler = "3.6.3"
cachetools = "4.2.2"
certifi = "*"
pytz = ">=2018.6"
tornado = ">=6.1"
[package.extras]
json = ["ujson"]
passport = ["cryptography (!=3.4,!=3.4.1,!=3.4.2,!=3.4.3)"]
socks = ["pysocks"]
[[package]]
name = "pytz"
version = "2021.3"
@ -399,6 +453,17 @@ category = "main"
optional = false
python-versions = "*"
[[package]]
name = "pytz-deprecation-shim"
version = "0.1.0.post0"
description = "Shims to make deprecation of pytz easier"
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
[package.dependencies]
tzdata = {version = "*", markers = "python_version >= \"3.6\""}
[[package]]
name = "requests"
version = "2.25.1"
@ -480,6 +545,14 @@ category = "main"
optional = false
python-versions = ">=3.6,<4.0"
[[package]]
name = "tornado"
version = "6.1"
description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
category = "main"
optional = false
python-versions = ">= 3.5"
[[package]]
name = "tortoise-orm"
version = "0.17.8"
@ -526,6 +599,30 @@ category = "main"
optional = false
python-versions = ">=3.6"
[[package]]
name = "tzdata"
version = "2021.5"
description = "Provider of IANA time zone data"
category = "main"
optional = false
python-versions = ">=2"
[[package]]
name = "tzlocal"
version = "4.1"
description = "tzinfo object for the local timezone"
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
pytz-deprecation-shim = "*"
tzdata = {version = "*", markers = "platform_system == \"Windows\""}
[package.extras]
devenv = ["black", "pyroma", "pytest-cov", "zest.releaser"]
test = ["pytest-mock (>=3.3)", "pytest (>=4.3)"]
[[package]]
name = "urllib3"
version = "1.26.7"
@ -542,7 +639,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
content-hash = "5c405fa6ef97b2f9f81e5cf3ea24313142fcf712b6dda7eda87facb0d281f153"
content-hash = "1001a2815c4da3a9e3ce5fed65bcbd2b962bec3dc64180cf217430f2a9d32b9e"
[metadata.files]
aerich = [
@ -557,6 +654,10 @@ appdirs = [
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
]
apscheduler = [
{file = "APScheduler-3.6.3-py2.py3-none-any.whl", hash = "sha256:e8b1ecdb4c7cb2818913f766d5898183c7cb8936680710a4d3a966e02262e526"},
{file = "APScheduler-3.6.3.tar.gz", hash = "sha256:3bb5229eed6fbbdafc13ce962712ae66e175aa214c69bed35a06bffcf0c5e244"},
]
arrow = [
{file = "arrow-1.1.1-py3-none-any.whl", hash = "sha256:77a60a4db5766d900a2085ce9074c5c7b8e2c99afeaa98ad627637ff6f292510"},
{file = "arrow-1.1.1.tar.gz", hash = "sha256:dee7602f6c60e3ec510095b5e301441bc56288cb8f51def14dcb3079f623823a"},
@ -578,6 +679,10 @@ beautifulsoup4 = [
{file = "beautifulsoup4-4.9.3-py3-none-any.whl", hash = "sha256:fff47e031e34ec82bf17e00da8f592fe7de69aeea38be00523c04623c04fb666"},
{file = "beautifulsoup4-4.9.3.tar.gz", hash = "sha256:84729e322ad1d5b4d25f805bfa05b902dd96450f43842c4e99067d5e1369eb25"},
]
cachetools = [
{file = "cachetools-4.2.2-py3-none-any.whl", hash = "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001"},
{file = "cachetools-4.2.2.tar.gz", hash = "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"},
]
certifi = [
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
{file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
@ -756,10 +861,18 @@ python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
]
python-telegram-bot = [
{file = "python-telegram-bot-13.10.tar.gz", hash = "sha256:d2c555431821f4ace0c1b7ce12af41999f01b793b275dee131f1034d08c01e3e"},
{file = "python_telegram_bot-13.10-py3-none-any.whl", hash = "sha256:833f39110f5d019b39a6c6fcbabd6ea1627eaaa0a26e618c0be099568672d791"},
]
pytz = [
{file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"},
{file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"},
]
pytz-deprecation-shim = [
{file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"},
{file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"},
]
requests = [
{file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"},
{file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"},
@ -789,6 +902,49 @@ tomlkit = [
{file = "tomlkit-0.8.0-py3-none-any.whl", hash = "sha256:b824e3466f1d475b2b5f1c392954c6cb7ea04d64354ff7300dc7c14257dc85db"},
{file = "tomlkit-0.8.0.tar.gz", hash = "sha256:29e84a855712dfe0e88a48f6d05c21118dbafb283bb2eed614d46f80deb8e9a1"},
]
tornado = [
{file = "tornado-6.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32"},
{file = "tornado-6.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c"},
{file = "tornado-6.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05"},
{file = "tornado-6.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910"},
{file = "tornado-6.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b"},
{file = "tornado-6.1-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675"},
{file = "tornado-6.1-cp35-cp35m-win32.whl", hash = "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5"},
{file = "tornado-6.1-cp35-cp35m-win_amd64.whl", hash = "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68"},
{file = "tornado-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb"},
{file = "tornado-6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c"},
{file = "tornado-6.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921"},
{file = "tornado-6.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558"},
{file = "tornado-6.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c"},
{file = "tornado-6.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085"},
{file = "tornado-6.1-cp36-cp36m-win32.whl", hash = "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575"},
{file = "tornado-6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795"},
{file = "tornado-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f"},
{file = "tornado-6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102"},
{file = "tornado-6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4"},
{file = "tornado-6.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd"},
{file = "tornado-6.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01"},
{file = "tornado-6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d"},
{file = "tornado-6.1-cp37-cp37m-win32.whl", hash = "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df"},
{file = "tornado-6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37"},
{file = "tornado-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95"},
{file = "tornado-6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a"},
{file = "tornado-6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5"},
{file = "tornado-6.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288"},
{file = "tornado-6.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f"},
{file = "tornado-6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6"},
{file = "tornado-6.1-cp38-cp38-win32.whl", hash = "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326"},
{file = "tornado-6.1-cp38-cp38-win_amd64.whl", hash = "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c"},
{file = "tornado-6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5"},
{file = "tornado-6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe"},
{file = "tornado-6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea"},
{file = "tornado-6.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2"},
{file = "tornado-6.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0"},
{file = "tornado-6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd"},
{file = "tornado-6.1-cp39-cp39-win32.whl", hash = "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c"},
{file = "tornado-6.1-cp39-cp39-win_amd64.whl", hash = "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4"},
{file = "tornado-6.1.tar.gz", hash = "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791"},
]
tortoise-orm = [
{file = "tortoise-orm-0.17.8.tar.gz", hash = "sha256:1f5020e9964d32a4d6ed685d466b5d7285de328a63ee92ee988c1e4baf8fefbf"},
{file = "tortoise_orm-0.17.8-py3-none-any.whl", hash = "sha256:f18c41bb83be4748a6ca259ed7309ca954b35f5790971824bbc79a11d2b1ef3b"},
@ -801,6 +957,14 @@ typing-extensions = [
{file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"},
{file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"},
]
tzdata = [
{file = "tzdata-2021.5-py2.py3-none-any.whl", hash = "sha256:3eee491e22ebfe1e5cfcc97a4137cd70f092ce59144d81f8924a844de05ba8f5"},
{file = "tzdata-2021.5.tar.gz", hash = "sha256:68dbe41afd01b867894bbdfd54fa03f468cfa4f0086bfb4adcd8de8f24f3ee21"},
]
tzlocal = [
{file = "tzlocal-4.1-py3-none-any.whl", hash = "sha256:28ba8d9fcb6c9a782d6e0078b4f6627af1ea26aeaa32b4eab5324abc7df4149f"},
{file = "tzlocal-4.1.tar.gz", hash = "sha256:0f28015ac68a5c067210400a9197fc5d36ba9bc3f8eaf1da3cbd59acdfed9e09"},
]
urllib3 = [
{file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"},
{file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"},

View File

@ -23,6 +23,7 @@ appdirs = "~1.4"
tweepy = "~4.1"
facebook-sdk = {git = "https://github.com/mobolic/facebook-sdk.git"}
aerich = "~0.6"
python-telegram-bot = "^13.10"
[tool.poetry.dev-dependencies]
responses = "~0.13"

View File

@ -26,27 +26,6 @@ def test_message_length_failure(event):
TelegramFormatter().validate_event(event)
@pytest.mark.parametrize(
"message, result",
[
["", ""],
["a#b", "ab"],
["-", "\\-"],
["(", "\\("],
["!", "\\!"],
[")", "\\)"],
[")!", "\\)\\!"],
["[link](https://link.com)", "[link](https://link.com)"],
[
"[link](https://link.com) [link2](https://link.com)",
"[link](https://link.com) [link2](https://link.com)",
],
],
)
def test_escape_message(message, result):
assert TelegramFormatter().escape_message(message) == result
def test_event_validation(event):
event.description = None
with pytest.raises(InvalidEvent):