sopel
sopel copied to clipboard
version: fallback behavior if no module- or file-level `__version__`
One can .version pluginname
for any loaded plugin, but e.g. a single-file module stored in ~/.sopel/plugins/pluginname.py
will simply return [version] pluginname (unknown)
if it doesn't contain a __version__
member.
I propose that, at least for single-file plugins, the plugin machinery should fall back on the file modification timestamp in lieu of a version number.* It'd probably be reasonable to format the file's modification time as yyyy.mm.dd
, and ignore hours or smaller units.**
* | It gets trickier for Folder or Namespace Package plugins, but we're discouraging the use of those now. |
** | Our Sphinx theme for 8.x, Furo, is even versioned this way on PyPI, though packaging strips the tags' leading zeroes.
I'm sure someone will come along and say we should just use the Unix timestamp as the version number, but come on. |
Here's a small patch to version
that would implement the desired behavior, although it relies on accessing Sopel._plugins
directly, so it will need some support work to do it the Right Way™, either adding the modification time to the plugin metadata or adding a mechanism for retrieving the plugin from the bot.
click for patch
diff --git a/sopel/modules/version.py b/sopel/modules/version.py
index 536eaa83..ad2bca5e 100644
--- a/sopel/modules/version.py
+++ b/sopel/modules/version.py
@@ -9,6 +9,7 @@ https://sopel.chat
from __future__ import annotations
import datetime
+import importlib.util
import os
import platform
@@ -51,6 +52,13 @@ def version(bot, trigger):
meta = bot.get_plugin_meta(plugin)
if meta["version"] is None:
version = "(unknown)"
+ # TODO: this uses implementation details of Sopel ;(
+ spec = importlib.util.find_spec(bot._plugins[plugin].module_name)
+ if spec.origin:
+ mtime = os.stat(spec.origin).st_mtime
+ timestamp = datetime.datetime.fromtimestamp(mtime).strftime("%d %b %Y")
+ version += " — last modified {ts}".format(ts=timestamp)
else:
version = "v" + str(meta["version"])
Output before patch:
15:40 <testibot> [version] 8ball (unknown)
15:40 <SnoopJ> !reload version
Output after patch:
15:40 <SnoopJ> !version 8ball
15:40 <testibot> [version] 8ball (unknown) — last modified 02 Apr 2023
(note: I prefer using %b
where possible to avoid possible confusion over date order but I don't feel super strongly about that, it could just as easily be %Y.%m.%d
)