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

rules: refactoring of Sopel's rule system to an object-oriented approach #1873

Merged
merged 20 commits into from
Jun 11, 2020

Conversation

Exirel
Copy link
Contributor

@Exirel Exirel commented May 25, 2020

Description

I replaced the function-based rule management of Sopel by a more object-oriented approach:

  • before: callables defined in plugins would be registered "as-is" and manipulated as such, without a typed interface
  • now: callables defined in plugins are used to generate "Rule" objects, which have a clear interface

sopel.bot.Sopel

In this PR, the bot's dispatch and triggered rule execution are modified to use the new rule system. It delegates the callable registration to the Manager (see below), and deal less with callables, and more with higher objects, such as "Plugin" and "Rule".

I've kept the Sopel.call method for now, because the URL Callbacks system still uses it. However, I plan on changing that, so that URL Callbacks will be part of the new Rule system, to be unified under the same mechanisms (and I've to resist the urge to say "rules" here because it could be confusing). It is possible to do that either in Sopel 7.1 or Sopel 7.2. My biggest concern at the moment is to see if these changes won't clash with the ongoing work in #1805 (spoiler: they probably do).

sopel.plugins.rules.Manager

The Manager class is the entry-point to the Rule-based management system: you can register rules, commands, nick commands, and action commands. It is used by sopel.bot.Sopel to manage all of that for the bot.

There are 3 key concept:

  • register rules
  • match a pretrigger
  • unregister rules

The manager will store/remove rules based on their plugin, so it's now easier to add/remove a plugin: there is no "is this the right callable?" shenanigan anymore. Beside, the regexes part is totally absent from the mix, because Sopel doesn't care for that when adding or removing a plugin. The regex is not part of a Rule's identity.

sopel.plugins.rules.AbstractRule (and subclasses)

The AbstractRule defines the new rule interface: what you can ask of it, how you can work with it, and how you can manipulate it. See its docstring for more information about the relevant data it contains and manage.

The key point for me was to add a classmethod named from_callable, which ensure that it's always possible to create a rule object from a plugin callable. I believe plugin author shouldn't have to care about all the fancy tricks we use internally to write a plugin. Functions are fine, decorators work great, and I don't plan on changing that anytime soon.

However, I needed to switch the focus of the bot from "function" and "regexes" to a more semantic approach: rules, commands, labels, plugins. These are the key components of the system.

Also, I totally added the sopel.module.label decorator, so now Rules have labels (see below for more).

sopel.module.label

Commands (and nick/action commands) have a name (and aliases), so it was quite easy to disable them or enable them per-channel: all you had to do was using .help to know the list of commands, and you could then disable them. Easy peasy. Sadly, anoynomous rules required you to know the exact name of the function for the same purpose, which is bonkers. Also it was a pain to debug things or to read the logs.

