Version 7.0.0
Sopel 7.0 contains numerous fixes, tweaks, new features, and internal improvements. While we maintain no official statistics on such things, it’s probably the biggest release the project has ever seen.
The full, detailed list of changes is below, but you can just read the migration guide if all you care about is the really important stuff. All breaking changes (including those planned for the next release) are explained there.
Plugin changes
- The
spellcheckplugin has been removed to simplify dependencies [#1675] - Similarly, the
ipythonplugin is now an external package, eliminating from Sopel itself a dependency which most users will never need [#1684]- Find the new
sopel-ipythonpackage on PyPI
- Find the new
- The
.choose/.choicecommand has been moved fromdiceinto a standalone plugin, aptly namedchoose[#1679] - Moved
.pyinto its own plugin, namedpy[#1710, #1711, #1712]- In case of issues with our “official” instance, there’s now a setting to configure the address of your own Oblique service
- The
currencyplugin changed data sources to support more currencies, and can optionally use Fixer.io for even more [#1430, #1627, #1629]- Fixer.io requires a free API key, which gives plenty of calls per month (the plugin caches exchange rates for 24 hours)
- Choose any of five pastebin services for
helpoutput [#1451, #1651]- This is intended mostly for resilience (so one pastebin service going down, as ptpb did during the 6.6.x life-cycle, won’t force a new Sopel release), but it’s also just good to have choices
- Optionally hide IRC server name/address in
helpcommand listing [#1459] - New
helpplugin setting,reply_method[#1700] wiktionarynow supports many more parts of speech [#1443]- Definitions can be retrieved for things like proper nouns, prepositional phrases, and punctuation marks—things that were unsupported in Sopel 6.x
- This means that the
wiktionaryplugin is now somewhat case-sensitive, to account for common and proper nouns that differ only in capitalization
urlwill now ignore “private” addresses by default [#1439, #1624]- New config settings for the
urlplugin allow overriding the checks, in cases where loading previews of e.g. LAN servers is safe - The default is off, so users don’t unwittingly open themselves to attackers fishing for running HTTP services on the local machine or network
- New config settings for the
urlnow correctly ignores invalid URLs (e.g.http://*\.com) [#1788]- Various improvements to the
clockfunctions [#1592]- Improved guessing in
.t/.timecommand, which no longer falls back all the way to the bot’s default timezone if given an unrecognized argument - New
.tzcommand, to explicitly get time for a timezone name (in case of conflict between a known nick and a timezone name)
- Improved guessing in
- The
tell&remindplugins’ “.db” files have changed names [#1699]- Both will attempt automatic migration of existing files, if they exist, and output debugging information if the migration fails
- The
.atcommand (inremind) understands dates now [#1590, #1736]- Finally, it’s possible to set a reminder more than 24 hours ahead without
first converting the future date/time to a duration for use with
.in!
- Finally, it’s possible to set a reminder more than 24 hours ahead without
first converting the future date/time to a duration for use with
- A new
tellplugin setting allows delivering messages privately [#1694] - The
redditplugin now also handles shortredd.itlinks, direct links to comments, inlineu/andr/references, & reddit-hosted image/video links [#1503, #1720, #1722, #1734, #1760, #1773] - Spoilers & NSFW are now separate concepts in the
redditplugin [#1620]- Reddit implemented spoilers as a distinct post flag some time ago. Sopel’s plugin supports independently setting channels as “SFW” or “spoiler-free”.
- Rolling
.dicenow officially supports trailing# comments[#1577] - Python version is now included in
.versioncommand output [#1462] - The
.versioncommand’s output format is improved [#1633] - Using the
.reloadcommand shows the specific file reloaded [#1762] - The
.seencommand’s output now uses relative time [#1661] - Readability of
.choosecommand output is significantly improved [#1425] - Added
.invitecommand [#1497]- Both Sopel and the inviting user must have privileges in the target channel
- A
.restartcommand is added [#1333]- Usable by admins only, just like
.quit
- Usable by admins only, just like
- The
.msgcommand is now known as.say[#1606].msgwill continue to work for now, likely until being removed in Sopel 8
- The
adminplugin auto-saves channels when using.join/.part, and added.tmpjoin/.tmppartcommands to bypass this behavior [#1492] - Added command to
.unsetconfig values in theadminplugin [#1556] - Restored commands in
adminchannelplugin for managing op/voice [#1498]- These were removed some time ago, seemingly without reason, by the project’s previous maintainers
- Since there was some desire from users to have them back, we restored them
- Fixed/tweaked hostmask handling in
adminchannelban functions [#1791] findalso collects Sopel’s own messages now, so users can “correct” the bot if they wish to be extra cheeky [#1470]- Fixed that the
urlplugin had to be enabled or some link-handling functions wouldn’t work [#1510] - Tweaked
.ddgcommand output so it’s less likely to mangle URLs [#1713] remindcommands now “reply” with error messages [#1715]- Fixed
etymologyplugin error with empty argument [#1677] - Fixed an uncaught exception in
instagramplugin [#1702] - Handle JSON fetch/parse errors in
find_updatesplugin [#1779] - Removed nonsensical uses of the
core.verify_sslsetting [#1706] - Unused
clockplugin settings have been removed [#1696] - Updated MaxMind database handling in
ipplugin [#1797] - Reworked
safetyplugin’s cache management [#1753, #1802] - General code cleanup and tweaks all around [#1402, #1486, #1505, #1569, #1573, #1578, #1579, #1581, #1592, #1606, #1607, #1609, #1678, #1681, #1696, #1717, #1721, #1725, #1735, #1741, #1754]
Core changes
- Brought back support for non-SQLite databases by switching to SQLAlchemy
[#1446, #1652, #1729, #1755, #1774, #1777, #1783]
- For details on using non-SQLite databases, see the README or configuration instructions
- You will probably need to install additional dependencies if you wish to use something other than SQLite
- Migrating an existing database from SQLite to your chosen option is probably easy, but we do not offer instructions for doing so
- Be aware that plugins written for older versions of Sopel might not work properly with non-SQLite databases
- The
db_filenameconfig setting (for SQLite) is now interpreted as relative to the config’shomedirsetting [#1574]homediritself has a default value that will be used if not set
- Added separate server & nickname authentication options [#1513]
- Added
commands_on_connectsetting to send a list of commands automatically when Sopel’s IRC connection is successfully established [#1528] - Log files have become much more configurable [#1678, #1714]
- Logs are named based on the config name
- Many, many new settings added to customize logging
- The default log format includes timestamp, source package, & level (which will make logs much more useful when reporting bugs)
- Logs now have information about which plugin file was reloaded [#1762]
- This is helpful for owners of Sopel instances with multiple versions of a plugin available for testing or development purposes
- Sopel’s own rate-limiting & flood protection parameters are now configurable, and can even be turned off entirely if Sopel is behind a bouncer or other IRC proxy that handles flood protection itself [#1518, #1638]
- Added more control over JOIN throttling [#1751]
- Includes a new
throttle_waitsetting instead of a hard-coded time value
- Includes a new
- Log timestamp and log line formats are now configurable [#1512]
- See details in the logging configuration docs
- Log filenames now include the config name, to help keep track of logs from multiple Sopel instances [#1547]
- Home directory is no longer assumed to be
~/.sopelon first run [#1404] - Restarting Sopel via CLI is added [#1333]
- Sopel’s CLI is restructured [#1493, #1509, #1718]
- New subcommands (
start,stop,restart, andconfigure) replace many of the old--options, cleaning up the syntax - The legacy
--options will continue to work for the life of Sopel 7.x, and will be removed in Sopel 8
- New subcommands (
- New
--config-dircommon option [#1598] - Added a new
sopel-configcommand for working with config files [#1507]- Currently supports
list(existing files),init(new config file), andget(config value) actions - The old
--listargument tosopelis considered deprecated, and will be removed in Sopel 8 - See detailed usage in your terminal with
sopel-config --help, or review the online CLI docs at our website
- Currently supports
- Added a new
sopel-pluginscommand for managing plugins [#1588]- Currently supports
list(available plugins),show(plugin details & status),enable&disable(edits config on the user’s behalf) - See detailed usage in your terminal with
sopel-plugins --help, or review the online CLI docs at our website
- Currently supports
- Sopel now also looks for plugins in
$HOMEDIR/plugins[#1747]- This is part of a longer-term plan to reduce confusion over the term “module”, which Sopel has been using in conflicting ways; see [#1738]
- The config file Sopel should use can be specified via the
SOPEL_CONFIGenvironment variable [#1473] - List values in config can be separated by newlines [#1628, #1690]
- Newline-separated values support commas within each value
- Comma-separated value support will end someday, but likely not till Sopel 9
- Find more details in the
ListAttributedocumentation
- Config options can be set/overridden via environment variables [#1096]
- Variable naming format:
SOPEL_SECTION_OPTION - Underscores in
SECTIONandOPTIONnames are preserved, e.g.SOPEL_CORE_AUTH_PASSWORD
- Variable naming format:
- Example multi-instance systemd template is now available [#1059]
- Example systemd unit files wait until networking is connected before starting Sopel [#1511]
- Running Sopel on an unknown OS platform will output a warning encouraging the user to report any issues (because test coverage on an unrecognized platform name is likely to be nil) [#1487]
- Cleaned up or refactored a bunch of places [#1424, #1429, #1456, #1458, #1472, #1479, #1510, #1522, #1527, #1542, #1557, #1561, #1567, #1579, #1580, #1583, #1597, #1610, #1635, #1685, #1697, #1708, #1716, #1723, #1724, #1728, #1730, #1731, #1732, #1735, #1739, #1740, #1741, #1742, #1743, #1754, #1759, #1787]
- Sopel 7 will emit warnings when run under Python 2, as Python 2.7 support
officially ended on January 1, 2020 [#1488, #1795, #1800]
- Sopel’s warnings are set to become more dire around the time when Python’s maintainers plan to release the final version of 2.7
- While Sopel 7 is intended to remain compatible with Python 2, future compatibility is not guaranteed, and users should plan for Sopel 8 to officially drop Python 2 support (see upgrade notes)
- Added support for IRCv3
echo-messagecapability, which Sopel will now request upon connecting to an IRC server [#1470, #1672, #1674] - Added support for disabling commands (or entire plugins) on a per-channel
basis [#1235]
- See how it works: Per-channel configuration
- Fixed tracking user
awaystate [#1663, #1664, #1666, #1703] - User information is now periodically updated [#1664]
- Fixed a case in which MODE tracking could break [#1737]
- Handle non-standard
+y/+YOPER modes [#1671]- A new
OPERconstant insopel.modulenow exists for these channel modes, which (at least on InspIRCd) use the privilege prefix! - This is a stopgap for one specific case; we are working on further changes to support dynamic parsing of privilege modes/prefixes at connect time
- A new
- Stopped sending TOPIC command on JOIN [#1749]
- IRC servers should send the topic on join without being asked, per spec
- Greatly improved the warning printed when a deprecated function is used,
adding detail and removing unnecessary traceback lines [#1568, #1613]
- Typical length of output for each deprecated function call reduced from roughly 15 lines to 3 (warning, file/line, and offending code snippet)
- Added optional
@deprecateddecorator arguments:reason: why this item was deprecatedversion: the version in which the deprecation happenedremoved_in: the version in which the deprecated item will be removed
- The end-of-life warning for users on Python 2.x is now date-aware [#1756]
- Made sure ignored users cannot trigger URL handlers [#1806]
- Tightened up some more dependency version specifiers [#1807]
API changes
- API documentation has been almost entirely overhauled [#1563,
#1566, #1646, #1668, #1669, #1680, #1719, #1727,
#1735, #1750, #1766, #1770, #1771, #1772, #1775,
#1776, #1778, #1782, #1813]
- Nearly every file, both for the public API and Sopel’s internals, was
reviewed in its entirety to make these improvements globally:
- More consistent style
- Better use of Sphinx features (e.g. parameter definitions, return value notes, & version annotations)
- General cleanup and copy-editing
- Add more detail and examples to help new bot users and plugin authors
- Remove or correct outdated information left over from previous versions
- Nearly every file, both for the public API and Sopel’s internals, was
reviewed in its entirety to make these improvements globally:
- Most of Sopel’s submodules now define
__all__, limiting namespace pollution from using*in imports [#1582, #1727] - Plugins can register themselves via
setuptoolsentry points [#1585]- This feature is an evolution of the previous mechanism to install plugins
via PyPI packages, which required a specific directory structure and
package name format (
sopel_modules.plugin_name) - See the entry point plugin documentation for more
- This feature is an evolution of the previous mechanism to install plugins
via PyPI packages, which required a specific directory structure and
package name format (
- Logging has been reworked [#1678]
- The
sopel.logger.get_logger()function is deprecated in favor of a newsopel.tools.get_logger()utility with plugin-specific behavior sopel.logger.get_logger()will begin emitting deprecation warnings in version 8.0, and will be removed in 9.0
- The
- Testing tools have been overhauled [#1731, #1732, #1781]
- The old “Mock” classes in
sopel.test_toolsare now deprecated:MockConfigMockSopelMockSopelWrapper
- New pytest fixtures make the real objects usable in tests directly
- The bot keeps track of running triggered threads, so tests can be sure that processing has finished before evaluating results
- Sopel also now exports a
pytestplugin, for convenience
- The old “Mock” classes in
module.event()decorator no longer requires a rule [#1693, #1709]- Since 99% (unscientific guesstimate) of event decorators were paired with
@module.rule('.*'), that’s now implied if no rule decorator is present
- Since 99% (unscientific guesstimate) of event decorators were paired with
- Added
sopel.tools.web(replacessopel.web) [#1616, #1670]- Both old and new import locations will work until Sopel 7 end-of-life
- The
sopel.webpackage will be removed completely in Sopel 8 - Functions marked as deprecated in the old location (e.g.
web.get()) do not carry forward to the new package namespace; they remain deprecated
- Added
tools.web.unquote(), the reverse oftools.web.quote()[#1681]- Note: This is not available in the
sopel.webcompatibility layer
- Note: This is not available in the
- Added a set of methods in the
botobject to manipulate URL callbacks:bot.register_url_callback,bot.unregister_url_callback, andbot.search_url_callbacks[#1508, #1808]- Modules should switch to using these new API methods instead of directly
accessing
bot.memory['url_callbacks'] - There are no definite plans to remove
bot.memory['url_callbacks'], but it should be considered deprecated
- Modules should switch to using these new API methods instead of directly
accessing
- Added
kick()method tobotobject [#1539]bot.kick(nick, channel, optional_message)is shorthand for the patternbot.write(['KICK', channel, nick], optional_message), used by a number of both core and third-party plugins
- Added
bot.myinfo, containing the server’s RPL_MYINFO (004) data [#1769]- More information in the MYINFO documentation
- Added
bot.isupport, exposing network-specific settings and properties from the server’s RPL_ISUPPORT (005) data [#1758]- This includes useful things like the network’s maximum nickname length
(
NICKLEN), maximum topic length (TOPICLEN), number of targets allowed per command (TARGMAX), and channel-privilege mappings (PREFIX) - More information in the ISUPPORT documentation
- This includes useful things like the network’s maximum nickname length
(
- Added
session()method tobot.db[#1811]db.connect()now logs a message when used with a non-SQLite database connected, as raw connection behavior for different DB types varies
- Added
delete_{nick,channel}_valuemethods inbot.db[#1526] - Added “plugin value” API to
bot.db[#1621]- Functionally identical to “nick” and “channel” values, but in a separate namespace intended for plugins’ use to store key-value data that isn’t associated with a nick or channel and doesn’t belong in the config file
- Added optional
defaultkwarg todb.get_*_value()functions [#1673]- This allows streamlining some uses of values fetched from the database
- New
sopel.module.output_prefixdecorator [#1701]- Defines a prefix for all output sent from the decorated callable via
bot.sayorbot.notice(bot.action&bot.replydon’t fit the use cases this feature is intended to address)
- Defines a prefix for all output sent from the decorated callable via
- New
sopel.module.require_accountdecorator [#1733]- This is useful to require services login on networks where Sopel can track users’ authentication status, but will block all use of the decorated callable on networks without the necessary features
sopel.moduledecorators work much more consistently [#1632]- All relevant decorators accept multiple arguments at once, and will work properly if used multiple times on the same function
- Added
replyoption tomodule.require_*decorators [#1456, #1500]- Passing
reply=Truewill send the error message as if viabot.reply(), prefixing it with the name of the calling user to get their attention - Passing
reply=False(or omitting the argument) will behave exactly as before, with the error message sent as if viabot.say()
- Passing
- Fixed the
@module.urldecorator to work always, regardless of whether any core plugins are enabled [#1510, #1576] - Added
bot.hostmaskproperty (read-only) [#1537]- This property is a shortcut for
bot.users.get(bot.nick).hostmask, so it will throw an error if the bot is not connected to a network and joined to at least one channel. Basically, don’t try to use it in pluginsetup()orshutdown()methods.
- This property is a shortcut for
- Added
bot.get_plugin_meta()method to fetch plugin information [#1762] - Added
module.echodecorator [#1470]- Decorated callables will receive messages that Sopel itself sends,
regardless of whether the IRC server actually supports
echo-message - Don’t send output from
@echo-decorated callables; this will cause loops
- Decorated callables will receive messages that Sopel itself sends,
regardless of whether the IRC server actually supports
- Added
module.action_commandsdecorator [#1660]- This presently conflicts with other command/trigger decorators because of internal implementation details, but fixing that is on our to-do list
- If you want both
action_commandsand another command type (commands,nickname_commands, etc.), use@action_commands('foo')to decorate a wrapper function that simply calls the main one
- Officially deprecated the methods
SopelMemory.contains()andSopelMemoryWithDefault.contains(), to be removed in Sopel 8 [#1563]- Use the
inoperator instead
- Use the
- Officially deprecated the
bot.msg()method [#1606]- Adds a warning to Sopel’s output for any third-party code that is still
using
bot.msg()(which was declared deprecated and removed from the API docs in 6.0) instead ofbot.say()
- Adds a warning to Sopel’s output for any third-party code that is still
using
- Added a new
user_helpkwarg to@module.exampledecorator [#1403]- This allows multiple help examples per command, as requested in #1200
- See the Sopel 7 migration guide for details on using this new parameter, and about backwards compatibility
- Added a new
onlinekwarg to@module.exampledecorator [#1555]- Example tests that require an Internet connection may be marked with
online=Trueto indicate this fact (the default isFalse) - This facilitates running only offline-safe plugin tests, by passing
--offlineto pytest, if an Internet connection is unavailable - Outside of the test suite, this parameter has no effect
- Example tests that require an Internet connection may be marked with
- Corrected case-mapping in
tools.Identifierclass [#1744]- See the Sopel 7 migration guide for details, particularly if your plugin interacts with the database and/or user/channel identifiers in their lowercase form
- Added more utilities to
tools.time:tools.time.seconds_to_human(), for generating human-readable fuzzy relative timestamps fromtimedeltaor raw number of seconds [#1560]tools.time.get_nick_timezone()andtools.time.get_channel_timezone(), for cases where the fallback behavior(s) oftools.time.get_timezone()would be undesired [#1592]
- Made
tools.time.validate_timezone()more robust [#1707] - Added alias for 462 numeric in
tools.events[#1665]- RFC 2812 defined an incorrect spelling,
ERR_ALREADYREGISTRED, and Sopel copied it verbatim - The spelling
ERR_ALREADYREGISTEREDcan be used now, too
- RFC 2812 defined an incorrect spelling,
- Fixed invalid raw lines in generated
@exampletests [#1499] - Fixed
PreTriggerobjects missing thetextattribute sometimes [#1782]