Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check Python 3.11 #473

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ed2e036
Check Python 3.11
attzonko Dec 14, 2023
53c3c03
Update test.yml
attzonko Dec 14, 2023
b4e12f1
Update lint.yml
attzonko Dec 14, 2023
347067c
Adding ruff
attzonko Jan 19, 2024
6cd641d
Add ruff to lint
attzonko Jan 19, 2024
e77ccef
Merge branch 'main' into attzonko-patch-3
attzonko Feb 22, 2024
9d861a5
Build(deps-dev): bump pytest from 8.0.1 to 8.0.2
dependabot[bot] Feb 26, 2024
67effa4
Build(deps-dev): bump pytype from 2024.2.13 to 2024.2.27
dependabot[bot] Mar 4, 2024
3e3534a
Configurable log level
Roy-Orbison Mar 12, 2024
f25d87d
Reorder imports as per isort rules
unode Mar 15, 2024
dd1a447
Reorder imports as per isort rules
unode Mar 15, 2024
325b068
Build(deps-dev): bump filelock from 3.13.1 to 3.13.3 (#506)
dependabot[bot] Mar 26, 2024
b6c5437
CI: update pre-commit hooks (#501)
github-actions[bot] Mar 26, 2024
51da0fa
Build(deps-dev): bump pytype from 2024.2.27 to 2024.3.19 (#505)
dependabot[bot] Mar 26, 2024
e67a008
Build(deps-dev): bump black from 24.2.0 to 24.3.0 (#503)
dependabot[bot] Mar 26, 2024
d2f15d2
Build(deps-dev): bump pytest from 8.0.2 to 8.1.1 (#499)
dependabot[bot] Mar 26, 2024
4e36d64
Add ruff to pre-commit framework
unode Mar 31, 2024
4cae901
Fix ruff failures
unode Mar 31, 2024
3cb13c9
CI: update pre-commit hooks (#508)
github-actions[bot] Apr 2, 2024
75300a0
Build(deps-dev): bump filelock from 3.13.3 to 3.15.4
dependabot[bot] Jun 24, 2024
fc00cc2
Build(deps-dev): bump black from 24.3.0 to 24.4.2
dependabot[bot] Apr 29, 2024
c8488a3
Build(deps-dev): bump pytest-xdist from 3.5.0 to 3.6.1
dependabot[bot] Apr 29, 2024
d78bf17
CI: update pre-commit hooks
unode Jul 6, 2024
ccfa7d2
Build(deps-dev): bump pytype from 2024.3.19 to 2024.4.11
dependabot[bot] Jul 14, 2024
9d9b2a5
Build(deps-dev): bump flake8 from 7.0.0 to 7.1.0
dependabot[bot] Jul 14, 2024
3fbba7e
Build(deps-dev): bump pytest from 8.1.1 to 8.2.2
dependabot[bot] Jul 14, 2024
db00330
CI: update pre-commit hooks
unode Jul 19, 2024
9d9c13c
remove deprecated `asyncio.iscoroutinefunction` and use `inspect.isco…
ArtemIsmagilov Jul 16, 2024
e8ca08f
update to latest spec compose
ArtemIsmagilov Jul 15, 2024
4e435cd
correction initialize args and comprehention constructions (#527)
ArtemIsmagilov Jul 26, 2024
e08ed01
CI: update pre-commit hooks
unode Jul 27, 2024
4d5a023
try up deps (#536)
ArtemIsmagilov Dec 5, 2024
744a012
remove dual list convert (#534)
ArtemIsmagilov Dec 5, 2024
cc4dffa
not needed convert args to -> tuple -> list (#532)
ArtemIsmagilov Dec 5, 2024
2dffdcd
optimization for loops and refac to py3 (#528)
ArtemIsmagilov Dec 5, 2024
0b4704e
CI: update pre-commit hooks (#540)
github-actions[bot] Dec 5, 2024
0216f37
Update mattermostautodriver requirement from ~=1.3.0 to ~=2.0.0 (#464)
dependabot[bot] Dec 10, 2024
fd7e6ae
Added file_ids handling for incoming messages (#558)
Sergeydmitr Dec 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,19 @@ jobs:
with:
access_token: ${{ github.token }}
- uses: actions/checkout@v4
- name: Set up Python 3.10
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.10'
python-version: '3.11'
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip3-${{ hashFiles('*requirements.txt') }}
- run: pip install wheel
- name: Install dependencies
run: pip install -e .[dev]
- name: Run Ruff
run: ruff .
- name: Run Flake8
run: flake8
- name: Black code style
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: [3.8, 3.9, '3.10']
python-version: [3.8, 3.9, '3.10', '3.11']

steps:
- name: Cancel Outdated Runs
Expand All @@ -43,7 +43,7 @@ jobs:
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: [3.8, 3.9, '3.10']
python-version: [3.8, 3.9, '3.10', '3.11']
steps:
- uses: actions/checkout@v4
- name: Set up Python
Expand All @@ -58,9 +58,9 @@ jobs:
run: pip install -e .[dev]
- name: Launch test server
working-directory: tests/integration_tests
run: docker-compose up -d && sleep 30
- name: Print docker info
run: docker ps -a
run: docker compose up -d && sleep 30
- name: Print docker services info
run: docker compose ps -a
- name: Run integration tests
working-directory: tests/integration_tests
run: pytest . -vv -n auto
14 changes: 10 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v4.6.0
hooks:
- id: end-of-file-fixer
- id: fix-byte-order-marker
Expand All @@ -22,16 +22,22 @@ repos:
- "--filter-files"
- repo: https://github.com/psf/black
# Code style formatting
rev: 24.2.0
rev: 24.8.0
hooks:
- id: black
exclude: (.*/)*snapshots/
- repo: https://github.com/PyCQA/flake8
# Checks the code for PEP8 violations and common pitfals
rev: 7.0.0
rev: 7.1.1
hooks:
- id: flake8
exclude: (.*/)*snapshots/
# Ruff is a "fastar than flake8" linter/formatter
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.9
hooks:
# Run the linter.
- id: ruff
- repo: https://github.com/mattseymour/pre-commit-pytype
rev: '2023.5.8'
hooks:
Expand All @@ -54,6 +60,6 @@ repos:
- "88"
- repo: https://github.com/pycqa/doc8
# sphinx rst style checker
rev: v1.1.1
rev: v1.1.2
hooks:
- id: doc8
2 changes: 0 additions & 2 deletions docker-compose.yml → compose.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: "3.7"

services:
app:
# This docker-compose file specifies a mmpy_bot
Expand Down
13 changes: 7 additions & 6 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
black==24.2.0
black==24.4.2
docformatter==1.7.5
filelock==3.13.1
filelock==3.15.4
isort==5.13.2
flake8==7.0.0
pytest==8.0.1
pytest-xdist==3.5.0
pytype==2024.2.13
flake8==7.1.0
pytest==8.2.2
pytest-xdist==3.6.1
pytype==2024.4.11
snapshottest==0.6.0
ruff==0.1.13
4 changes: 3 additions & 1 deletion mmpy_bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ def _register_logger(self):
**{
"format": self.settings.LOG_FORMAT,
"datefmt": self.settings.LOG_DATE_FORMAT,
"level": logging.DEBUG if self.settings.DEBUG else logging.INFO,
"level": (
logging.DEBUG if self.settings.DEBUG else self.settings.LOG_LEVEL
),
"filename": self.settings.LOG_FILE,
"filemode": "w",
}
Expand Down
45 changes: 22 additions & 23 deletions mmpy_bot/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def create_post(
message: str,
file_paths: Optional[Sequence[str]] = None,
root_id: str = "",
props: Dict = {},
props: Optional[Dict] = None,
ephemeral_user_id: Optional[str] = None,
):
"""Create a post in the specified channel with the specified text.
Expand All @@ -52,8 +52,8 @@ def create_post(
paths are specified, those files will be uploaded to mattermost first and then
attached.
"""
if file_paths is None:
file_paths = []
file_paths = file_paths or []
props = props or {}

file_ids = (
self.upload_files(file_paths, channel_id) if len(file_paths) > 0 else []
Expand Down Expand Up @@ -88,9 +88,9 @@ def get_post_thread(self, post_id: str):
duplicate and wrongly ordered entries in the ordered list."""
thread_info = self.posts.get_post_thread(post_id)

id_stamps = []
for id, post in thread_info["posts"].items():
id_stamps.append((id, int(post["create_at"])))
id_stamps = (
(id, int(post["create_at"])) for id, post in thread_info["posts"].items()
)
# Sort the posts by their timestamps
sorted_stamps = sorted(id_stamps, key=lambda x: x[-1])
# Overwrite the order with the sorted list
Expand All @@ -116,7 +116,7 @@ def reply_to(
message: Message,
response: str,
file_paths: Optional[Sequence[str]] = None,
props: Dict = {},
props: Optional[Dict] = None,
ephemeral: bool = False,
direct: bool = False,
):
Expand All @@ -127,8 +127,8 @@ def reply_to(

Also supports replying privately by setting direct=True.
"""
if file_paths is None:
file_paths = []
file_paths = file_paths or []
props = props or {}

if direct and not message.is_direct_message:
# NOTE we explicitly don't pass root_id as it would refer to a
Expand Down Expand Up @@ -160,14 +160,15 @@ def direct_message(
message: str,
file_paths: Optional[Sequence[str]] = None,
root_id: str = "",
props: Dict = {},
props: Optional[Dict] = None,
ephemeral_user_id: Optional[str] = None,
):
# Private/direct messages are sent to a special channel that
# includes the bot and the recipient
direct_id = self.channels.create_direct_channel([self.user_id, receiver_id])[
"id"
]
props = props or {}

return self.create_post(
channel_id=direct_id,
Expand Down Expand Up @@ -199,22 +200,20 @@ def upload_files(
) -> List[str]:
"""Given a list of file paths and the channel id, uploads the corresponding
files and returns a list their internal file IDs."""
file_list = []
for path in file_paths:
path = Path(path)
# Note: 'files' should be a name of an expected attribute in the body
# but seems to be ignored when simply uploading files to mattermost
file_list.append(
# Note: 'files' should be a name of an expected attribute in the body
# but seems to be ignored when simply uploading files to mattermost
file_list = [
(
"files",
(
"files",
(
path.name,
Path(path).read_bytes(),
),
)
Path(path).name,
Path(path).read_bytes(),
),
)
for path in file_paths
]

result = self.files.upload_file(
files=file_list, data={"channel_id": channel_id}
)
return list(info["id"] for info in result["file_infos"])
return [info["id"] for info in result["file_infos"]]
53 changes: 24 additions & 29 deletions mmpy_bot/event_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
log = logging.getLogger("mmpy.event_handler")


class EventHandler(object):
class EventHandler:
def __init__(
self,
driver: Driver,
Expand All @@ -37,10 +37,8 @@ def start(self):
def _should_ignore(self, message: Message):
# Ignore message from senders specified in settings, and maybe from ourself
return (
True
if message.sender_name.lower()
message.sender_name.lower()
in (name.lower() for name in self.settings.IGNORE_USERS)
else False
) or (self.ignore_own_messages and message.sender_name == self.driver.username)

async def _check_queue_loop(self, webhook_queue: queue.Queue):
Expand Down Expand Up @@ -75,37 +73,34 @@ async def _handle_post(self, post):

# Find all the listeners that match this message, and have their plugins handle
# the rest.
tasks = []
for matcher, functions in self.plugin_manager.message_listeners.items():
match = matcher.search(message.text)
if match:
groups = list([group for group in match.groups() if group != ""])
for function in functions:
# Create an asyncio task to handle this callback
tasks.append(
asyncio.create_task(
function.plugin.call_function(
function, message, groups=groups
)
)
)
tasks = [
asyncio.create_task(
function.plugin.call_function(
function,
message,
groups=[group for group in match.groups() if group != ""],
)
)
for matcher, functions in self.plugin_manager.message_listeners.items()
if (match := matcher.search(message.text))
for function in functions
]

# Execute the callbacks in parallel
asyncio.gather(*tasks)

async def _handle_webhook(self, event: WebHookEvent):
# Find all the listeners that match this webhook id, and have their plugins
# handle the rest.
tasks = []
for matcher, functions in self.plugin_manager.webhook_listeners.items():
match = matcher.search(event.webhook_id)
if match:
for function in functions:
# Create an asyncio task to handle this callback
tasks.append(
asyncio.create_task(
function.plugin.call_function(function, event)
)
)

tasks = [
# Create an asyncio task to handle this callback
asyncio.create_task(function.plugin.call_function(function, event))
for matcher, functions in self.plugin_manager.webhook_listeners.items()
if matcher.search(event.webhook_id)
for function in functions
]

# If this webhook doesn't correspond to any listeners, signal the WebHookServer
# to not wait for any response
if len(tasks) == 0:
Expand Down
8 changes: 4 additions & 4 deletions mmpy_bot/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def __init__(
)

self.function = function
self.is_coroutine = asyncio.iscoroutinefunction(function)
self.is_coroutine = inspect.iscoroutinefunction(function)
self.is_click_function: bool = False
self.matcher = matcher
self.metadata = metadata
Expand Down Expand Up @@ -100,7 +100,7 @@ def __init__(

if self.is_click_function:
_function = self.function.callback
if asyncio.iscoroutinefunction(_function):
if inspect.iscoroutinefunction(_function):
raise ValueError(
"Combining click functions and coroutines is currently not supported!"
" Consider using a regular function, which will be threaded by default."
Expand Down Expand Up @@ -155,10 +155,10 @@ def __call__(self, message: Message, *args):
assert len(args) <= 1 # There is only one group, (.*)?
if len(args) == 1:
# Turn space-separated string into list
args = tuple(shlex.split(args[0]))
args = shlex.split(args[0])
try:
ctx = self.function.make_context(
info_name=self.plugin.__class__.__name__, args=list(args)
info_name=self.plugin.__class__.__name__, args=args
)
ctx.params.update({"self": self.plugin, "message": message})
return self.function.invoke(ctx)
Expand Down
13 changes: 10 additions & 3 deletions mmpy_bot/settings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import collections
import logging
import os
import warnings
from dataclasses import dataclass, field, fields
Expand All @@ -8,9 +9,7 @@
def _get_comma_separated_list(string: str, type=str):
values = string.split(",")
# Convert to the specified type if necessary.
if type is not str:
values = list([type(value) for value in values])
return values
return values if type is str else [type(value) for value in values]


def _is_valid_option(_type, valid_types):
Expand Down Expand Up @@ -59,6 +58,7 @@ class Settings:
DEBUG: bool = False
# Respond to channel message "!help" (without @bot)
RESPOND_CHANNEL_HELP: bool = False
LOG_LEVEL: int = logging.INFO
LOG_FILE: Optional[str] = None
LOG_FORMAT: str = "[%(asctime)s][%(name)s][%(levelname)s] %(message)s"
LOG_DATE_FORMAT: str = "%m/%d/%Y %H:%M:%S"
Expand Down Expand Up @@ -91,6 +91,13 @@ def __post_init__(self):
)
self.MATTERMOST_API_PATH = self.MATTERMOST_API_PATH[: -len(api_url)]

if self.DEBUG:
warnings.warn(
"DEBUG has been deprecated and will be removed in a future release. "
"Set LOG_LEVEL to logging.DEBUG to increase verbosity.",
DeprecationWarning,
)

def _check_environment_variables(self):
for f in fields(self):
if f.name in os.environ:
Expand Down
4 changes: 4 additions & 0 deletions mmpy_bot/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def channel_id(self):
def channel_name(self):
return self.body["data"]["channel_name"]

@cached_property
def file_ids(self):
return self.body["data"]["post"].get("file_ids", [])

@cached_property
def is_direct_message(self):
return self.body["data"]["channel_type"] == "D"
Expand Down
Loading
Loading