Now it's easier: rules have a label now. By default, it is derived from their handler's name (the function's __name__ attribute that is). But because it's not always what you want, you can use a new decorator for that:

# file recorder.py
from sopel import module

@module.rule(r'.*')
@module.label('logall')
def dope_rule_to_log_them_all(bot, trigger):
    # you can now record everything!
    pass

Then, when loading the rule (using Rule.from_callable), doing str(rule) will outpot something like that:

<Rule recorder.logall (1)>

In that case, the recorder is the plugin name, logall the rule's label, and 1 is the number of regexes this rule object uses.

Output Example

Because I implemented the magic method __str__ for all rules, this is now what the startup logs looks like, with log-level set to DEBUG (note how easier to read it is now):

Sopel 7.1.0.dev0 (running on Python 3.6.8)
https://sopel.chat/

Loaded config file: /home/fstrzelecki/.sopel/freenode.cfg
[2020-05-26 10:42:33,693] sopel.bot            INFO     - Loading plugins...
[2020-05-26 10:42:33,699] sopel.plugins.rules  DEBUG    - Rule registered: <Rule find.collectlines (1)>
[2020-05-26 10:42:33,700] sopel.plugins.rules  DEBUG    - Rule registered: <Rule find.part_cleanup (1)>
[2020-05-26 10:42:33,700] sopel.plugins.rules  DEBUG    - Rule registered: <Rule find.quit_cleanup (1)>
[2020-05-26 10:42:33,700] sopel.plugins.rules  DEBUG    - Rule registered: <Rule find.kick_cleanup (1)>
[2020-05-26 10:42:33,700] sopel.plugins.rules  DEBUG    - Rule registered: <Rule find.findandreplace (1)>
[2020-05-26 10:42:33,700] sopel.bot            INFO     - Plugin loaded: find
[2020-05-26 10:42:34,316] sopel.plugins.rules  DEBUG    - Command registered: <Command reddit.setsafeforwork [setsfw]>
[2020-05-26 10:42:34,317] sopel.plugins.rules  DEBUG    - Command registered: <Command reddit.getsafeforwork [getsfw]>
[2020-05-26 10:42:34,319] sopel.plugins.rules  DEBUG    - Command registered: <Command reddit.setspoilerfree [setspoilfree]>
[2020-05-26 10:42:34,320] sopel.plugins.rules  DEBUG    - Command registered: <Command reddit.getspoilerfree [getspoilfree]>
[2020-05-26 10:42:34,320] sopel.plugins.rules  DEBUG    - Rule registered: <Rule reddit.reddit_slash_info (1)>
[2020-05-26 10:42:34,320] sopel.plugins.rules  DEBUG    - Command registered: <Command reddit.subreddit []>
[2020-05-26 10:42:34,321] sopel.plugins.rules  DEBUG    - Command registered: <Command reddit.redditor []>
[2020-05-26 10:42:34,321] sopel.bot            DEBUG    - URL Callback added "image_info" for URL pattern "re.compile('https?://i\\.redd\\.it/\\S+')"
[2020-05-26 10:42:34,321] sopel.bot            DEBUG    - URL Callback added "video_info" for URL pattern "re.compile('https?://v\\.redd\\.it/([\\w-]+)')"
[2020-05-26 10:42:34,321] sopel.bot            DEBUG    - URL Callback added "rpost_info" for URL pattern "re.compile('https?://redd\\.it/([\\w-]+)')"
[2020-05-26 10:42:34,321] sopel.bot            DEBUG    - URL Callback added "rpost_info" for URL pattern "re.compile('https?://(?:www\\.|old\\.|pay\\.|ssl\\.|[a-z]{2}\\.)?reddit\\.com/r/\\S+?/comments/([\\w-]+)(?:/[\\w%]+)?/?$')"
[2020-05-26 10:42:34,321] sopel.bot            DEBUG    - URL Callback added "comment_info" for URL pattern "re.compile('https?://(?:www\\.|old\\.|pay\\.|ssl\\.|[a-z]{2}\\.)?reddit\\.com/r/\\S+?/comments/\\S+?/\\S+?/([\\w-]+)')"
[2020-05-26 10:42:34,321] sopel.bot            DEBUG    - URL Callback added "auto_redditor_info" for URL pattern "re.compile('https?://(?:www\\.|old\\.|pay\\.|ssl\\.|[a-z]{2}\\.)?reddit\\.com/u(?:ser)?/([\\w-]+)')"
[2020-05-26 10:42:34,321] sopel.bot            DEBUG    - URL Callback added "auto_subreddit_info" for URL pattern "re.compile('https?://(?:www\\.|old\\.|pay\\.|ssl\\.|[a-z]{2}\\.)?reddit\\.com/r/([\\w-]+)/?$')"
[2020-05-26 10:42:34,321] sopel.bot            INFO     - Plugin loaded: reddit
[2020-05-26 10:42:34,345] sopel.plugins.rules  DEBUG    - Rule registered: <Rule safety.url_handler (1)>
[2020-05-26 10:42:34,345] sopel.plugins.rules  DEBUG    - Command registered: <Command safety.safety []>
[2020-05-26 10:42:34,346] sopel.bot            DEBUG    - Job added "_clean_cache", will run every 86400 seconds
[2020-05-26 10:42:34,346] sopel.bot            INFO     - Plugin loaded: safety
[2020-05-26 10:42:34,364] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.op []>
[2020-05-26 10:42:34,364] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.deop []>
[2020-05-26 10:42:34,364] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.voice []>
[2020-05-26 10:42:34,364] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.devoice []>
[2020-05-26 10:42:34,365] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.kick []>
[2020-05-26 10:42:34,365] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.ban []>
[2020-05-26 10:42:34,365] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.unban []>
[2020-05-26 10:42:34,365] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.quiet []>
[2020-05-26 10:42:34,365] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.unquiet []>
[2020-05-26 10:42:34,366] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.kickban [kb]>
[2020-05-26 10:42:34,366] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.topic []>
[2020-05-26 10:42:34,366] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.tmask []>
[2020-05-26 10:42:34,366] sopel.plugins.rules  DEBUG    - Command registered: <Command adminchannel.showmask []>
[2020-05-26 10:42:34,366] sopel.bot            INFO     - Plugin loaded: adminchannel
[2020-05-26 10:42:34,374] sopel.plugins.rules  DEBUG    - Command registered: <Command currency.cur [currency|exchange]>
[2020-05-26 10:42:34,374] sopel.plugins.rules  DEBUG    - Rule registered: <Rule currency.exchange_re (1)>
[2020-05-26 10:42:34,374] sopel.bot            INFO     - Plugin loaded: currency
[2020-05-26 10:42:34,381] sopel.plugins.rules  DEBUG    - Rule registered: <Rule bugzilla.show_bug (1)>
[2020-05-26 10:42:34,381] sopel.bot            INFO     - Plugin loaded: bugzilla
[2020-05-26 10:42:34,391] sopel.plugins.rules  DEBUG    - Command registered: <Command ip.iplookup [ip]>
[2020-05-26 10:42:34,392] sopel.bot            INFO     - Plugin loaded: ip
[2020-05-26 10:42:34,396] sopel.plugins.rules  DEBUG    - Command registered: <Command calc.c [calc]>
[2020-05-26 10:42:34,396] sopel.bot            INFO     - Plugin loaded: calc
[2020-05-26 10:42:34,402] sopel.plugins.rules  DEBUG    - Command registered: <Command tell.tell [ask]>
[2020-05-26 10:42:34,403] sopel.plugins.rules  DEBUG    - Nick Command registered: <NickCommand tell.tell [ask] (Exibot [])>
[2020-05-26 10:42:34,403] sopel.plugins.rules  DEBUG    - Rule registered: <Rule tell.message (1)>
[2020-05-26 10:42:34,403] sopel.bot            INFO     - Plugin loaded: tell
[2020-05-26 10:42:34,411] sopel.plugins.rules  DEBUG    - Command registered: <Command wiktionary.wt [define|dict]>
[2020-05-26 10:42:34,411] sopel.plugins.rules  DEBUG    - Command registered: <Command wiktionary.ety []>
[2020-05-26 10:42:34,411] sopel.bot            INFO     - Plugin loaded: wiktionary
[2020-05-26 10:42:34,415] sopel.plugins.rules  DEBUG    - Command registered: <Command lmgtfy.lmgtfy [lmgify|gify|gtfy]>
[2020-05-26 10:42:34,416] sopel.bot            INFO     - Plugin loaded: lmgtfy
[2020-05-26 10:42:34,428] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.join []>
[2020-05-26 10:42:34,428] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.tmpjoin []>
[2020-05-26 10:42:34,428] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.part []>
[2020-05-26 10:42:34,428] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.tmppart []>
[2020-05-26 10:42:34,428] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.restart []>
[2020-05-26 10:42:34,429] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.quit []>
[2020-05-26 10:42:34,429] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.say [msg]>
[2020-05-26 10:42:34,429] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.me []>
[2020-05-26 10:42:34,430] sopel.plugins.rules  DEBUG    - Rule registered: <Rule admin.invite_join (1)>
[2020-05-26 10:42:34,430] sopel.plugins.rules  DEBUG    - Rule registered: <Rule admin.hold_ground (1)>
[2020-05-26 10:42:34,430] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.mode []>
[2020-05-26 10:42:34,430] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.set []>
[2020-05-26 10:42:34,430] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.unset []>
[2020-05-26 10:42:34,430] sopel.plugins.rules  DEBUG    - Command registered: <Command admin.save []>
[2020-05-26 10:42:34,430] sopel.bot            INFO     - Plugin loaded: admin
[2020-05-26 10:42:34,431] sopel.plugins.rules  DEBUG    - Rule registered: <Rule find_updates.startup_version_check (1)>
[2020-05-26 10:42:34,431] sopel.bot            DEBUG    - Job added "check_version", will run every 86400 seconds
[2020-05-26 10:42:34,431] sopel.bot            INFO     - Plugin loaded: find_updates
[2020-05-26 10:42:34,435] sopel.plugins.rules  DEBUG    - Command registered: <Command dice.d [dice|roll]>
[2020-05-26 10:42:34,435] sopel.bot            INFO     - Plugin loaded: dice
[2020-05-26 10:42:34,451] sopel.plugins.rules  DEBUG    - Command registered: <Command clock.t [time]>
[2020-05-26 10:42:34,452] sopel.plugins.rules  DEBUG    - Command registered: <Command clock.tz [timez]>
[2020-05-26 10:42:34,453] sopel.plugins.rules  DEBUG    - Command registered: <Command clock.settz [settimezone]>
[2020-05-26 10:42:34,454] sopel.plugins.rules  DEBUG    - Command registered: <Command clock.gettz [gettimezone]>
[2020-05-26 10:42:34,455] sopel.plugins.rules  DEBUG    - Command registered: <Command clock.settimeformat [settf]>
[2020-05-26 10:42:34,456] sopel.plugins.rules  DEBUG    - Command registered: <Command clock.gettimeformat [gettf]>
[2020-05-26 10:42:34,456] sopel.plugins.rules  DEBUG    - Command registered: <Command clock.setchanneltz [setctz]>
[2020-05-26 10:42:34,457] sopel.plugins.rules  DEBUG    - Command registered: <Command clock.getchanneltz [getctz]>
[2020-05-26 10:42:34,458] sopel.plugins.rules  DEBUG    - Command registered: <Command clock.setchanneltimeformat [setctf]>
[2020-05-26 10:42:34,459] sopel.plugins.rules  DEBUG    - Command registered: <Command clock.getchanneltimeformat [getctf]>
[2020-05-26 10:42:34,459] sopel.bot            INFO     - Plugin loaded: clock
[2020-05-26 10:42:34,465] sopel.plugins.rules  DEBUG    - Command registered: <Command wikipedia.w [wiki|wik]>
[2020-05-26 10:42:34,466] sopel.bot            DEBUG    - URL Callback added "mw_info" for URL pattern "re.compile('https?:\\/\\/([a-z]+\\.wikipedia\\.org)\\/wiki\\/((?!File\\:)[^ #]+)#?([^ ]*)')"
[2020-05-26 10:42:34,466] sopel.bot            INFO     - Plugin loaded: wikipedia
[2020-05-26 10:42:34,469] sopel.plugins.rules  DEBUG    - Command registered: <Command xkcd.xkcd []>
[2020-05-26 10:42:34,469] sopel.bot            DEBUG    - URL Callback added "get_url" for URL pattern "re.compile('xkcd.com/(\\d+)')"
[2020-05-26 10:42:34,469] sopel.bot            DEBUG    - URL Callback added "xkcd_main_page" for URL pattern "re.compile('https?://xkcd\\.com/?$')"
[2020-05-26 10:42:34,469] sopel.bot            INFO     - Plugin loaded: xkcd
[2020-05-26 10:42:34,473] sopel.plugins.rules  DEBUG    - Command registered: <Command choose.choose [ch|choice]>
[2020-05-26 10:42:34,473] sopel.bot            INFO     - Plugin loaded: choose
[2020-05-26 10:42:34,478] sopel.plugins.rules  DEBUG    - Command registered: <Command remind.in []>
[2020-05-26 10:42:34,478] sopel.plugins.rules  DEBUG    - Command registered: <Command remind.at []>
[2020-05-26 10:42:34,478] sopel.bot            DEBUG    - Job added "remind_monitoring", will run every 2 seconds
[2020-05-26 10:42:34,478] sopel.bot            INFO     - Plugin loaded: remind
[2020-05-26 10:42:34,479] sopel.plugins.rules  DEBUG    - Command registered: <Command tld.tld []>
[2020-05-26 10:42:34,480] sopel.bot            INFO     - Plugin loaded: tld
[2020-05-26 10:42:34,494] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.shrug []>
[2020-05-26 10:42:34,494] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.happy []>
[2020-05-26 10:42:34,495] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.tableflip [tflip]>
[2020-05-26 10:42:34,495] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.unflip []>
[2020-05-26 10:42:34,495] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.lenny []>
[2020-05-26 10:42:34,496] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.rage [anger]>
[2020-05-26 10:42:34,496] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.cry []>
[2020-05-26 10:42:34,496] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.love []>
[2020-05-26 10:42:34,497] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.success [winner]>
[2020-05-26 10:42:34,498] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.confused [wat]>
[2020-05-26 10:42:34,498] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.crazy []>
[2020-05-26 10:42:34,498] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.hungry []>
[2020-05-26 10:42:34,498] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.surprised []>
[2020-05-26 10:42:34,498] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.sick []>
[2020-05-26 10:42:34,498] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.afraid []>
[2020-05-26 10:42:34,498] sopel.plugins.rules  DEBUG    - Command registered: <Command emoticons.worried []>
[2020-05-26 10:42:34,498] sopel.bot            INFO     - Plugin loaded: emoticons
[2020-05-26 10:42:34,500] sopel.bot            DEBUG    - URL Callback added "instaparse" for URL pattern "re.compile('(https?:\\/\\/(?:www\\.){0,1}instagram\\.com\\/([a-zA-Z0-9_\\.]{,30}\\/)?p\\/[a-zA-Z0-9_-]+)')"
[2020-05-26 10:42:34,500] sopel.bot            INFO     - Plugin loaded: instagram
[2020-05-26 10:42:34,502] sopel.plugins.rules  DEBUG    - Command registered: <Command version.version []>
[2020-05-26 10:42:34,502] sopel.plugins.rules  DEBUG    - Rule registered: <Rule version.ctcp_version (1)>
[2020-05-26 10:42:34,502] sopel.plugins.rules  DEBUG    - Rule registered: <Rule version.ctcp_source (1)>
[2020-05-26 10:42:34,503] sopel.plugins.rules  DEBUG    - Rule registered: <Rule version.ctcp_ping (1)>
[2020-05-26 10:42:34,503] sopel.plugins.rules  DEBUG    - Rule registered: <Rule version.ctcp_time (1)>
[2020-05-26 10:42:34,503] sopel.bot            INFO     - Plugin loaded: version
[2020-05-26 10:42:34,505] sopel.plugins.rules  DEBUG    - Command registered: <Command isup.isupinsecure []>
[2020-05-26 10:42:34,505] sopel.plugins.rules  DEBUG    - Command registered: <Command isup.isup []>
[2020-05-26 10:42:34,505] sopel.bot            INFO     - Plugin loaded: isup
[2020-05-26 10:42:34,506] sopel.plugins.rules  DEBUG    - Command registered: <Command py.py []>
[2020-05-26 10:42:34,506] sopel.bot            INFO     - Plugin loaded: py
[2020-05-26 10:42:34,512] sopel.plugins.rules  DEBUG    - Nick Command registered: <NickCommand reload.reload [] (Exibot [])>
[2020-05-26 10:42:34,512] sopel.plugins.rules  DEBUG    - Nick Command registered: <NickCommand reload.update [] (Exibot [])>
[2020-05-26 10:42:34,512] sopel.plugins.rules  DEBUG    - Nick Command registered: <NickCommand reload.load [] (Exibot [])>
[2020-05-26 10:42:34,512] sopel.plugins.rules  DEBUG    - Command registered: <Command reload.reload []>
[2020-05-26 10:42:34,512] sopel.plugins.rules  DEBUG    - Command registered: <Command reload.update []>
[2020-05-26 10:42:34,512] sopel.plugins.rules  DEBUG    - Command registered: <Command reload.load []>
[2020-05-26 10:42:34,512] sopel.bot            INFO     - Plugin loaded: reload
[2020-05-26 10:42:34,518] sopel.plugins.rules  DEBUG    - Command registered: <Command units.temp []>
[2020-05-26 10:42:34,519] sopel.plugins.rules  DEBUG    - Command registered: <Command units.length [distance]>
[2020-05-26 10:42:34,520] sopel.plugins.rules  DEBUG    - Command registered: <Command units.weight [mass]>
[2020-05-26 10:42:34,520] sopel.bot            INFO     - Plugin loaded: units
[2020-05-26 10:42:34,521] sopel.plugins.rules  DEBUG    - Command registered: <Command invite.invite []>
[2020-05-26 10:42:34,521] sopel.bot            INFO     - Plugin loaded: invite
[2020-05-26 10:42:34,522] sopel.plugins.rules  DEBUG    - Command registered: <Command countdown.countdown []>
[2020-05-26 10:42:34,523] sopel.bot            INFO     - Plugin loaded: countdown
[2020-05-26 10:42:34,535] sopel.plugins.rules  DEBUG    - Command registered: <Command meetbot.startmeeting []>
[2020-05-26 10:42:34,535] sopel.plugins.rules  DEBUG    - Command registered: <Command meetbot.subject []>
[2020-05-26 10:42:34,535] sopel.plugins.rules  DEBUG    - Command registered: <Command meetbot.endmeeting []>
[2020-05-26 10:42:34,535] sopel.plugins.rules  DEBUG    - Command registered: <Command meetbot.chairs []>
[2020-05-26 10:42:34,535] sopel.plugins.rules  DEBUG    - Command registered: <Command meetbot.action []>
[2020-05-26 10:42:34,535] sopel.plugins.rules  DEBUG    - Command registered: <Command meetbot.listactions []>
[2020-05-26 10:42:34,536] sopel.plugins.rules  DEBUG    - Command registered: <Command meetbot.agreed []>
[2020-05-26 10:42:34,536] sopel.plugins.rules  DEBUG    - Command registered: <Command meetbot.link []>
[2020-05-26 10:42:34,536] sopel.plugins.rules  DEBUG    - Command registered: <Command meetbot.info []>
[2020-05-26 10:42:34,536] sopel.plugins.rules  DEBUG    - Rule registered: <Rule meetbot.log_meeting (1)>
[2020-05-26 10:42:34,536] sopel.plugins.rules  DEBUG    - Command registered: <Command meetbot.comment []>
[2020-05-26 10:42:34,536] sopel.plugins.rules  DEBUG    - Command registered: <Command meetbot.comments []>
[2020-05-26 10:42:34,536] sopel.bot            INFO     - Plugin loaded: meetbot
[2020-05-26 10:42:34,541] sopel.plugins.rules  DEBUG    - Rule registered: <Rule translate.tr (1)>
[2020-05-26 10:42:34,542] sopel.plugins.rules  DEBUG    - Command registered: <Command translate.translate [tr]>
[2020-05-26 10:42:34,543] sopel.plugins.rules  DEBUG    - Command registered: <Command translate.mangle [mangle2]>
[2020-05-26 10:42:34,543] sopel.plugins.rules  DEBUG    - Rule registered: <Rule translate.collect_mangle_lines (1)>
[2020-05-26 10:42:34,543] sopel.bot            INFO     - Plugin loaded: translate
[2020-05-26 10:42:34,548] sopel.plugins.rules  DEBUG    - Command registered: <Command search.duck [ddg|g]>
[2020-05-26 10:42:34,548] sopel.plugins.rules  DEBUG    - Command registered: <Command search.bing []>
[2020-05-26 10:42:34,548] sopel.plugins.rules  DEBUG    - Command registered: <Command search.search []>
[2020-05-26 10:42:34,548] sopel.plugins.rules  DEBUG    - Command registered: <Command search.suggest []>
[2020-05-26 10:42:34,548] sopel.bot            INFO     - Plugin loaded: search
[2020-05-26 10:42:34,554] sopel.plugins.rules  DEBUG    - Command registered: <Command help.help []>
[2020-05-26 10:42:34,554] sopel.bot            INFO     - Plugin loaded: help
[2020-05-26 10:42:34,556] sopel.plugins.rules  DEBUG    - Command registered: <Command announce.announce []>
[2020-05-26 10:42:34,556] sopel.bot            INFO     - Plugin loaded: announce
[2020-05-26 10:42:34,557] sopel.plugins.rules  DEBUG    - Command registered: <Command unicode_info.u []>
[2020-05-26 10:42:34,557] sopel.bot            INFO     - Plugin loaded: unicode_info
[2020-05-26 10:42:34,559] sopel.plugins.rules  DEBUG    - Command registered: <Command pronouns.pronouns []>
[2020-05-26 10:42:34,559] sopel.plugins.rules  DEBUG    - Command registered: <Command pronouns.setpronouns []>
[2020-05-26 10:42:34,559] sopel.bot            INFO     - Plugin loaded: pronouns
[2020-05-26 10:42:34,560] sopel.plugins.rules  DEBUG    - Command registered: <Command uptime.uptime []>
[2020-05-26 10:42:34,560] sopel.bot            INFO     - Plugin loaded: uptime
[2020-05-26 10:42:34,562] sopel.plugins.rules  DEBUG    - Command registered: <Command rand.rand []>
[2020-05-26 10:42:34,562] sopel.bot            INFO     - Plugin loaded: rand
[2020-05-26 10:42:34,563] sopel.plugins.rules  DEBUG    - Rule registered: <Rule ping.hello (1)>
[2020-05-26 10:42:34,563] sopel.plugins.rules  DEBUG    - Rule registered: <Rule ping.rude (1)>
[2020-05-26 10:42:34,563] sopel.plugins.rules  DEBUG    - Rule registered: <Rule ping.interjection (1)>
[2020-05-26 10:42:34,563] sopel.bot            INFO     - Plugin loaded: ping
[2020-05-26 10:42:34,565] sopel.plugins.rules  DEBUG    - Command registered: <Command seen.seen []>
[2020-05-26 10:42:34,565] sopel.plugins.rules  DEBUG    - Rule registered: <Rule seen.note (1)>
[2020-05-26 10:42:34,565] sopel.bot            INFO     - Plugin loaded: seen
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Command registered: <Command coretasks.execute []>
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.startup (1)>
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.handle_isupport (1)>
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.parse_reply_myinfo (1)>
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Command registered: <Command coretasks.useserviceauth []>
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.retry_join (1)>
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.handle_names (1)>
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.track_modes (1)>
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.track_nicks (1)>
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.track_part (1)>
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.track_kick (1)>
[2020-05-26 10:42:34,573] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.track_join (1)>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.track_quit (1)>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.receive_cap_list (1)>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.auth_proceed (1)>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.sasl_success (1)>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Command registered: <Command coretasks.blocks []>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.account_notify (1)>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.recv_whox (1)>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.recv_who (1)>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.end_who (1)>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.track_notify (1)>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.track_topic (1)>
[2020-05-26 10:42:34,574] sopel.plugins.rules  DEBUG    - Rule registered: <Rule coretasks.handle_url_callbacks (1)>
[2020-05-26 10:42:34,574] sopel.bot            DEBUG    - Job added "_periodic_send_who", will run every 30 seconds
[2020-05-26 10:42:34,574] sopel.bot            INFO     - Plugin loaded: coretasks
[2020-05-26 10:42:34,574] sopel.bot            INFO     - Registered 40 plugins, 0 failed, 1 disabled
[2020-05-26 10:42:34,575] sopel.irc.backends   INFO     - Connecting to chat.freenode.net:6697...
[2020-05-26 10:42:34,575] sopel.irc.backends   DEBUG    - Set socket
[2020-05-26 10:42:34,717] sopel.irc.backends   DEBUG    - Connection attempt
[2020-05-26 10:42:34,960] sopel.irc.backends   INFO     - Connection accepted by the server...
[2020-05-26 10:42:34,960] sopel.irc.backends   DEBUG    - Starting job scheduler for connection timeout...
[2020-05-26 10:42:34,963] sopel.irc            INFO     - Connected.
[2020-05-26 10:42:51,176] sopel.coretasks      INFO     - Joining 1 channels (with JOIN throttle ON); this may take a moment.
[2020-05-26 10:42:51,177] sopel.coretasks      DEBUG    - 0 commands to execute:
[2020-05-26 10:42:51,282] sopel.coretasks      DEBUG    - Received an apparently useless MODE message: :Exibot MODE Exibot :+Zi
[2020-05-26 10:42:57,172] sopel.coretasks      INFO     - Channel joined: #exirel
[2020-05-26 10:42:57,173] sopel.coretasks      DEBUG    - JOIN event added to queue for channel: #exirel
[2020-05-26 10:42:58,605] sopel.coretasks      DEBUG    - Sending WHO after channel JOIN: #exirel

Checklist

  • I have read CONTRIBUTING.md
  • I can and do license this contribution under the EFLv2
  • No issues are reported by make qa (runs make quality and make test)
  • I have tested the functionality of the things this change touches

@Exirel Exirel added the Feature label May 25, 2020
@Exirel Exirel added this to the 7.1.0 milestone May 25, 2020
@lgtm-com

This comment has been minimized.

@lgtm-com

This comment has been minimized.

@lgtm-com

This comment has been minimized.

@Exirel Exirel force-pushed the core-object-oriented-rules branch from c6af90f to e747d30 Compare May 26, 2020 08:19
@lgtm-com

This comment has been minimized.

@Exirel Exirel marked this pull request as ready for review May 26, 2020 08:44
@Exirel Exirel requested a review from dgw May 26, 2020 08:44
@Exirel
Copy link
Contributor Author

Exirel commented May 27, 2020

I've just pushed a new commit that contains modification to handle the example decorator, so the Rule object can keep that information. While I was at it, I reworked it a bit to create a better structure (yet not the best I believe) for the 3 separates cases I found:

  • example can be used for tests: return "as-is"
  • example can be used for doc: it's an "usage", and it is processed in get_usages() to handle command prefix and nicknames
  • the handler's docstring is the doc, but now I use inspect.getdoc because this is exactly why this function exists (no more trim_docstring nonsense)

The next step is to modify sopel.bot.Sopel.doc and sopel.bot.Sopel.command_groups so that they will be 1. read-only and 2. derived from the registered rules in real-time.

And after that, maybe in Sopel 7.2 (or before if I found the time), I'll suggest a totally new interface for documentation. But right now, I'm not sure about what we need exactly, so I stick to being backward compatible - this is already an improvement anyway!

@lgtm-com

This comment has been minimized.

@Exirel
Copy link
Contributor Author

Exirel commented May 27, 2020

The next step is to modify sopel.bot.Sopel.doc and sopel.bot.Sopel.command_groups so that they will be 1. read-only and 2. derived from the registered rules in real-time.

This is done. With added tests!

@lgtm-com

This comment has been minimized.

@Exirel
Copy link
Contributor Author

Exirel commented May 27, 2020

@dgw fully ready for review now!

@lgtm-com

This comment has been minimized.

@Exirel
Copy link
Contributor Author

Exirel commented Jun 1, 2020

I was able to build on this PR to add new features that was seemingly impossible before.

Also I put the High Priority label, because PR #1881 is a high priority feature and it depends on this one. (PR #1881 implements the high priority feature #1757)

@lgtm-com

This comment has been minimized.

Copy link
Member

@dgw dgw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh my, 104 line notes. And I haven't even tested anything; this is just a paper review. (Not that I should need to test it, because you wrote literally 2,000+ lines of tests, but y'know… 😎)

