Metadata-Version: 2.1
Name: miniirc_extras
Version: 0.3.3
Summary: WIP extensions for miniirc.
Home-page: https://github.com/luk3yx/miniirc_extras
Author: luk3yx
License: MIT
Description: # miniirc_extras
        
        ![Python 3.5+] [![Available on PyPI.]](https://pypi.org/project/miniirc_extras/) [![License: MIT]](https://github.com/luk3yx/miniirc_extras/blob/master/LICENSE.md)
        
        [Python 3.5+]: https://img.shields.io/badge/python-3.5+-blue.svg
        [Available on PyPI.]: https://img.shields.io/pypi/v/miniirc_extras.svg
        [License: MIT]: https://img.shields.io/pypi/l/miniirc.svg
        
        An extension of miniirc ([GitHub](https://github.com/luk3yx/miniirc),
        [GitLab](https://gitlab.com/luk3yx/miniirc)) that adds more features.
        
        Note that miniirc_extras is still in beta and there can and will be breaking
        API changes before v1.0.0, and miniirc_extras may not work with older versions
        of miniirc.
        
        *Some features here may be merged into miniirc eventually.*
        
        ## Loading features
        
        After importing miniirc_extras, features can be loaded with
        `irc.require('feature_name')`, and once loaded can be accessed with
        `irc.feature_name`.
        
        ## Features
        
         - `chans`: Channel mode tracking, must be loaded while miniirc is disconnected.
         - `ensure_connection`: https://github.com/luk3yx/miniirc/issues/15
         - `mp`: *(WIP)* Multiprocessing handlers for miniirc.
         - `testfeature`: Debugging
         - `users`: User tracking, must be loaded while miniirc is disconnected.
         - `_json` *(Proof-of-concept)*: Parse JSON messages.
        
        ### `irc.users`
        
        `irc.users` adds rudimentary user tracking to miniirc.
        
        #### `User` objects
        
        User objects store the current user's information and user-defined data, and
        can be accessed with `irc.users[Hostmask]` or `irc.users['nick']`.
        
        The following items are available in `User` objects:
        
        | Variable      | Description                                               |
        | ------------- | --------------------------------------------------------  |
        | `nick`        | The user's current nickname.                              |
        | `ident`       | The user's current ident.                                 |
        | `host`        | The user's current hostname.                              |
        | `realname`    | The user's `realname`.                                    |
        | `hostmask`    | A `Hostmask` object containing the user's hostmask.       |
        | `raw_hostmask`| A string containing `nick!user@host`.                     |
        | `channels`    | A set containing `Channel` objects for channels the user is currently in. |
        | `account`     | A string containing the user's current NickServ account, or `None` if the user isn't logged in. |
        | `avatar_url`  | The avatar URL of the user. Currently only IRCCloud avatars work. |
        
        You can also set and get items with strings as keys and JSON-compatible objects
        as values.
        
        `User` objects have the following helper functions:
        
        | Function          | Description                                             |
        | ----------------- | ------------------------------------------------------- |
        | `msg(*text)`      | Send a `PRIVMSG` to the user.                           |
        | `me(*text)`       | Send a `CTCP ACTION` (`/me`) to the user.               |
        | `notice(*text)`   | Send a `NOTICE` to the user.                            |
        | `kick(channel, reason='')` | Kicks the user from `channel` (a string or `Channel` object). |
        
        ### `irc.chans`
        
        `irc.chans` adds channel mode tracking on top of `irc.users`. You can get
        channels with `irc.chans['#channel-name']`
        
        #### `Channel` objects
        
        `Channel` objects have the following attributes:
        
        | Variable      | Description                                               |
        | ------------- | --------------------------------------------------------  |
        | `name`        | The name of the channel.                                  |
        | `modes`       | A `ModeList` object containing a list of modes.           |
        | `topic`       | The channel topic.                                        |
        | `users`       | A `set` containing `User` objects for members of this channel. |
        
        #### `ModeList` objects
        
        ModeList objects store a list of modes, and have the following functions:
        
        | Function          | Description                                             |
        | ----------------- | ------------------------------------------------------- |
        | `getbool(mode)`   | Returns `True` if `mode` (a single-character string) is set on the corresponding channel. *Use this for `+i`, `+t`, etc* |
        | `getstr(mode, default=None)` | Return the parameter `mode` was set with, otherwise `default`. *Use this for `+k`, `+l`, etc* |
        | `getset(mode)` | Return a `frozenset` containing all the entries stored in `mode`. If you plan to use this for modes such as `+b`, you may want to run `MODE #channel +b` when the bot/client joins the channel to populate the list. *Use this for `+b`, `+e`, `+o`, `+v`, etc* |
        | `hasstr(mode)` | Returns `True` if `mode` is set with a single parameter, otherwise `False`. |
        | `hasset(mode)` | Equivalent to `len(getset(mode)) > 0`. |
        
        *You can access `ModeList` objects like `dict`s, however this will require
        extra type checking code if you plan to use mypy or another type checker.*
        
        ### `irc.mp`
        
        Multiprocessing handlers. You can create multiprocessing handlers with
        `irc.mp.Handler` and `irc.mp.CmdHandler`. These handlers are called with the
        limited `RestrictedIRC` object (a subclass of `AbstractIRC`) instead of the
        normal `IRC` object.
        
        The following functions/variables work with `RestrictedIRC`:
        
        `active_caps`, `channels`, `connect_modes`, `ctcp`, `debug`, `ident`, `ip`,
        `ircv3_caps`, `isupport`, `me`, `msg`, `nick`, `notice`, `persist`,
        `ping_interval`, `port`, `quit_message`, `quote`, `realname`, `ssl`,
        `verify_ssl`
        
        Trying to modify these variables will result in an `AttributeError` or the set
        operation silently failing.
        
        ## Misc classes
        
        ### AbstractIRC
        
        The `miniirc_extras.AbstractIRC` class provides an easy way to type check `IRC`
        objects without stub files.
        
        ### Hostmask
        
        miniirc_extras adds the abstract-ish class `miniirc_extras.Hostmask`:
        
        ```py
        from miniirc_extras import Hostmask
        
        isinstance('test', Hostmask)                    # False
        isinstance(('nick', 123, 'host'), Hostmask)     # False
        isinstance(('nick', 'user', 'host'), Hostmask)  # True
        
        Hostmask('nick', 'user', 'host') # ('nick', 'user', 'host')
        Hostmask(123456, 'user', 'host') # TypeError
        ```
        
        ## Creating new features
        
        *This API will probably change in the future.*
        
        You can create your own features with `miniirc_extras.Feature`:
        
        ```py
        @miniirc_extras.Feature('feature_name')
        class MyFeature:
            def test_func(self):
                print('test_func called with', self._irc)
        
            def __call__(self):
                print('MyFeature called with', self._irc)
        
            def __init__(self, irc):
                self._irc = irc
        ```
        
        Once registered, you can `require` and use it:
        
        ```py
        irc.require('feature_name')
        
        irc.feature_name()           # MyFeature called with <miniirc.IRC object>
        irc.feature_name.test_func() # test_func called with <miniirc.IRC object>
        ```
        
        ## Miscellaneous functions
        
        Some miscellaneous functions and classes are located in `miniirc_extras.utils`.
        
        | Function          | Description                                             |
        | ----------------- | ------------------------------------------------------- |
        | `DummyIRC(...)`   | A subclass of `miniirc.IRC` that cannot connect to servers. `DummyIRC.__init__` has no required parameters. |
        | `dict_to_tags(tags)` | Converts a dict containing strings and booleans into an IRCv3 tags string. Example: `dict_to_tags({'tag1': True, 'tag2': 'tag-data'})` → `b'@tag1;tag2=tag-data '` |
        | `get_raw_socket(irc)` | Attempts to get the raw socket from an AbstractIRC object. This is not recommended, and under no circumstances should you attempt to receive data using this socket. **Only use this if there is no alternative.** Raises a miniirc_extras.error if no socket can be found. |
        | `tags_to_dict(tag_list, separator = ';')` | Converts a tags list (`tag1;tag2=tag-data`) joined by `separator` into a `dict` containing strings and booleans. |
        | `ircv3_message_parser(msg, *, colon=True)` | The same as `miniirc.ircv3_message_parser`, but also accepts `bytes` and `bytearray`s. The `colon` keyword argument works in the same way as the `colon` keyword argument on `miniirc.Handler`. |
        | `hostmask_to_str(hostmask)` | Converts a `Hostmask` object into a `nick!user@host` string. |
        | `ircv2_message_unparser(cmd, hostmask, tags, args, *, colon=True, encoding='utf-8')` | Converts miniirc-style message data into an IRCv2 message encoded with `encoding` (or `None` to return a `str`). When `colon` is `False`, `args[-1]` will have a colon prepended to it. |
        | `ircv3_message_unparser(cmd, hostmask, tags, args, *, colon=True, encoding='utf-8')` | The same as `ircv2_message_unparser`, but tags are added. |
        | `namedtuple(...)` | Alias for `collections.namedtuple` on Python 3.7+, otherwise a wrapper that adds `defaults` and `module` keyword arguments. |
        | `VersionInfo(major=0, minor=0, micro=0, releaselevel='final', serial=0)` | A `namedtuple` similar to `type(sys.version_info)`. |
        
        *Note that `dict_to_tags` and `tags_to_dict` are available in miniirc as
        internal functions, however they can and will change.*
        
        ### `miniirc_extras.utils.irc_from_url`
        
        Allows you to create `IRC` objects from URLs, for example
        `irc_from_url('irc://nick@ssl-server.example/#channel1,#channel2')` will create
        an `IRC` object with the nickname `nick`. Any keyword arguments passed to
        `irc_from_url` are sent to `IRC()`.
        
        ### `miniirc_extras.utils.HandlerGroup`
        
        Allows you to create a group of handlers and apply them in bulk to `IRC`
        objects.
        
        | Method            | Description                                             |
        | ----------------- | ------------------------------------------------------- |
        | `Handler(...)`    | Adds a `Handler` to the group, uses the same syntax as `irc.Handler`. |
        | `CmdHandler(...)`    | Adds a `CmdHandler` to the group, uses the same syntax as `irc.CmdHandler`. |
        | `add_to(irc_or_group)` | Adds all the handlers in this group to an IRC object or another handler group. |
        | `copy()`          | Returns another handler group with the same handlers as this one. |
        
        ### `miniirc_extras.utils.numerics`
        
        An `Enum` of most of the IRC numerics in [RFC 1459], [RFC 2812], and
        [modern.ircdocs.horse](https://modern.ircdocs.horse/#numerics). See
        `miniirc_extras/_numerics.py` for a list of
        numerics and their names.
        
        Example:
        ```py
        import miniirc
        from miniirc_extras.utils import numerics
        
        @miniirc.Handler(numerics.RPL_WELCOME, colon=False)
        def handler(irc, hostmask, args):
            print('Connected to IRC!')
        ```
        
        Another example:
        ```py
        >>> from miniirc_extras.utils import numerics
        >>> numerics.RPL_ISUPPORT
        <numerics.RPL_ISUPPORT: 0​0​5>
        >>> numerics['RPL_MOTD']
        <numerics.RPL_MOTD: 372>
        >>> numerics(465)
        <numerics.ERR_YOUREBANNEDCREEP: 465>
        >>> numerics('422')
        <numerics.ERR_NOMOTD: 422>
        >>> str(numerics.RPL_YOURHOST)
        '002'
        ```
        
        ### `miniirc_extras.aioirc`
        
        An asyncio-oriented version of `miniirc.IRC`. Example:
        
        ```py
        import asyncio, time
        from miniirc_extras import aioirc
        
        irc = aioirc.AsyncIRC(ip, 6697, nickname, '#botwar', auto_connect=False)
        
        @irc.Handler('PRIVMSG', colon=False)
        def handle_privmsg(irc, hostmask, args):
            if args[0] == '#botwar' and args[1] == '>thread_test':
                irc.msg(args[0], '[Thread] Waiting 1 second...')
                time.sleep(1)
                irc.msg(args[0], '[Thread] Done!')
        
        @irc.Handler('PRIVMSG', colon=False)
        async def handle_privmsg(irc, hostmask, args):
            if args[0] == '#botwar' and args[1] == '>coro_test':
                await irc.msg(args[0], '[Coroutine] Waiting 1 second...')
                await asyncio.sleep(1)
                await irc.msg(args[0], '[Coroutine] Done!')
        
        if __name__ == '__main__':
            irc.connect()
            asyncio.get_event_loop().run_forever()
        ```
        
        This probably doesn't need to be used unless asyncio-based libraries need to be
        used.
        
        ### `miniirc_extras.formatting`
        
        Text formatting. Inspired by [ircmessage](https://pypi.org/project/ircmessage/).
        
        #### `colours`/`colors` enum
        
        The `colours` (or `colors`) enum contains colours and their corresponding code.
        Do not use these to format text, instead use the below `style` and `colorize`
        functions.
        
        #### `Styler` objects
        
        Styler objects are callables that apply IRC formatting to strings.
        
        ```py
        miniirc_extras.formatting.Styler(fg=None, bg=None, *,
                bold: bool = False, italics: bool = False, underline: bool = False,
                reverse_colour: bool = False, strikethrough: bool = False,
                spoiler: bool = False, monospace: bool = False, reset: bool = True)
        ```
        
        *Note that `Styler` accepts both `reverse_colour` and `reverse_color`.*
        
        `fg` and `bg` can be strings or values from the aforementioned `Enum`.
        
        The parameters passed to `__init__` are available as attributes on the object,
        for example `styler.bold`.
        
        Setting `reset` to `False` is not recommended, as when enabled it only resets
        any changed formatting.
        
        For cleaner code, you can also use
        `miniirc_extras.formatting.style(text, fg=None, ...)`.
        
        **Example:**
        
        ```py
        from miniirc_extras import formatting
        
        styler = formatting.Styler('red', bold=True, monospace=True)
        msg = styler('Test message')
        print(styler.fg)    # <colours.red: 04>
        print(styler.fg)    # None
        print(styler.bold)  # True
        print(repr(msg))    # '\x11\x02\x0304Test message\x0399\x02\x11'
        
        msg2 = formatting.style('Test message', 'red', bold=True, monospace=True)
        assert msg == msg2 # No error
        
        print(repr(formatting.unstyle(msg))) # 'Test message'
        ```
        
        #### "Lightweight" stylers
        
        There are a number of predefined `Styler`s that are more efficient (if you are
        only adding one style):
        
        ```py
        bold            = Styler(bold=True)
        italics         = Styler(italics=True)
        italic          = italics
        underline       = Styler(underline=True)
        reverse_colour  = Styler(reverse_colour=True)
        reverse_color   = reverse_colour
        strikethrough   = Styler(strikethrough=True)
        monospace       = Styler(monospace=True)
        spoiler         = Styler(spoiler=True)
        ```
        
        Lightweight stylers are subclassed from `Styler` and will run slightly faster,
        provided you are only changing one style.
        
        You can also use `miniirc_extras.formatting.colorize(text, fg)` (or
        `miniirc_extras.formatting.colourise(text, fg)`) if you are only changing the
        foreground colour/color for a similarly small speed improvement.
        
        *Note that `formatting.style(text, 'red', bold=True)` is recommended over
        `formatting.bold(formatting.colorize(text, 'red'))`, as it is more readable
        and probably faster.*
        
        ### Deprecated functions.
        
        These functions still work for now but will probably be removed from
        miniirc_extras v1.0.0:
        
        #### `miniirc_extras.DummyIRC`
        
        Now called `miniirc_extras.utils.DummyIRC`.
        
        #### `miniirc_extras.VersionInfo`
        
        Now called `miniirc_extras.utils.VersionInfo`.
        
        #### Other planned breaking changes
        
         - To coincide with miniirc v2.0.0, all functions that take a `colon` keyword
            argument here will default to `False` (instead of `True`). This may change
            in miniirc_extras v1.0.0 instead.
         - If Python 3.5 is obsolete by the time miniirc_extras v1.0.0 is released,
            support may be dropped.
        
        [RFC 1459]: https://tools.ietf.org/html/rfc1459
        [RFC 2812]: https://tools.ietf.org/html/rfc2812
        
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.5
Description-Content-Type: text/markdown
