Example #1
0
    def logger(self) -> Logger:
        """get the default logger of plugin which will automaticly
        log info into the plugin cache dir

        Returns:
            Logger: Instance of Logger

        Examples:
            ding_dong_plugin = DingDongPlugin()
            ding_dong_plugin.logger.info('log info ...')
        """
        if self._default_logger:
            return self._default_logger

        self._default_logger = get_logger(self.name,
                                          file=os.path.join(
                                              self.cache_dir, 'log.log'))
        assert self._default_logger is not None, 'can not set default logger'

        return self._default_logger
    EventLoginPayload, EventFriendshipPayload, EventHeartbeatPayload,
    EventErrorPayload, FileBox, RoomMemberPayload, RoomPayload,
    RoomInvitationPayload, RoomQueryFilter, FriendshipPayload, ContactPayload,
    MessagePayload, MessageQueryFilter, ImageType, EventType, MessageType,
    Puppet, PuppetOptions, MiniProgramPayload, UrlLinkPayload, get_logger)

from wechaty_puppet.exceptions import (  # type: ignore
    WechatyPuppetConfigurationError, WechatyPuppetError,
    WechatyPuppetGrpcError, WechatyPuppetOperationError,
    WechatyPuppetPayloadError)

from wechaty_puppet_official_account import config
from .official_account import OfficialAccount, OfficialAccountOption
from .schema import OAMessagePayload

logger = get_logger('OfficialAccountPuppet')


@dataclass
class OfficialAccountPuppetOptions(PuppetOptions):
    app_id: Optional[str] = None
    app_secret: Optional[str] = None
    port: Optional[int] = 80