Don't panic too much, though. There are a lot of repetitions of the same typo fix (due to copy/paste or what-have-you), and not many comments that will require actual thought.

docs/source/plugin.rst Outdated Show resolved Hide resolved
sopel/bot.py Outdated Show resolved Hide resolved
sopel/bot.py Show resolved Hide resolved
sopel/bot.py Outdated Show resolved Hide resolved
sopel/bot.py Outdated Show resolved Hide resolved
sopel/plugins/rules.py Outdated Show resolved Hide resolved
sopel/plugins/rules.py Outdated Show resolved Hide resolved
sopel/plugins/rules.py Outdated Show resolved Hide resolved
sopel/plugins/rules.py Show resolved Hide resolved
sopel/plugins/rules.py Outdated Show resolved Hide resolved
sopel/module.py Outdated Show resolved Hide resolved
@lgtm-com

This comment has been minimized.

@lgtm-com

This comment has been minimized.

@lgtm-com

This comment has been minimized.

@lgtm-com

This comment has been minimized.

@Exirel
Copy link
Contributor Author

Exirel commented Jun 6, 2020

So, I've read all your comments, fixed what I could, didn't rebase anything, and replied with what I think are relevant answers.

@dgw I can see that you have question about the new interface, because you saw that it wasn't totally finished. I believe that too, and I'd like to improve it in future PR, rather than here. I prioritized backward compatibility over new feature, and I think new PRs like #1881 are the way to go.

