Git Product home page Git Product logo

pincer's People

Contributors

arthurdw avatar beastmatser avatar codacy-badger avatar darvil82 avatar dependabot[bot] avatar dr-electron avatar drawbu avatar enderchief avatar gillesigot avatar gitbolt avatar krishnajalan avatar kylianpl avatar lunarmagpie avatar maneren avatar mithicspirit avatar mjneff2 avatar mwath avatar ooliver1 avatar qexat avatar sigmanificient avatar skelmis avatar sly-little-test avatar snyk-bot avatar sourcery-ai[bot] avatar sriram-bb63 avatar stamtsag avatar thebobbobs avatar trag1c avatar vincentrps avatar whydowelivewithoutmeaning avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

pincer's Issues

✨ Implementation of `channel.send`

Task

Implementing channel.send to allow more customization within command and future tasks.
You may also want to add a optional parameter channel to Message & Embed object.

Exemple

@task.loop(minutes=30)
async def very_useful_task(self):
    channel = await Channel.from_id(123456789)

    # Todo: implement this:
    await channel.send("Spam eggs!")

Also (optional):

@command()
async def useful_command():
    return Message(
        "Hello, world!",
        channel=await Channel.from_id(123456789)
    )

✨ Allow users to decide default encoding for pillow images

Is your feature request related to a problem? Please describe.
Pincer sends pillow images as PNGs by default. Bot developers with image heavy bots would benefit from being able to change the default image type and parameters to whatever they want.

Describe the solution you'd like
I think a config object in pincer/utils/_config.py is the best option right now. Im open to other suggestions ofc.

Notes

The Config "thing" will have to handle all of the options for image.save(). Theres a lot of stuff
and none of it is guaranteed to be used besides format. Have fun :) Luckily we only need to handle the ones that the discord docs mention.
Also make sure the system can be expanded if we need other configuration ofc.

πŸ› Guild only command doesn't work

class InfoCog:
    
    @command(guild=GUILD_ID)
    async def about_command(self) -> Embed:
        return Embed(
            ...
        )
future: <Task finished name='Task-9' coro=<Client.event_handler() done, defined at D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py:514> exception=AttributeError("'AppCommand' object has no attribute 'app'")>
Traceback (most recent call last):
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 527, in event_handler
    await self.process_event(payload.event_name.lower(), payload)
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 512, in process_event
    await self.execute_error(e)
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 490, in execute_error
    raise error
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 506, in process_event
    key, args, kwargs = await self.handle_middleware(payload, name)
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 443, in handle_middleware
    extractable = await ware(self, payload, *args, **kwargs)
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 129, in wrapper
    return await (
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\middleware\ready.py", line 37, in on_ready_middleware
    await ChatCommandHandler(self).initialize()
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\commands.py", line 462, in initialize
    await self.__add_commands()
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\commands.py", line 455, in __add_commands
    await self.add_commands(commands_to_add)
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\commands.py", line 339, in add_commands
    await gather(*list(map(
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\commands.py", line 328, in add_command
    add_endpoint = self.__add_guild.format(command=cmd)
AttributeError: 'AppCommand' object has no attribute 'app'

✨ Add a way to start the bot from asynchronous function

Is your feature request related to a problem? Please describe.
When I was editing the mCoding bot to only use a global aiohttp session, I stumbled upon an error when trying to run this code:

async def main():
    async with aiohttp.ClientSession() as session:
        bot.run()


asyncio.run(main())

Error: RuntimeError: This event loop is already running

Describe the solution you'd like
An (asynchronous) method that allows this behaviour.
Like this:

async def main():
    async with aiohttp.ClientSession() as session:
        await bot.start()


asyncio.run(main())

Describe alternatives you've considered
Use a method that always checks if the session exists, if not create one, else return the existing one.

πŸ› Python 3.7 Does not support 'typing.Protocol'

Describe the bug
Python 3.7 does not support typing.Protocol.

To Reproduce
Steps to reproduce the behavior:

  1. Run code in python 3.7
  2. Get an error
    ImportError: cannot import name 'Protocol' from 'typing' (/usr/lib/python3.7/typing.py)

πŸ§ͺ Improving Code Coverage with new pytests

As of right now, there is only 2, or more like a single test for the whole library.

Tasks

Implement new pytests to validate the behavior of objects, utils and core components of the library.
All missing tests on current should be passed.

πŸ› Can't create Message with MessageComponent inside of MessageComponent

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Try to create this object

Message(
    content="1234",
    components=[
        MessageComponent(
            type=1,
            components=[
                MessageComponent(
                    type=2,
                    label="click me!",
                    style=2,
                    custom_id="1234"
                )
            ]
        )
    ]
)

Theres 2 errors.

  1. options should be optional. A few other APINullable properties are not correctly marked as missing.
  2. This error is raised if the other problem is fixed.

πŸ› Unexpected 'default_member_permissions' for commands

Seems like commands missing a other arg

payload received

DEBUG:pincer.core:Received response for applications/901944968002801665/commands | [{"id": "901949693456678924", "application_id": "901944968002801665", "name": "panel", "description": "Description not set", "version": "901949693456678925", "default_permission": true, "default_member_permissions": null, "type": 1, "dm_permission": null}]
Traceback (most recent call last):
  File "D:\Sigmou-Bot\venv\lib\site-packages\pincer\client.py", line 523, in event_handler
    await self.process_event(payload.event_name.lower(), payload)
  File "D:\Sigmou-Bot\venv\lib\site-packages\pincer\client.py", line 508, in process_event
    await self.execute_error(e)
  File "D:\Sigmou-Bot\venv\lib\site-packages\pincer\client.py", line 486, in execute_error
    raise error
  File "D:\Sigmou-Bot\venv\lib\site-packages\pincer\client.py", line 502, in process_event
    key, args, kwargs = await self.handle_middleware(payload, name)
  File "D:\Sigmou-Bot\venv\lib\site-packages\pincer\client.py", line 439, in handle_middleware
    extractable = await ware(self, payload, *args, **kwargs)
  File "D:\Sigmou-Bot\venv\lib\site-packages\pincer\client.py", line 111, in wrapper
    return await (
  File "D:\Sigmou-Bot\venv\lib\site-packages\pincer\middleware\ready.py", line 37, in on_ready_middleware
    await ChatCommandHandler(self).initialize()
  File "D:\Sigmou-Bot\venv\lib\site-packages\pincer\commands.py", line 486, in initialize
    await self.__init_existing_commands()
  File "D:\Sigmou-Bot\venv\lib\site-packages\pincer\commands.py", line 364, in __init_existing_commands
    self._api_commands = await self.get_commands()
  File "D:\Sigmou-Bot\venv\lib\site-packages\pincer\commands.py", line 300, in get_commands
    return list(map(
  File "D:\Sigmou-Bot\venv\lib\site-packages\pincer\utils\api_object.py", line 105, in from_dict
    return cls(
TypeError: __init__() got an unexpected keyword argument 'default_member_permissions'

πŸ‘” Name conflicts

As #2 and #3 stated, this project's name is similar to names of other projects. In this issue we can discuss what to do with there conflicts.

πŸ› Bug in bot loading with package architecture

Bot structure

- app
    - cogs
        - __init__.py
        - info.py

    - __init__.py
    - bot.py
- run.py
DEBUG:pincer.core:New event received, checking if handler exists for opcode: 0
DEBUG:pincer.core:Event handler found, ensuring async future in current loop.
DEBUG:pincer.core:Waiting for new event.
DEBUG:pincer:`ready` middleware has been invoked
DEBUG:root:0 commands registered.
DEBUG:pincer.core:GET applications/881583379504582727/commands | null
DEBUG:pincer:`payload` middleware has been invoked
DEBUG:pincer.core:Received response for applications/881583379504582727/commands | []
DEBUG:pincer.core:Request has been sent successfully. Returning json response.
ERROR:asyncio:Task exception was never retrieved
[crash]
future: <Task finished name='Task-9' coro=<Client.event_handler() done, defined at D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py:514> exception=KeyError('app.bot')>
Traceback (most recent call last):
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 527, in event_handler
    await self.process_event(payload.event_name.lower(), payload)
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 512, in process_event
    await self.execute_error(e)
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 490, in execute_error
    raise error
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 509, in process_event
    self.execute_event(call, *args, **kwargs)
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 400, in execute_event
    args = (ChatCommandHandler.managers[call.__module__], *args)
KeyError: 'app.bot'

πŸ› Missing `8` as value of `SystemChannelFlags`

Traceback (most recent call last):
  File "/home/container/mcoding_bot/tasks/update_channels.py", line 91, in update_channels
    await self.get_guild(self.config.mcoding_server)
  File "/home/container/venv/lib/python3.8/site-packages/pincer/client.py", line 561, in get_guild
    return await Guild.from_id(self, guild_id)
  File "/home/container/venv/lib/python3.8/site-packages/pincer/objects/guild/guild.py", line 480, in from_id
    return Guild.from_dict(construct_client_dict(client, data))
  File "/home/container/venv/lib/python3.8/site-packages/pincer/objects/guild/guild.py", line 535, in from_dict
    return super().from_dict(data)
  File "/home/container/venv/lib/python3.8/site-packages/pincer/utils/api_object.py", line 236, in from_dict
    return cls(**dict(map(
  File "<string>", line 64, in __init__
  File "/home/container/venv/lib/python3.8/site-packages/pincer/utils/api_object.py", line 207, in __post_init__
    attr_value = self.__attr_convert(attr, specific_tp)
  File "/home/container/venv/lib/python3.8/site-packages/pincer/utils/api_object.py", line 168, in __attr_convert
    return convert(
  File "/home/container/venv/lib/python3.8/site-packages/pincer/utils/conversion.py", line 57, in convert
    return MISSING if value is MISSING else handle_factory()
  File "/home/container/venv/lib/python3.8/site-packages/pincer/utils/conversion.py", line 54, in handle_factory
    else fin_fac(value)
  File "/home/container/venv/lib/python3.8/site-packages/pincer/utils/conversion.py", line 49, in fin_fac
    return factory(v)
  File "/usr/local/lib/python3.8/enum.py", line 339, in __call__
    return cls.__new__(cls, value)
  File "/usr/local/lib/python3.8/enum.py", line 662, in __new__
    raise ve_exc
ValueError: 8 is not a valid SystemChannelFlags

image

πŸ‘” Naming colision

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

πŸ”¨ Implement command options (subcommands)

Feature

Implement subcommands. So that eg the following data gets sent to discord:

{
    "name": "permissions",
    "description": "Get or edit permissions for a user or a role",
    "options": [
        {
            "name": "user",
            "description": "Get or edit permissions for a user",
            "type": 2, // 2 is type SUB_COMMAND_GROUP
            "options": [
                {
                    "name": "get",
                    "description": "Get permissions for a user",
                    "type": 1, // 1 is type SUB_COMMAND
                    "options": [
                        {
                            "name": "user",
                            "description": "The user to get",
                            "type": 6, // 6 is type USER
                            "required": true
                        },
                        {
                            "name": "channel",
                            "description": "The channel permissions to get. If omitted, the guild permissions will be returned",
                            "type": 7, // 7 is type CHANNEL
                            "required": false
                        }
                    ]
                },
                {
                    "name": "edit",
                    "description": "Edit permissions for a user",
                    "type": 1,
                    "options": [
                        {
                            "name": "user",
                            "description": "The user to edit",
                            "type": 6,
                            "required": true
                        },
                        {
                            "name": "channel",
                            "description": "The channel permissions to edit. If omitted, the guild permissions will be edited",
                            "type": 7,
                            "required": false
                        }
                    ]
                }
            ]
        },
        {
            "name": "role",
            "description": "Get or edit permissions for a role",
            "type": 2,
            "options": [
                {
                    "name": "get",
                    "description": "Get permissions for a role",
                    "type": 1,
                    "options": [
                        {
                            "name": "role",
                            "description": "The role to get",
                            "type": 8, // 8 is type ROLE
                            "required": true
                        },
                        {
                            "name": "channel",
                            "description": "The channel permissions to get. If omitted, the guild permissions will be returned",
                            "type": 7,
                            "required": false
                        }
                    ]
                },
                {
                    "name": "edit",
                    "description": "Edit permissions for a role",
                    "type": 1,
                    "options": [
                        {
                            "name": "role",
                            "description": "The role to edit",
                            "type": 8,
                            "required": true
                        },
                        {
                            "name": "channel",
                            "description": "The channel permissions to edit. If omitted, the guild permissions will be edited",
                            "type": 7,
                            "required": false
                        }
                    ]
                }
            ]
        }
    ]
}

Code implementation

Open for discussion, please post suggestions on how you'd like to use this in the lib.

Useful link(s)

https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure

:rotating_light: Flake8 W503/W504 warnings

Describe the bug
Flake8 warns about both line break before and after a binary operator (W503 and W504).
Therefore you always have warnings no matter what code style you use.

Expected behavior
Flake8 should not warn about W503 errors since Pincer is already using W504's code style.

Potential fix
Add W503 to the ignore list in the file .flake8.
e.g.

ignore =
    ...
    H501,
    # W503: line break before binary operator
    W503

Screenshots
image
image

Speech Recognizer using python

Describe the solution you'd like
I want to add speech recognizer code that can identify words that we spoke and this can be used for further improvement of any customized work.

✨Type checking imports for all type hints

Task

Only import type hints when TYPE_CHECKING is true.

Must be present:

from __future__ import annotations

from typing import TYPE_CHECKING

Example

from __future__ import annotations

from typing import TYPE_CHECKING
from dataclasses import dataclass


if TYPE_CHECKING:
    from typing import List


@dataclass
class Foo:
    bar: List[int] = None

Speech Recognizer using python

*Describe the solution you'd like
I want to add speech recognizer code that can identify words that we spoke and this can be used for further improvement of any customized work.

πŸ› [Python 3.8.8] Unsupported `|` operation for types `dict`

Describe the bug
An unsupported | operation causing a crash within the middlewares.

future: <Task finished name='Task-10' coro=<Client.event_handler() done, defined at /home/container/pincer/client.py:340> exception=TypeError("unsupported operand type(s) for |: 'dict' and 'dict'")>
Traceback (most recent call last):
  File "/home/container/pincer/client.py", line 353, in event_handler
    await self.process_event(payload.event_name.lower(), payload)
  File "/home/container/pincer/client.py", line 330, in process_event
    key, args, kwargs = await self.handle_middleware(payload, event_name)
  File "/home/container/pincer/client.py", line 295, in handle_middleware
    extractable = await ware(self, payload, *args, **kwargs)
  File "/home/container/pincer/client.py", line 119, in wrapper
    return await (
  File "/home/container/pincer/middleware/ready.py", line 26, in on_ready_middleware
    {"_client": self, "_http": self.http} | payload.data.get("user")
TypeError: unsupported operand type(s) for |: 'dict' and 'dict'
DEBUG:pincer:`payload` middleware has been invoked

This also cause the function to not work.

  • os: ubuntu 18.04
  • pincer: 0.6.11
  • python: 3.8.8

πŸ› Basic cog Example don't work

ERROR:asyncio:Task exception was never retrieved
future: <Task finished name='Task-14' coro=<OnReadyCog.on_ready() done, defined at D:\Pincer\dev\basic_cogs\cogs\on_ready.py:8> exception=AttributeError("'OnReadyCog' object has no attribute 'client'")>
Traceback (most recent call last):
  File "D:\Pincer\dev\basic_cogs\cogs\on_ready.py", line 12, in on_ready
    f"Started client on {self.client.bot}\n"
AttributeError: 'OnReadyCog' object has no attribute 'client'

πŸ› Relative import are not suported for cogs loading

       for cog_class in start_config:
           self.load_cog(f".cogs.{flatten_name(cog_class)}")
Traceback (most recent call last):
  File "D:\Pincer-Bot\run.py", line 12, in <module>
    main()
  File "D:\Pincer-Bot\run.py", line 8, in main
    Bot().run()
  File "D:\Pincer-Bot\app\bot.py", line 16, in __init__
    self.load_cogs()
  File "D:\Pincer-Bot\app\bot.py", line 25, in load_cogs
    self.load_cog(f".cogs.{flatten_name(cog_class)}")
  File "D:\Pincer-Bot\venv\lib\site-packages\pincer\client.py", line 323, in load_cog
    module = import_module(path)
  File "C:\Users\Sigmanificient\AppData\Local\Programs\Python\Python39\lib\importlib\__init__.py", line 122, in import_module
    raise TypeError(msg.format(name))
TypeError: the 'package' argument is required to perform a relative import for '.cogs.info'

Process finished with exit code 1
``

πŸ› Exception thrown when ping is sent in DM

Describe the bug
When you send a notification to a bot in a DM, it causes an exception and the on_message() event does not run.
https://pastebin.com/YGHtuWuu

To Reproduce
Steps to reproduce the behavior:

  1. Paste this code in
from pincer import Client
from pincer.objects.app.intents import Intents

bot = Client(token, intents=Intents.DIRECT_MESSAGES)
bot.run()

Expected behavior
There should not be an exception. Additionally. on_message() should run.

Desktop (please complete the following information):

  • Python Version - Python 3.8.12
  • OS: I use arch btw
  • Browser: Discord App

πŸ› Request in `UserMessage.react` missing an argument

Describe the bug
Look in the file pincer/objects/message/user_message.py in the function UserMessage.react.
Issue:
The react function calls HTTPClient.put which requires route and data as an argument but it only supplies route.

Expected behavior
It should either be optional or there is a missing argument.

Additional context
Using Pincer 0.10.0

πŸ› Circular Import Bug

Describe the bug

Circular imports for pincer.objects.interactions

Error:


Traceback (most recent call last):
  File "/home/docs/checkouts/readthedocs.org/user_builds/pincer-test/checkouts/latest/pincer/__init__.py", line 17, in <module>
    from pincer.client import Client, Bot
  File "/home/docs/checkouts/readthedocs.org/user_builds/pincer-test/checkouts/latest/pincer/client.py", line 37, in <module>
    from pincer.objects.user import User
  File "/home/docs/checkouts/readthedocs.org/user_builds/pincer-test/checkouts/latest/pincer/objects/__init__.py", line 41, in <module>
    from .interactions import Interaction, MessageInteraction
  File "/home/docs/checkouts/readthedocs.org/user_builds/pincer-test/checkouts/latest/pincer/objects/interactions.py", line 33, in <module>
    from pincer.objects.message import Message
  File "/home/docs/checkouts/readthedocs.org/user_builds/pincer-test/checkouts/latest/pincer/objects/message.py", line 36, in <module>
    from pincer.objects.interactions import MessageInteraction
ImportError: cannot import name 'MessageInteraction' from partially initialized module 'pincer.objects.interactions' (most likely due to a circular import) (/home/docs/checkouts/readthedocs.org/user_builds/pincer-test/checkouts/latest/pincer/objects/interactions.py)

πŸ› Unhandled payload with `"op": 0`

Describe the bug
An unhandled payload cause the dispatcher the raise an UnhandldException

The payload received is the following:

{
  "op": 0,
  "d": {
    "v": 9,
    "user_settings": {},
    "user": {
      "verified": true,
      "username": "Pincer",
      "mfa_enabled": true,
      "id": "881583379504582727",
      "flags": 0,
      "email": null,
      "discriminator": "9011",
      "bot": true,
      "avatar": "4a50719d099a6dd1e385dfe5367ff77b"
    },
    "session_id": "5bc3022b8cfda8224bcb8b8e22ff236f",
    "relationships": [],
    "private_channels": [],
    "presences": [],
    "guilds": [
      {
        "unavailable": true,
        "id": "813915317867642910"
      },
      {
        "unavailable": true,
        "id": "846838746833747968"
      },
      {
        "unavailable": true,
        "id": "881531065859190804"
      }
    ],
    "guild_join_requests": [],
    "geo_ordered_rtc_regions": [
      "europe",
      "st-pete",
      "russia",
      "dubai",
      "india"
    ],
    "application": {
      "id": "881583379504582727",
      "flags": 303104
    },
    "_trace": [
      (
            "[\"gateway-prd-main-xcl8\",{\"micros\":82707,\"calls\":[\"discord-sessions-blue-prd-2-124\","
            "{\"micros\":80697,\"calls\":[\"start_session\",{\"micros\":55991,\"calls\":[\"api-prd-main-5v7v\","
            "{\"micros\":49593,\"calls\":[\"get_user\",{\"micros\":5644},\"add_authorized_ip\",{\"micros\":1403},"
            "\"get_guilds\",{\"micros\":5424},\"coros_wait\",{\"micros\":0}]}]},\"guilds_connect\",{\"micros\":2,"
            "\"calls\":[]},\"presence_connect\",{\"micros\":19581,\"calls\":[]}]}]}]"
      )
    ]
  },
  "s": 1,
  "t": "READY"
}

To Reproduce
Steps to reproduce the behavior:

from pincer.core.gateway import Dispatcher

BOT_TOKEN: str = ...

bot = Dispatcher(BOT_TOKEN)
bot.run()

πŸ—οΈ Reorganizing the objects package with with subfolders

module organization within the library is crucial, and the current objects package isn't very well organized, with almost all object put at the root. This is the actual tree of the pincer.objects folder:

objects
β”œβ”€ events
β”‚   β”œβ”€β”€ channel.py
β”‚   β”œβ”€β”€ error.py
β”‚   β”œβ”€β”€ gateway_commands.py
β”‚   β”œβ”€β”€ guild.py
β”‚   β”œβ”€β”€ hello_ready.py
β”‚   β”œβ”€β”€ integration.py
β”‚   β”œβ”€β”€ invite.py
β”‚   β”œβ”€β”€ message.py
β”‚   β”œβ”€β”€ presence.py
β”‚   β”œβ”€β”€ thread.py
β”‚   β”œβ”€β”€ typing_start.py
β”‚   β”œβ”€β”€ voice.py
β”‚   β”œβ”€β”€ webhook.py
β”‚   └── __init__.py
β”œβ”€β”€  application.py
β”œβ”€β”€  app_command.py
β”œβ”€β”€  attachment.py
β”œβ”€β”€  audit_log.py
β”œβ”€β”€  ban.py
β”œβ”€β”€  button.py
β”œβ”€β”€  channel.py
β”œβ”€β”€  connection.py
β”œβ”€β”€  embed.py
β”œβ”€β”€  emoji.py
β”œβ”€β”€  followed_channel.py
β”œβ”€β”€  guild.py
β”œβ”€β”€  guild_features.py
β”œβ”€β”€  guild_member.py
β”œβ”€β”€  guild_template.py
β”œβ”€β”€  guild_widget.py
β”œβ”€β”€  integration.py
β”œβ”€β”€  intents.py
β”œβ”€β”€  interactions.py
β”œβ”€β”€  interaction_base.py
β”œβ”€β”€  invite.py
β”œβ”€β”€  message.py
β”œβ”€β”€  message_component.py
β”œβ”€β”€  message_context.py
β”œβ”€β”€  message_reference.py
β”œβ”€β”€  overwrite.py
β”œβ”€β”€  reaction.py
β”œβ”€β”€  role.py
β”œβ”€β”€  select_menu.py
β”œβ”€β”€  session_start_limit.py
β”œβ”€β”€  stage.py
β”œβ”€β”€  sticker.py
β”œβ”€β”€  thread.py
β”œβ”€β”€  throttle_scope.py
β”œβ”€β”€  throttling.py
β”œβ”€β”€  user.py
β”œβ”€β”€  user_message.py
β”œβ”€β”€  voice_region.py
β”œβ”€β”€  voice_state.py
β”œβ”€β”€  webhook.py
β”œβ”€β”€  welcome_screen.py
└── __init__.py

Moving each module to a separate package would make thing easier.

objects
β”œβ”€β”€ events
β”‚   β”œβ”€β”€ ...
β”‚   └── __init__.py
β”œβ”€β”€ app
β”‚   β”œβ”€β”€ ...
β”‚   └── __init__.py
β”œβ”€β”€ guild
β”‚   β”œβ”€β”€ ...
β”‚   └── __init__.py
β”œβ”€β”€ message
β”‚   β”œβ”€β”€ ...
β”‚   └── __init__.py
β”œβ”€β”€ user
β”‚   β”œβ”€β”€ ...
β”‚   └── __init__.py
└── voice
    β”œβ”€β”€ ...
    └── __init__.py

πŸ› TypeError: 'MissingType' object is not subscriptable

Describe the bug
This error occurs

    content_type: APINullable[str] = MISSING
TypeError: 'MissingType' object is not subscriptable

To Reproduce
Run code that has this line or build docs.

Expected behavior
There shouldn't be an error

Additional context
APINullable can be
APINullable = Union[S, MissingType]
This should allow it to use generics.

mypy generics docs

πŸ› TypeError: __init__() got an unexpected keyword argument 'member'

Describe the bug
When running a basic command, there is an error that prints out but the command still works.

To Reproduce
Steps to reproduce the behavior:

  1. Using a simple bot with a guild command
from pincer import Client, command
from pincer.objects import Intents

class Bot(Client):
    @Client.event
    async def on_ready(self):
        print(f'Bot logged in on as {self.bot}')

    @command(guild=GUILD_ID_HERE)
    async def ping(self):
        return f'Pong!'

bot = Bot(TOKEN_HERE, intents=Intents.all())
bot.run()
  1. Run the code
  2. Call /ping
  3. The bot will return Pong! to Discord but raises an error.

Expected behavior
No error.

Full Console Out/Input

$ python main.py
<function on_ready_middleware at 0x7f2adec9e040> True
Bot logged in on as BOTNAME#XXXX
<function interaction_create_middleware at 0x7f2adec8fdc0> True
<function message_create_middleware at 0x7f2adec8fee0> False
ERROR:asyncio:Task exception was never retrieved
future: <Task finished name='Task-15' coro=<Client.event_handler() done, defined at Pincer/pincer/client.py:337> exception=TypeError("__init__() got an unexpected keyword argument 'member'")>
Traceback (most recent call last):
  File "Pincer/pincer/client.py", line 352, in event_handler
    key, args, kwargs = await self.handle_middleware(payload, event_name)
  File "Pincer/pincer/client.py", line 315, in handle_middleware
    extractable = await ware(self, payload, *args, **kwargs)
  File "Pincer/pincer/client.py", line 142, in wrapper
    return await (
  File "Pincer/pincer/middleware/message_create.py", line 32, in message_create_middleware
    return "on_message", [UserMessage.from_dict(payload.data)]
  File "Pincer/pincer/utils/api_object.py", line 105, in from_dict
    return cls(**{
  File "<string>", line 33, in __init__
  File "Pincer/pincer/objects/user_message.py", line 337, in __post_init__
    self.interaction = convert(
  File "Pincer/pincer/utils/conversion.py", line 50, in convert
    return MISSING if value is MISSING else handle_factory()
  File "Pincer/pincer/utils/conversion.py", line 47, in handle_factory
    else fin_fac(value)
  File "Pincer/pincer/utils/conversion.py", line 41, in fin_fac
    else factory(v)
  File "Pincer/pincer/utils/api_object.py", line 105, in from_dict
    return cls(**{
TypeError: __init__() got an unexpected keyword argument 'member'

✨ Allowing PIL image to get return in command

Tasks

Implement the support of Image type from the Pillow library.
You might want to use the standard IO and not saving the image afile.

from PIL import Image

...

@Client.command()
async def image_example(self) -> Image:
    img = Image.new("RGBA", (200, 100), "white")
    ...
    
    # returning a single image
    return img
@Client.command()
async def image_example(self) -> Message:
    img = Image.new("RGBA", (200, 100), "white")
    ...

    # Sending the image within a custom message, as a file
    return Message(..., file=img)

πŸ› Sphinx TypeError in release

Describe the bug
Release variable is currently assigned a VersionInfo object, but requires a string.

To Reproduce
Steps to reproduce the behavior:

  1. Run "make html"

Expected behavior
Documentation builds properly

Screenshots
Screen Shot 2021-10-06 at 11 53 01 PM

Desktop (please complete the following information):

  • OS: macOS M1

πŸ› Support for duplicates event

The current cog system does not support an event to be called within multiples cogs.

File system

- cogs
   - yt_statistics.py
- bot.py

bot.py

class Bot(Client):

    ...

    @Client.event
    async def on_ready(self):
        print(
            "       _____       _ _            _____     _",
            " _____|     |___ _| |_|___ ___   | __  |___| |_",
            "|     |   --| . | . | |   | . |  | __ -| . |  _|",
            "|_|_|_|_____|___|___|_|_|_|_  |  |_____|___|_|",
            "                          |___|" "",
            sep="\n",
        )

YtStatistics

class YtStatistics(commands.Cog):

    def __init__(self, client: Bot):
        self.client = client

    @Client.event
    async def on_ready(self):
        task = TaskScheduler(self.client)

        @task.loop(seconds=2)
        async def update_channels():
            print("Updating channels...")

        update_channels.start()


setup = YtStatistics

Raises

pincer.exceptions.InvalidEventName: The event on_ready has already been registered or is not a valid event name.

This may be improved by forwarding every event of the same name one after an other?

✨ Implement channel editing

Task

Implemented a channel.edit method. In this method you can pass named arguments for the channel attribute(s) that have to change.

Example:

@command()
async def update_channel():
    channel = await Channel.from_id(...)
    
    # the method to add
    await channel.edit(name="foo")

✨ Create COG system

Task

Make a system where commands can be properly structured using several files.

Example

Something in the lines of the following:

main file

from pincer import Client

class Bot(Client):
    @Client.event
    async def on_ready(self):
        self.load_cog("cogs.example")

if __name__ == "__main__":
    Bot(token).run()

cogs/example.py

from pincer import command, Cog

class Example(Cog):
    def __init__(self, client):
        self.client = client

    @command()
     async def example(self):
         ...

def setup(bot):
    Example(bot)

⬆️ Change minimum version to 3.7 instead of 3.6

Describe the bug
Many packages and features do not support Python 3.6 anymore.

  • aiohttp -> >= 3.7

  • typing.Protocol >= 3.7

  • __future__.annotations >= 3.7

  • dataclasses >= 3.7

  • async and await being reserved keywords >= 3.7

  • asyncio is a lot faster from 3.6 to 3.7

  • UTF-8 encoding is default (unless specified) - we wont need # -*- coding: utf-8 -*

  • __getattr__() can be defined for classes

To Reproduce
Either run in Python 3.6 or set your IDE to Python 3.6.

Solution
Change the version to 3.7

πŸ› Middlewares current import is changing the cwd

Describe the bug
When using @client.event, the current working directory is changed to Lib/pincer/middlewares as the chdir is used within the __init__.py of middlewares.

To Reproduce

import os
from pincer import Client


class Bot(Client):

    def __init__(self):
        super().__init__(token='')


print(os.getcwd())

D:\Pincer\pincer\middleware

Expected behavior

D:\Pincer\dev

Desktop (please complete the following information):

os: windows
python: 3.9.6
pincer: 0.6.10

✨ Get Interaction from slash commands

Is your feature request related to a problem? Please describe.
The only way to respond to a slash command is returning a message from the function. This is great for small things but makes it impossible to continue doing a task after you respond.

Describe the solution you'd like
You should be able to pass interaction in the slash command function. We already have something similar for MessageContext but that can be changed a bit.

Implementation Ideas
Typehint interaction
Use a system like flask's url parameter handling where you specify the variable in the decorator.
Get Interaction from ctx (ctx.interaction)

πŸ‘” Name too similar to another project.

Hello, as a faithful supporter of the Piscord project, I think it's not fair to take this name.

Effectively, you could choose another name, because actually, the two names are too similar and can confuse the people who can use Piscord, or redirect the people searching for Pyscord on Piscord.

So, for the better understanding of everyone, can you please change the name of your library not to be too similar to Piscord.

Best regards,
RedsTom.

✨ Support for `tasks.loop`

Task

Make a decorator that transform a asynchronous function to a task object.

@task.loop(minute=30)
async def my_task(self):
    ...

When calling my_task.start() this will register the task to repeat the given amount of time.

πŸ› Within Cogs, events are passing bot instance to `self` instead of the cog instance

Describe the bug
The given example for cog doesn't work as expected:

Traceback (most recent call last):
  File "D:\Pincer\dev\basic_cogs\cogs\on_ready.py", line 11, in on_ready
    f"Started client on {self.client.bot}\n"
AttributeError: 'Bot' object has no attribute 'client'

The method causing the issue:

    @Client.event
    async def on_ready(self):
        print(
            f"Started client on {self.client.bot}\n"
            "Registered commands: " + ", ".join(self.client.chat_commands)
        )

A simple print(type(self) reveals the problem lies in self being the instance of the bot, and not the cog.

πŸ’„ Prettify the Debug Logging

Pincer come with an integrated debug logging mode that can be activated using this line of code

logging.basicConfig(level=logging.DEBUG)

Tho, the current implementation isn't particularity easy to read.

...
DEBUG:pincer.core:Waiting for new event.
DEBUG:pincer.core:Resting heart for 41s
DEBUG:pincer:`payload` middleware has been invoked
DEBUG:websockets.client:< TEXT '{"t":"READY","s":1,"op":0,"d":{"v":9,"user_sett...\"calls\\":[]}]}]}]"]}}' [1051 bytes]
DEBUG:pincer.core:New event received, checking if handler exists for opcode: 0
DEBUG:pincer.core:Event handler found, ensuring async future in current loop.
DEBUG:pincer.core:Waiting for new event.
DEBUG:pincer:`ready` middleware has been invoked
DEBUG:root:1 commands registered.
DEBUG:pincer.core:GET applications/891738511311515708/commands | null
DEBUG:pincer:`payload` middleware has been invoked
DEBUG:pincer.core:Received response for applications/891738511311515708/commands | []
DEBUG:pincer.core:Request has been sent successfully. Returning json response.
DEBUG:pincer.core:POST applications/891738511311515708/guilds/813915317867642910/commands | {"type": 1, "name": "choose", "description": "Description not set", "options": [{"type": 3, "name": "choice", "description": "Description not set", "required": true, "choices": [{"name": "This will be the test value", "value": "Test"}, {"name": "Sample lol", "value": "Sample lol"}, {"name": "Geheh", "value": "Geheh"}]}], "guild_id": 813915317867642910, "default_permission": true}
DEBUG:pincer.core:Received response for applications/891738511311515708/guilds/813915317867642910/commands | {"id": "893854037093527562", "application_id": "891738511311515708", "name": "choose", "description": "Description not set", "version": "894012817345245255", "default_permission": true, "type": 1, "guild_id": "813915317867642910", "options": [{"type": 3, "name": "choice", "description": "Description not set", "required": true, "choices": [{"name": "This will be the test value", "value": "Test"}, {"name": "Sample lol", "value": "Sample lol"}, {"name": "Geheh", "value": "Geheh"}]}]}
DEBUG:pincer.core:Request has been sent successfully. Returning json response.

Tasks

Make the debug mode prettier, while still being toggable by the first line.
Custom coloring, colorama, termcolor or even rich can be used as long as the used features is supported by most OS.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.