class OfficialAccountPuppet(Puppet):
    def __init__(self, options: Optional[OfficialAccountPuppetOptions]):
        if not options:
            options = OfficialAccountPuppetOptions(
                app_id=config.app_id,
                app_secret=config.app_secret,
Example #3
0
from typing import (Union, Optional, TYPE_CHECKING)
import json

from wechaty.exceptions import WechatyOperationError
from wechaty_puppet import (  # type: ignore
    FriendshipType, FriendshipPayload, get_logger)
# from wechaty.utils import type_check

from ..types import Acceptable
from ..accessory import Accessory

if TYPE_CHECKING:
    from .contact import Contact

log = get_logger('FriendShip')


class Friendship(Accessory, Acceptable):
    """
    Send, receive friend request, and friend confirmation events.

    * 1. send request
    * 2. receive request(in friend event)
    * 3. confirmation friendship(friend event)
    """

    Type = FriendshipType

    def __init__(self, friendship_id: str):
        """
Example #4
0
from .exceptions import (
    WechatyPluginError,
)

if TYPE_CHECKING:
    from .wechaty import (
        Wechaty
    )
    from .user import (
        Room,
        RoomInvitation,
        Friendship,
        Contact,
        Message,
    )
log: logging.Logger = get_logger(__name__)


@dataclass
class WechatyPluginOptions:
    """options for wechaty plugin"""
    name: Optional[str] = None
    metadata: Optional[dict] = None


class PluginStatus(Enum):
    """plugin running status"""
    Running = 0
    Stopped = 1

Example #5
0
from .user import (
    Contact,
    Friendship,
    Message,
    Tag,
    Room,
    Image,
    RoomInvitation,
    MiniProgram,
    Favorite
)
from .utils import (
    qr_terminal
)

log = get_logger('Wechaty')

DEFAULT_TIMEOUT = 300


PuppetModuleName = str


@dataclass
class WechatyOptions:
    """
    WechatyOptions instance
    """
    name: Optional[str] = None
    puppet: Optional[Union[PuppetModuleName, Puppet]] = None
    puppet_options: Optional[PuppetOptions] = None
Example #6
0
import logging
import os
from typing import Optional, Union

from apscheduler.schedulers.asyncio import AsyncIOScheduler
from wechaty import Wechaty, Contact, UrlLink
from wechaty.user import Message, Room
from wechaty_puppet import ScanStatus, get_logger, FileBox  # type: ignore

from service.msg_service import get_wx_public_article_url_link, get_weather_url_link, get_music_file_url, \
    get_south_north_fund
"""
微信机器人
"""

log: logging.Logger = get_logger('MyBot')


class MyBot(Wechaty):
    """
    listen wechaty event with inherited functions, which is more friendly for
    oop developer
    """
    def __init__(self):
        super().__init__()
        global contact_ids
        global room_ids
        contact_ids = ['wxid_zs0tjy7p1jl922']
        room_ids = ["9680172400@chatroom"]

    async def on_message(self, msg: Message):
Example #7
0
See the License for the specific language governing permissions and
limitations under the License.
"""
from __future__ import annotations

from typing import (
    TYPE_CHECKING,
    Any,
    List,
)
from wechaty_puppet import get_logger

if TYPE_CHECKING:
    from .tag import Tag

log = get_logger('Favorite')


# pylint: disable=R
class Favorite:
    """
    favorite object which handle the url_link content
    """
    def __init__(self, favorite_id: str):
        self.favorite_id = favorite_id

    def get_id(self) -> str:
        """
        get favorite_id
        :return:
        """
Example #8
0
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from __future__ import annotations

from typing import (
    Type, )

from wechaty_puppet import (  # type: ignore
    FileBox, ImageType, get_logger)

from ..accessory import Accessory

log = get_logger('Image')


class Image(Accessory):
    """
    User Image class
    """
    def __str__(self):
        return 'Image<%d>' % self.image_id

    def __init__(
        self,
        image_id: str,
    ) -> None:
        """
        :param image_id:
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import os
# TODO: need to fix error -> found module but no type hints or library stubs
from wechaty_puppet import get_logger   # type: ignore

logger = get_logger('WechatyPuppetServiceConfig')


def get_token():
    """
    get the token from environment variable
    """
    return os.environ.get('WECHATY_PUPPET_SERVICE_TOKEN', None) or \
        os.environ.get('TOKEN', None) or \
        os.environ.get('token', None) or None


def get_endpoint():
    """
    get the endpoint from environment variable
    """
Example #10
0
    get_logger,
    EventMessagePayload)
from wechaty_puppet.schemas.types import (  # type: ignore
    MessagePayload,
    ContactPayload,
    FriendshipPayload,
    ImageType,
    RoomInvitationPayload,
    RoomPayload,
    RoomMemberPayload
)
from wechaty_puppet_mock.exceptions import WechatyPuppetMockError
from wechaty_puppet_mock.mock.mocker import Mocker, MockerResponse


log = get_logger('PuppetMock')


@dataclass
class PuppetMockOptions(PuppetOptions):
    """options for puppet mock"""
    mocker: Optional[Mocker] = None


# pylint: disable=too-many-public-methods
class PuppetMock(Puppet):
    """mock for puppet"""
    def __init__(self, options: PuppetMockOptions, name: str = 'puppet-mock'):
        super().__init__(options, name)

        if not options.mocker:
Example #11
0
#!/usr/bin/python
# -*- coding:utf-8 -*-
"""plugin of groupchat assistant, including tagging, member manager,
help system and timed task plugin"""
from wechaty import Wechaty
from wechaty.plugin import WechatyPlugin
from wechaty_puppet import get_logger

from tagging_plugin import Tagging
from timed_task_plugin import TimedTask
from member_manager_plugin import MemberManager
from help_plugin import HelpSystem
from help_modules.example_dict import groupchat_bot_help_zh

log = get_logger('Groupchat Assistant')


class GroupchatAssistant(WechatyPlugin):
    """groupchat assistant plugin"""
    @property
    def name(self) -> str:
        """get the name of plugin"""
        return 'groupchat assistant'

    def __init__(self, data_path='database.db', config_path='config.pkl'):
        """params:
            data_path: path of database file,
            config_path: path of database config file, which
                         contains auto-created information"""
        self.plugins = [
            Tagging(data_path, config_path),
Example #12
0
import re
from typing import Union
import pickle

from wechaty import Message, Contact, Room
from wechaty.plugin import WechatyPlugin
from wechaty_puppet import get_logger

from data.database import Database
from data.data_transfer import DataTransfer
from tagging_modules.question_answering import QuestionAnswering
from tagging_modules.tag_controller import TagController
from tagging_modules.display import Display
from utils.extract_msg import split_quote_and_mention

log = get_logger('Tagging plugin')


class Tagging(WechatyPlugin):
    """tagging system plugin for bot"""
    @property
    def name(self) -> str:
        """get the name of the plugin"""
        return 'tagging'

    def __init__(self, data_path='database.db', config_path='config.pkl'):
        """params:
            data_path: path of database file,
            config_path: path of database config file, which
                         contains auto-created information"""
        self.data_path = data_path
limitations under the License.
"""
from __future__ import annotations

from typing import TYPE_CHECKING
from dataclasses import asdict

from wechaty import Accessory
from wechaty_puppet import MiniProgramPayload, get_logger   # type: ignore
from wechaty.utils import default_str

if TYPE_CHECKING:
    from wechaty.user import Message


log = get_logger('MiniProgram')


class MiniProgram(Accessory):
    """
    mini_program object which handle the url_link content
    """
    def __init__(self, payload: MiniProgramPayload):
        """
        initialization for mini_program
        :param payload:
        """
        log.info('MiniProgram created')
        self._payload: MiniProgramPayload = payload

    @classmethod
import json
from datetime import datetime
from dataclasses import dataclass
from wechaty_puppet import (  # type: ignore
    ContactPayload, RoomPayload, MessagePayload, Puppet, get_logger, EventType,
    FileBox, MessageType)
from wechaty import (  # type: ignore
    Contact, Room, Message)

if TYPE_CHECKING:
    from wechaty import Contact, Wechaty

from wechaty_puppet_mock.mock.environment import EnvironmentMock
from wechaty_puppet_mock.exceptions import WechatyPuppetMockError

log = get_logger('Mocker')


@dataclass
class MockerResponse:
    """this is the common data-structure for mocker"""
    type: int
    payload: str


class Mocker(AsyncIOEventEmitter):
    """mock fake data"""
    def __init__(self):
        super().__init__()
        self.id: str = str(uuid4())
    EventType,
    MessageType,
    Puppet,
    PuppetOptions,
    MiniProgramPayload,
    UrlLinkPayload,

    get_logger
)

from .config import (
    WECHATY_PUPPET_PADPLUS_ENDPOINT,
    WECHATY_PUPPET_PADPLUS_TOKEN
)

log = get_logger('PadPlusPuppet')


def _map_message_type(message_payload: MessagePayload) -> MessagePayload:
    """
    get messageType value which is ts-wechaty-puppet type from hostie server,
        but is MessageType. so we should map it to MessageType from chatie-grpc
    target MessageType Enum:
        MESSAGE_TYPE_UNSPECIFIED  = 0;

       MESSAGE_TYPE_ATTACHMENT   = 1;
       MESSAGE_TYPE_AUDIO        = 2;
       MESSAGE_TYPE_CONTACT      = 3;
       MESSAGE_TYPE_EMOTICON     = 4;
       MESSAGE_TYPE_IMAGE        = 5;
       MESSAGE_TYPE_TEXT         = 6;
Example #16
0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import os
import re
from typing import (
    Optional, )

from wechaty_puppet import (  # type: ignore
    FileBox, get_logger)

log = get_logger('Config')

# log.debug('test logging debug')
# log.info('test logging info')

_FILE_PATH = os.path.dirname(os.path.realpath(__file__))
DATA_PATH = os.path.realpath(os.path.join(
    _FILE_PATH,
    '../data',
), )


def global_exception_handler(exception: Exception) -> None:
    """
    handle the global exception
    :param exception: exception message
Example #17
0
from wechaty_puppet.watch_dog import WatchdogFood, Watchdog  # type: ignore

from .utils import (qr_terminal)

from .user import (Contact, Friendship, Message, Tag, Room, Image,
                   RoomInvitation, MiniProgram, Favorite, ContactSelf)

from .plugin import (WechatyPlugin, WechatyPluginManager)

from .exceptions import (  # type: ignore
    WechatyStatusError, WechatyConfigurationError, WechatyOperationError,
)

from .utils import timestamp_to_date

log: logging.Logger = get_logger('Wechaty')

DEFAULT_TIMEOUT = 300

PuppetModuleName = str


@dataclass
class WechatyOptions:
    """
    WechatyOptions instance
    """
    name: Optional[str] = None
    puppet: Optional[Union[PuppetModuleName, Puppet]] = None
    puppet_options: Optional[PuppetOptions] = None
                                             MatcherOption, RoomMatcher,
                                             MessageMatcher, ContactMatcher)

from wechaty_plugin_contrib.exception import (WechatyPluginConfigurationError)


@dataclass
class RoomInviterOptions(WechatyPluginOptions):
    # add rules to the specific Matcher
    rules: Dict[MessageMatcher,
                Union[List[RoomMatcher],
                      RoomMatcher]] = field(default_factory=dict)
    welcome: str = field(default_factory=str)


logger = get_logger('RoomInviterPlugin')


class RoomInviterPlugin(WechatyPlugin):
    def __init__(self, options: RoomInviterOptions):
        super().__init__(options)
        if not options or not options.rules:
            raise ValueError('options is required, please add matcher rules')

        self.rules: Dict[MessageMatcher, List[RoomMatcher]] = {}
        for matcher, room_obj in options.rules.items():
            if not room_obj:
                raise ValueError(
                    f'matcher<{matcher}> can not match the target room')
            if isinstance(room_obj, RoomMatcher):
                self.rules[matcher] = [room_obj]
Example #19
0
    FileBox, MessagePayload, MessageQueryFilter, MessageType, get_logger)

from wechaty.exceptions import WechatyPayloadError, WechatyOperationError
from wechaty.utils import timestamp_to_date

from ..accessory import Accessory
from .mini_program import MiniProgram
# TODO -> remove Sayable interface temporary
# from ..types import Sayable

from .contact import Contact
from .url_link import UrlLink
from .image import Image
from .room import Room

log = get_logger('Message')

SUPPORTED_MESSAGE_FILE_TYPES: List[MessageType] = [
    MessageType.MESSAGE_TYPE_ATTACHMENT, MessageType.MESSAGE_TYPE_EMOTICON,
    MessageType.MESSAGE_TYPE_IMAGE, MessageType.MESSAGE_TYPE_VIDEO,
    MessageType.MESSAGE_TYPE_AUDIO
]


# pylint: disable=R0904,R0903
class Message(Accessory[MessagePayload]):
    """
    All of wechaty messages will be encapsulated as a Message object.

    you can get all of message attribute through publish method.
    """
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from __future__ import annotations

from typing import Union, List
import json
from datetime import datetime
from wechaty_puppet import RoomInvitationPayload, get_logger  # type: ignore
from .contact import Contact
from ..types import Acceptable
from ..accessory import Accessory

log = get_logger('RoomInvitation')


class RoomInvitation(Accessory, Acceptable):
    """
    Room Invitation
    """
    def __init__(self, room_invitation_id: str):
        """
        initialization
        """
        if self.puppet is None:
            raise Exception(
                'RoomInvitation class can not be instanciated directly!')
        self.invitation_id: str = room_invitation_id
        log.info('__init__ () <%s>', self)
Example #21
0
    TypeVar,
    Generic,
)

from wechaty_puppet import (
    get_logger,
    Puppet,
)

from wechaty.exceptions import WechatyAccessoryBindingError

# pylint:disable=R0401
if TYPE_CHECKING:
    from .wechaty import Wechaty

log = get_logger('Accessory')

PayloadType = TypeVar('PayloadType')


class Accessory(Generic[PayloadType]):
    """
    Translate the function from TypeScript to Python
    See: https://github.com/wechaty/wechaty/blob/master/src/accessory.ts
    """

    _puppet: Optional[Puppet] = None
    _wechaty: Optional[Wechaty] = None

    abstract: bool = True
Example #22
0
"""
UrlLink for Contact Message
"""
from __future__ import annotations

from typing import (
    Type,
    Union
)
import requests
from lxml import etree  # type: ignore
from wechaty_puppet import UrlLinkPayload, get_logger  # type: ignore

log = get_logger('UrlLink')


class UrlLink:
    """
    url_link object which handle the url_link content
    """

    def __init__(
        self,
        payload: UrlLinkPayload,
    ):
        """
        initialization
        :param payload:
        """
        self.payload: UrlLinkPayload = payload
Example #23
0
from typing import Any, Optional
from dataclasses import dataclass

from diskcache import Cache
from wechaty_puppet import (get_logger, WechatyPuppetOperationError)
from .schema import (OAMessagePayload, OAContactPayload, AccessTokenPayload)


@dataclass
class DataStoreOption:
    cache_dir: str = os.path.join(os.getcwd(), '.wechaty',
                                  'wechaty-puppet-official-account',
                                  'data_cache')


logger = get_logger('DataStore')


class DataStore:
    """
    store the payload with domain
    """
    def __init__(self, option: Optional[DataStoreOption] = None):
        """init the payload directory"""
        if not option:
            option = DataStoreOption()

        logger.info(f'init DataStore instance <{option}>')
        self.option: DataStoreOption = option

        if not os.path.exists(self.option.cache_dir):
Example #24
0
                            EventHeartbeatPayload, EventReadyPayload,
                            ScanStatus)

from .exceptions import (
    WechatyPluginError, )

if TYPE_CHECKING:
    from .wechaty import (Wechaty)
    from .user import (
        Room,
        RoomInvitation,
        Friendship,
        Contact,
        Message,
    )
log: Logger = get_logger(__name__)


def _check_local_port(port: int) -> bool:
    """
    check if the local port is in use
    Args:
        port (int): port

    Return:
        return True if the local port is valid, otherwise False

    Examples:
        >>> assert _check_local_port(5000)

    """
Example #25
0
from pyee import AsyncIOEventEmitter  # type: ignore
# from wechaty_puppet import RoomMemberPayload
from wechaty.exceptions import WechatyOperationError, WechatyPayloadError
from wechaty_puppet import (  # type: ignore
    FileBox, RoomQueryFilter, RoomMemberQueryFilter, RoomPayload, get_logger)
# from wechaty.utils import type_check
from ..accessory import Accessory
from ..config import AT_SEPARATOR

if TYPE_CHECKING:
    from .contact import Contact
    from .url_link import UrlLink
    from .mini_program import MiniProgram
    from .message import Message

log = get_logger('Room')


class Room(Accessory[RoomPayload]):
    """
    All wechat rooms(groups) will be encapsulated as a Room.
    """
    _pool: Dict[str, 'Room'] = defaultdict()

    def __init__(self, room_id: str) -> None:
        """docs"""
        super().__init__()

        self.room_id = room_id

    _event_stream: AsyncIOEventEmitter = AsyncIOEventEmitter()
Example #26
0
from typing import (
    Dict,
    # Optional,
    Union,
    TYPE_CHECKING)

from collections import defaultdict
from wechaty_puppet import get_logger  # type: ignore
from ..accessory import (
    Accessory, )

if TYPE_CHECKING:
    from .contact import Contact
    from .favorite import Favorite

log = get_logger('Tag')


class Tag(Accessory):
    """
    tag object which handle the url_link content
    """
    _pool: Dict[str, 'Tag'] = defaultdict()

    tag_id: str

    def __init__(
        self,
        tag_id: str,
    ) -> None:
        """
Example #27
0
"""
config unit test
"""
from typing import (
    Any,
    # Dict,
    Iterable,
)
from wechaty_puppet import get_logger  # type: ignore

import pytest  # type: ignore

# pylint: disable=C0103
log = get_logger('ConfigTest')

# pylint: disable=redefined-outer-name


# https://stackoverflow.com/a/57015304/1123955
@pytest.fixture(name='data', scope='module')
def fixture_data() -> Iterable[str]:
    """ doc """
    yield 'test'


def test_config(data: Any, ) -> None:
    """
    Unit Test for config function
    """
    print(data)
class AutoReplyRule:
    keyword: str
    reply_content: Union[str, FileBox, Contact, Message, MiniProgram]


@dataclass
class AutoReplyOptions(WechatyPluginOptions):
    rules: List[AutoReplyRule] = field(default_factory=list)
    matchers: List[Matcher] = field(default_factory=list)

    # add rules to the specific Matcher
    matcher_rules: Dict[Matcher,
                        List[AutoReplyRule]] = field(default_factory=dict)


logger = get_logger('AutoReplyPlugin')


class AutoReplyPlugin(WechatyPlugin):
    def __init__(self, options: AutoReplyOptions):
        super().__init__(options)

        if not options.rules and not options.matcher_rules.values():
            raise WechatyPluginConfigurationError(
                'rules not found in rules/matcher_rules')

        # if there is no matcher, it should be apply to all of target
        if not options.matchers:
            options.matchers = [
                RoomMatcher(True),
                MessageMatcher(True),
Example #29
0
from wechaty.config import PARALLEL_TASK_NUM
from wechaty.utils.async_helper import gather_with_concurrency

from ..accessory import Accessory

if TYPE_CHECKING:
    # pytype: disable=pyi-error
    from .tag import Tag
    # pytype: disable=pyi-error
    from .message import Message
    # pytype: disable=pyi-error
    from .url_link import UrlLink
    from .mini_program import MiniProgram
    

log = get_logger('Contact')


# pylint:disable=R0904
class Contact(Accessory[ContactPayload], AsyncIOEventEmitter):
    """
    contact object
    """
    _pool: Dict[str, 'Contact'] = {}

    def __init__(self, contact_id: str):
        """
        Init Contact object with id which will not be cached,

        so we suggest that you use load method to get a cached contact object
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from __future__ import annotations
import os
import asyncio
from typing import List, Optional

from wechaty import Wechaty, Room, RoomQueryFilter
from wechaty.user.contact import Contact
from wechaty_puppet import get_logger

log = get_logger('RoomMemberBot')


class MyBot(Wechaty):
    """oop wechaty bot, all of your entrypoint should be done here.
    """
    async def on_ready(self, payload):
        """all of initialization jobs shoule be done here.
        """
        log.info('ready event<%s>', payload)
        # search contact and add them to the specific room
        room: Optional[Room] = await self.Room.find(query=RoomQueryFilter(topic='room-topic-name'))
        if not room:
            return
        contacts: List[Contact] = await self.Contact.find_all()