sopel/loader.py Outdated Show resolved Hide resolved
:param str plugin: Optional filter on the plugin name
:return: ``True`` if the command exists, ``False`` otherwise

By default, this method doesn't search commands by their aliases. If
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's look at it from the perspective of a possible use-case, then.

Let's say I'm a plugin author who wants, for some reason, to programmatically register a new command. I want to be responsible, so I don't want to register my command if its name is already bound to something. In this case, I'd want aliases to be included, so I don't accidentally register something that will also trigger another handler unintentionally.

I'm having trouble thinking of a case when I (as a plugin author) wouldn't want to know about aliases, honestly. I get that explicitly requesting it "feels better", but the default behavior should reflect what most users of the method will expect. We have no hard data, obviously, but I anticipate most users would want aliases included based on my understanding of what this method (and its friends) is for.

sopel/plugins/rules.py Show resolved Hide resolved
sopel/plugins/rules.py Outdated Show resolved Hide resolved
sopel/plugins/rules.py Show resolved Hide resolved
sopel/plugins/rules.py Show resolved Hide resolved
test/test_bot.py Outdated Show resolved Hide resolved
sopel/bot.py Show resolved Hide resolved
Exirel and others added 18 commits June 10, 2020 08:50
I modified the loader.clean_callable function to stop adding regex to
the `rule` attribute on a callable that doesn't need to:

* commands,
* action commands,
* nickname commands,

don't need to have a specitic "rule" attribute. Therefore, when the bot
registers a callable, it can register it as an anonymous rule and as a
command, as expected by plugin authors.

Tests have been modified accordingly.
@Exirel Exirel force-pushed the core-object-oriented-rules branch from b7e0f9f to 15173d9 Compare June 10, 2020 06:55
@Exirel
Copy link
Contributor Author

Exirel commented Jun 10, 2020

Oh and this time Travis reported its status properly! All green!

@lgtm-com

This comment has been minimized.

@Exirel Exirel requested a review from dgw June 10, 2020 07:24
Copy link
Member

@dgw dgw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving a couple "suggestions" to apply myself, then I'll let Travis stew on this and come back to merge it before I go to bed tonight.

sopel/module.py Outdated Show resolved Hide resolved
sopel/module.py Outdated Show resolved Hide resolved
@lgtm-com
Copy link

lgtm-com bot commented Jun 10, 2020

This pull request introduces 3 alerts when merging 04c3821 into 1c65ebb - view on LGTM.com

new alerts:

  • 3 for Conflicting attributes in base classes

@dgw dgw merged commit 5fddc73 into sopel-irc:master Jun 11, 2020
@Exirel Exirel deleted the core-object-oriented-rules branch June 23, 2020 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants