Repository: getpelican/pelican (Python)

Issue:
Document breaking changes in Pelican 4.5
<!--
  Hi there! Thank you for discovering and submitting an issue.

  Before you submit this, let’s make sure of a few things.
  Please make sure the following boxes are ticked if they are correct.
  If not, please try and fulfill them first.
-->

<!-- Checked checkbox should look like this: [x] -->
- [x] I have read the [Filing Issues](https://docs.getpelican.com/en/latest/contribute.html#filing-issues) and subsequent “How to Get Help” sections of the documentation.
- [x] I have searched the [issues](https://github.com/getpelican/pelican/issues?q=is%3Aissue) (including closed ones) and believe that this is not a duplicate.

<!--
  Once the above boxes are checked, if you are able to fill in the following list
  with your information, it would be very helpful for maintainers.
-->

- **OS version and name**: Ubuntu 18.04 (WSL)
- **Python version**: 3.8.6

# Issues
<!--
  Now feel free to write your issue. Please avoid vague phrases like “[…] doesn’t work”.
  Be descriptive! Thanks again 🙌 ❤️
-->

## The first one

**As of https://github.com/getpelican/pelican/commit/58edad6897931f21c7c2f4314cfab33c2b167680, `import pelican.signals` is no longer valid.**

```
$ git reset 58edad^ --hard
$ python -c "import pelican.signals"  # exits 0

$ git reset 58edad --hard
$ python -c "import pelican.signals"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'pelican.signals'
```

## The second one

**As of https://github.com/getpelican/pelican/commit/ed1eca160e80bebbfd5870afe1f2a111f388e0ed, legacy plugins with `.` in their names stop working.**

### To reproduce

Create these files:
```
├── content
│   └── 1.rst
├── pelicanconf.py
├── plugins
│   └── m
│       └── test.py
```

```rst
.. content/1.rst
###
123
###
```

```python
# pelicanconf.py
PLUGINS = [
    'm.test',
]
PLUGIN_PATHS = [
    'plugins'
]
```

```python
# plugins/m/test.py
from pelican import signals


def takes_nothing():
    pass


def register():
    signals.initialized.connect(takes_nothing)
```

And then:
```
$ git reset ed1eca^ --hard
$ python -m pelican content
WARNING: Feeds generated without SITEURL set properly may not be valid
WARNING: No timezone information specified in the settings. Assuming your timezone is UTC for feed generation. Check http://docs.getpelican.com/en/latest/settings.html#timezone for more information
CRITICAL: takes_nothing() takes 0 positional arguments but 1 was given
# plugin correctly loaded

$ git reset ed1eca --hard
$ python -m pelican content
WARNING: Feeds generated without SITEURL set properly may not be valid
WARNING: No timezone information specified in the settings. Assuming your timezone is UTC for feed generation. Check http://docs.getpelican.com/en/latest/settings.html#timezone for more information
ERROR: Cannot load plugin `m.test`
  | No module named 'm'
ERROR: Skipping /[path redacted]/content/1.rst: could not find information about 'date'
Done: Processed 0 articles, 0 drafts, 0 pages, 0 hidden pages and 0 draft pages in 0.08 seconds.
# plugin not loaded
```

## Projects affected by these changes

An example: https://github.com/mosra/m.css

And a related issue: https://github.com/mosra/m.css/issues/178


Discussion:
First one was [known](https://github.com/getpelican/pelican/pull/2644#issuecomment-548304256), I tried to keep it backwards compatible at first by adding a dummy file but then opted to remove that since no plugin was using that style. `from pelican import signals` will still work.

I'll check second one. Does it still error if you include an empty `__init__.py` in the `m` folder~ **Edit**: Yes, it does. It think I found the issue. It was an oversight or misunderstanding on my part, about how the import machinery works. It doesn't seem to automatically resolve package submodules. I'll try to work on it soon.
> First one was [known](https://github.com/getpelican/pelican/pull/2644#issuecomment-548304256), I tried to keep it backwards compatible at first by adding a dummy file but then opted to remove that since no plugin was using that style. `from pelican import signals` will still work.
> 
> I'll check second one. Does it still error if you include an empty `__init__.py` in the `m` folder?

Yes it still errors.

In the affected project mentioned above, there is [an empty `__init__.py`](https://github.com/mosra/m.css/blob/master/plugins/m/__init__.py).
This should be enough to fix the second issue, if you want to test it out:

```diff
diff --git a/pelican/plugins/_utils.py b/pelican/plugins/_utils.py
index 78c19e54..a2930551 100644
--- a/pelican/plugins/_utils.py
+++ b/pelican/plugins/_utils.py
@@ -40,6 +40,11 @@ def list_plugins(ns_pkg=None):


 def load_legacy_plugin(plugin, plugin_paths):
+    if '.' in plugin:
+        # it is in a package, so resolve packages first
+        package, _, _ = plugin.rpartition('.')
+        load_legacy_plugin(package, plugin_paths)
+
     # Try to find plugin in PLUGIN_PATHS
     spec = importlib.machinery.PathFinder.find_spec(plugin, plugin_paths)
     if spec is None:
```

I'll make a PR when I have time to add tests for it.
Thanks for the quick fix! The plugins work fine with this patch.

But what about the first issue? Maybe one extra line in the changelog could save lots of plugin developers' time. You know, a lot of plugins are not included in the pelican-plugins repo (like the affected project I mentioned). These plugins' developers, if they were using `import pelican.signals`, a `BREAKING CHANGES` section in the changelog could help them fix their broken plugins easily. As is in the related issue I mentioned, sometimes this simple import error can be difficult to debug.
We can add the changelog entry for the next version about the change.

I could also restore `pelican.signals` but only with an `ImportError` stating that it is deprecated, and tell plugins to switch. That would look like this:

```console
ERROR: Cannot load plugin `m.test`
  | Importing from `pelican.signals` is deprecated. Use `from pelican import signals` or `import pelican.plugins.signals` instead.
```
I took the liberty of updating the [Pelican 4.5 release post](https://blog.getpelican.com/pelican-4.5-released.html), adding a fourth caveat to the **“Upgrading from previous releases”** section and including the above deprecation details.
> This should be enough to fix the second issue

@avaris this is great, thank you :heart: Would significantly simplify everything for all m.css users :)
I'm running Pelican 4.5.0 and am still experiencing load_legacy() not found issue.
```console
$ python3.8 -c "import pelican;print(pelican.__version__)"
4.5.0
```
At 7a6686f4 (origin/master, origin/HEAD) Fix SUMMARY_END_SUFFIX variable name in changelog
 

I've done a `git submodule` checkout of m.css into the working area of a website such that this directory layout is:
```
+ egbert.net
|-- content
|-- output
|-- plugins
|-- m.css
   |
   +-- plugins
      +-- ansilexer.py
      +-- dot2svg.py
      +-- latex2svg.py
      +-- latex2svgextra.py
      +-- m
         +-- htmlsanity.py
         +-- metadata.py 
...
```

I used the following plugin settings:
```
PLUGIN_PATHS = [ './plugins', 'm.css/plugins' ]
PLUGINS = [
#          'i18n_subsites',
          'collate_content',
          'sitemap',
          'dateish',
          'tag_cloud',
          'm.alias',
          'm.htmlsanity',
          'm.images',
          'm.math',
          'just_table',
          'code_include',
]
```

And my console output for Pelican was:
```console
ERROR: Cannot load plugin `m.alias`
  | No module named 'm'
ERROR: Cannot load plugin `m.htmlsanity`
  | No module named 'm'
ERROR: Cannot load plugin `m.images`
  | No module named 'm'
ERROR: Cannot load plugin `m.math`
  | No module named 'm'
```
Surely, I must be misreading the documentation or something, am I?
> I'm running Pelican 4.5.0 and am still experiencing load_legacy() not found issue.

Still? It's not fixed yet.
Yeah, latest master.  Will troubleshoot this.

A different error occurred when I used the following:
```python
PLUGIN_PATHS = [ './plugins', 'm.css/plugins', 'm.css/plugins/m' ]
```
whose output gives:
```console
(Pdb) c
ERROR: Cannot load plugin `m.math`
  | No module named 'latex2svg'
ERROR: Cannot register plugin `m.alias`
  | No module named 'pelican.signals'
ERROR: Cannot register plugin `m.htmlsanity`
  | name 'pelican' is not defined
ERROR: Cannot register plugin `m.images`
  | No module named 'pelican.signals'
```

Ordering of PLUGIN_PATHS don't matter...  Discontinuing this specific approach.  Back to  debugging 4.5.0 and legacy plugins.
Current starting point for debugging legacy plugin:
```console
(Pdb) b /usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/_utils.py:91
(Pdb) c
...
> /usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/_utils.py(44)load_legacy_plugin()
-> spec = importlib.machinery.PathFinder.find_spec(plugin, plugin_paths)
(Pdb) print(plugin)
m.alias
(Pdb) print(plugin_paths)
['/home/steve/work/github/egberts.github.io-src/m.css/plugins']
```
then
```console
(Pdb) n
> /usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/_utils.py(47)load_legacy_plugin()
-> spec = importlib.util.find_spec(plugin)
(Pdb) print(plugin)
m.alias
```
Down to `find_spec()`, `m.alias` not found in sys.modules.
```console
 91  ->     if fullname not in sys.modules:
 92             parent_name = fullname.rpartition('.')[0]
 93             if parent_name:
 94                 parent = __import__(parent_name, fromlist=['__path__'])
 95                 try:
 96                     parent_path = parent.__path__
(Pdb) print fullname
*** SyntaxError: Missing parentheses in call to 'print'. Did you mean print(fullname)?
(Pdb) print(fullname)
m.alias
(Pdb) print(sys.modules)
{'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, '_frozen_importlib': <module 'importlib._bootstrap' (frozen)>, '_imp': <module '_imp' (built-in)>, '_warnings': <module '_warnings' (built-in)>, '_frozen_importlib_external': <module 'importlib._bootstrap_external' (frozen)>, '_io': <module 'io' (built-in)>, 'marshal': <module 'marshal' (built-in)>, 'posix': <module 'posix' (built-in)>, '_thread': <module '_thread' (built-in)>, '_weakref': <module '_weakref' (built-in)>, 'time': <module 'time' (built-in)>, 'zipimport': <module 'zipimport' (frozen)>, '_codecs': <module '_codecs' (built-in)>, 'codecs': <module 'codecs' from '/usr/lib/python3.8/codecs.py'>, 'encodings.aliases': <module 'encodings.aliases' from '/usr/lib/python3.8/encodings/aliases.py'>, 'encodings': <module 'encodings' from '/usr/lib/python3.8/encodings/__init__.py'>, 'encodings.utf_8': <module 'encodings.utf_8' from '/usr/lib/python3.8/encodings/utf_8.py'>, '_signal': <module '_signal' (built-in)>, '__main__': <module '__main__' from '/usr/local/bin/pelican'>, 'encodings.latin_1': <module 'encodings.latin_1' from '/usr/lib/python3.8/encodings/latin_1.py'>, '_abc': <module '_abc' (built-in)>, 'abc': <module 'abc' from '/usr/lib/python3.8/abc.py'>, 'io': <module 'io' from '/usr/lib/python3.8/io.py'>, '_stat': <module '_stat' (built-in)>, 'stat': <module 'stat' from '/usr/lib/python3.8/stat.py'>, '_collections_abc': <module '_collections_abc' from '/usr/lib/python3.8/_collections_abc.py'>, 'genericpath': <module 'genericpath' from '/usr/lib/python3.8/genericpath.py'>, 'posixpath': <module 'posixpath' from '/usr/lib/python3.8/posixpath.py'>, 'os.path': <module 'posixpath' from '/usr/lib/python3.8/posixpath.py'>, 'os': <module 'os' from '/usr/lib/python3.8/os.py'>, '_sitebuiltins': <module '_sitebuiltins' from '/usr/lib/python3.8/_sitebuiltins.py'>, '_locale': <module '_locale' (built-in)>, '_bootlocale': <module '_bootlocale' from '/usr/lib/python3.8/_bootlocale.py'>, 'types': <module 'types' from '/usr/lib/python3.8/types.py'>, 'importlib._bootstrap': <module 'importlib._bootstrap' (frozen)>, 'importlib._bootstrap_external': <module 'importlib._bootstrap_external' (frozen)>, 'warnings': <module 'warnings' from '/usr/lib/python3.8/warnings.py'>, 'importlib': <module 'importlib' from '/usr/lib/python3.8/importlib/__init__.py'>, 'importlib.machinery': <module 'importlib.machinery' from '/usr/lib/python3.8/importlib/machinery.py'>, 'importlib.abc': <module 'importlib.abc' from '/usr/lib/python3.8/importlib/abc.py'>, '_operator': <module '_operator' (built-in)>, 'operator': <module 'operator' from '/usr/lib/python3.8/operator.py'>, 'keyword': <module 'keyword' from '/usr/lib/python3.8/keyword.py'>, '_heapq': <module '_heapq' (built-in)>, 'heapq': <module 'heapq' from '/usr/lib/python3.8/heapq.py'>, 'itertools': <module 'itertools' (built-in)>, 'reprlib': <module 'reprlib' from '/usr/lib/python3.8/reprlib.py'>, '_collections': <module '_collections' (built-in)>, 'collections': <module 'collections' from '/usr/lib/python3.8/collections/__init__.py'>, '_functools': <module '_functools' (built-in)>, 'functools': <module 'functools' from '/usr/lib/python3.8/functools.py'>, 'contextlib': <module 'contextlib' from '/usr/lib/python3.8/contextlib.py'>, 'importlib.util': <module 'importlib.util' from '/usr/lib/python3.8/importlib/util.py'>, 'mpl_toolkits': <module 'mpl_toolkits' from '/usr/lib/python3/dist-packages/mpl_toolkits/__init__.py'>, 'repoze': <module 'repoze' (namespace)>, 'virtualenvwrapper': <module 'virtualenvwrapper' (namespace)>, 'zope': <module 'zope' from '/usr/lib/python3/dist-packages/zope/__init__.py'>, 'sitecustomize': <module 'sitecustomize' from '/usr/lib/python3.8/sitecustomize.py'>, 'site': <module 'site' from '/usr/lib/python3.8/site.py'>, 'enum': <module 'enum' from '/usr/lib/python3.8/enum.py'>, '_sre': <module '_sre' (built-in)>, 'sre_constants': <module 'sre_constants' from '/usr/lib/python3.8/sre_constants.py'>, 'sre_parse': <module 'sre_parse' from '/usr/lib/python3.8/sre_parse.py'>, 'sre_compile': <module 'sre_compile' from '/usr/lib/python3.8/sre_compile.py'>, 'copyreg': <module 'copyreg' from '/usr/lib/python3.8/copyreg.py'>, 're': <module 're' from '/usr/lib/python3.8/re.py'>, '_csv': <module '_csv' (built-in)>, 'csv': <module 'csv' from '/usr/lib/python3.8/csv.py'>, 'email': <module 'email' from '/usr/lib/python3.8/email/__init__.py'>, 'fnmatch': <module 'fnmatch' from '/usr/lib/python3.8/fnmatch.py'>, 'ntpath': <module 'ntpath' from '/usr/lib/python3.8/ntpath.py'>, 'errno': <module 'errno' (built-in)>, 'urllib': <module 'urllib' from '/usr/lib/python3.8/urllib/__init__.py'>, 'urllib.parse': <module 'urllib.parse' from '/usr/lib/python3.8/urllib/parse.py'>, 'pathlib': <module 'pathlib' from '/usr/lib/python3.8/pathlib.py'>, 'binascii': <module 'binascii' (built-in)>, 'zlib': <module 'zlib' (built-in)>, '_compression': <module '_compression' from '/usr/lib/python3.8/_compression.py'>, '_weakrefset': <module '_weakrefset' from '/usr/lib/python3.8/_weakrefset.py'>, 'threading': <module 'threading' from '/usr/lib/python3.8/threading.py'>, '_bz2': <module '_bz2' from '/usr/lib/python3.8/lib-dynload/_bz2.cpython-38-x86_64-linux-gnu.so'>, 'bz2': <module 'bz2' from '/usr/lib/python3.8/bz2.py'>, '_lzma': <module '_lzma' from '/usr/lib/python3.8/lib-dynload/_lzma.cpython-38-x86_64-linux-gnu.so'>, 'lzma': <module 'lzma' from '/usr/lib/python3.8/lzma.py'>, 'pwd': <module 'pwd' (built-in)>, 'grp': <module 'grp' (built-in)>, 'shutil': <module 'shutil' from '/usr/lib/python3.8/shutil.py'>, '_struct': <module '_struct' (built-in)>, 'struct': <module 'struct' from '/usr/lib/python3.8/struct.py'>, 'zipfile': <module 'zipfile' from '/usr/lib/python3.8/zipfile.py'>, '__future__': <module '__future__' from '/usr/lib/python3.8/__future__.py'>, 'weakref': <module 'weakref' from '/usr/lib/python3.8/weakref.py'>, 'pkgutil': <module 'pkgutil' from '/usr/lib/python3.8/pkgutil.py'>, 'backports': <module 'backports' from '/usr/local/lib/python3.8/dist-packages/backports/__init__.py'>, 'collections.abc': <module 'collections.abc' from '/usr/lib/python3.8/collections/abc.py'>, 'backports.configparser.helpers': <module 'backports.configparser.helpers' from '/usr/local/lib/python3.8/dist-packages/backports/configparser/helpers.py'>, 'backports.configparser': <module 'backports.configparser' from '/usr/local/lib/python3.8/dist-packages/backports/configparser/__init__.py'>, 'configparser': <module 'configparser' from '/usr/local/lib/python3.8/dist-packages/configparser.py'>, 'importlib.metadata': <module 'importlib.metadata' from '/usr/lib/python3.8/importlib/metadata.py'>, '_string': <module '_string' (built-in)>, 'string': <module 'string' from '/usr/lib/python3.8/string.py'>, 'cmd': <module 'cmd' from '/usr/lib/python3.8/cmd.py'>, '_opcode': <module '_opcode' from '/usr/lib/python3.8/lib-dynload/_opcode.cpython-38-x86_64-linux-gnu.so'>, 'opcode': <module 'opcode' from '/usr/lib/python3.8/opcode.py'>, 'dis': <module 'dis' from '/usr/lib/python3.8/dis.py'>, 'token': <module 'token' from '/usr/lib/python3.8/token.py'>, 'tokenize': <module 'tokenize' from '/usr/lib/python3.8/tokenize.py'>, 'linecache': <module 'linecache' from '/usr/lib/python3.8/linecache.py'>, 'inspect': <module 'inspect' from '/usr/lib/python3.8/inspect.py'>, 'bdb': <module 'bdb' from '/usr/lib/python3.8/bdb.py'>, 'traceback': <module 'traceback' from '/usr/lib/python3.8/traceback.py'>, 'codeop': <module 'codeop' from '/usr/lib/python3.8/codeop.py'>, 'code': <module 'code' from '/usr/lib/python3.8/code.py'>, 'glob': <module 'glob' from '/usr/lib/python3.8/glob.py'>, 'pprint': <module 'pprint' from '/usr/lib/python3.8/pprint.py'>, 'signal': <module 'signal' from '/usr/lib/python3.8/signal.py'>, 'pdb': <module 'pdb' from '/usr/lib/python3.8/pdb.py'>, 'readline': <module 'readline' from '/usr/lib/python3.8/lib-dynload/readline.cpython-38-x86_64-linux-gnu.so'>, 'locale': <module 'locale' from '/usr/lib/python3.8/locale.py'>, 'gettext': <module 'gettext' from '/usr/lib/python3.8/gettext.py'>, 'argparse': <module 'argparse' from '/usr/lib/python3.8/argparse.py'>, 'atexit': <module 'atexit' (built-in)>, 'logging': <module 'logging' from '/usr/lib/python3.8/logging/__init__.py'>, 'multiprocessing.process': <module 'multiprocessing.process' from '/usr/lib/python3.8/multiprocessing/process.py'>, '_compat_pickle': <module '_compat_pickle' from '/usr/lib/python3.8/_compat_pickle.py'>, '_pickle': <module '_pickle' (built-in)>, 'pickle': <module 'pickle' from '/usr/lib/python3.8/pickle.py'>, '_socket': <module '_socket' (built-in)>, 'math': <module 'math' (built-in)>, 'select': <module 'select' (built-in)>, 'selectors': <module 'selectors' from '/usr/lib/python3.8/selectors.py'>, 'socket': <module 'socket' from '/usr/lib/python3.8/socket.py'>, 'array': <module 'array' (built-in)>, 'multiprocessing.reduction': <module 'multiprocessing.reduction' from '/usr/lib/python3.8/multiprocessing/reduction.py'>, 'multiprocessing.context': <module 'multiprocessing.context' from '/usr/lib/python3.8/multiprocessing/context.py'>, '__mp_main__': <module '__main__' from '/usr/local/bin/pelican'>, 'multiprocessing': <module 'multiprocessing' from '/usr/lib/python3.8/multiprocessing/__init__.py'>, 'pelican.log': <module 'pelican.log' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/log.py'>, '_datetime': <module '_datetime' (built-in)>, 'datetime': <module 'datetime' from '/usr/lib/python3.8/datetime.py'>, 'calendar': <module 'calendar' from '/usr/lib/python3.8/calendar.py'>, 'markupsafe._compat': <module 'markupsafe._compat' from '/usr/lib/python3/dist-packages/markupsafe/_compat.py'>, 'markupsafe._speedups': <module 'markupsafe._speedups' from '/usr/lib/python3/dist-packages/markupsafe/_speedups.cpython-38-x86_64-linux-gnu.so'>, 'markupsafe': <module 'markupsafe' from '/usr/lib/python3/dist-packages/markupsafe/__init__.py'>, '_bisect': <module '_bisect' (built-in)>, 'bisect': <module 'bisect' from '/usr/lib/python3.8/bisect.py'>, '_sha512': <module '_sha512' (built-in)>, '_random': <module '_random' (built-in)>, 'random': <module 'random' from '/usr/lib/python3.8/random.py'>, 'tempfile': <module 'tempfile' from '/usr/lib/python3.8/tempfile.py'>, '_hashlib': <module '_hashlib' from '/usr/lib/python3.8/lib-dynload/_hashlib.cpython-38-x86_64-linux-gnu.so'>, '_blake2': <module '_blake2' (built-in)>, '_sha3': <module '_sha3' (built-in)>, 'hashlib': <module 'hashlib' from '/usr/lib/python3.8/hashlib.py'>, 'jinja2._compat': <module 'jinja2._compat' from '/usr/lib/python3/dist-packages/jinja2/_compat.py'>, '_json': <module '_json' from '/usr/lib/python3.8/lib-dynload/_json.cpython-38-x86_64-linux-gnu.so'>, 'json.scanner': <module 'json.scanner' from '/usr/lib/python3.8/json/scanner.py'>, 'json.decoder': <module 'json.decoder' from '/usr/lib/python3.8/json/decoder.py'>, 'json.encoder': <module 'json.encoder' from '/usr/lib/python3.8/json/encoder.py'>, 'json': <module 'json' from '/usr/lib/python3.8/json/__init__.py'>, 'jinja2.utils': <module 'jinja2.utils' from '/usr/lib/python3/dist-packages/jinja2/utils.py'>, 'jinja2.bccache': <module 'jinja2.bccache' from '/usr/lib/python3/dist-packages/jinja2/bccache.py'>, 'jinja2.nodes': <module 'jinja2.nodes' from '/usr/lib/python3/dist-packages/jinja2/nodes.py'>, 'jinja2.exceptions': <module 'jinja2.exceptions' from '/usr/lib/python3/dist-packages/jinja2/exceptions.py'>, 'jinja2.visitor': <module 'jinja2.visitor' from '/usr/lib/python3/dist-packages/jinja2/visitor.py'>, 'jinja2.idtracking': <module 'jinja2.idtracking' from '/usr/lib/python3/dist-packages/jinja2/idtracking.py'>, 'jinja2.optimizer': <module 'jinja2.optimizer' from '/usr/lib/python3/dist-packages/jinja2/optimizer.py'>, 'jinja2.compiler': <module 'jinja2.compiler' from '/usr/lib/python3/dist-packages/jinja2/compiler.py'>, 'jinja2.runtime': <module 'jinja2.runtime' from '/usr/lib/python3/dist-packages/jinja2/runtime.py'>, 'jinja2.filters': <module 'jinja2.filters' from '/usr/lib/python3/dist-packages/jinja2/filters.py'>, 'numbers': <module 'numbers' from '/usr/lib/python3.8/numbers.py'>, '_decimal': <module '_decimal' from '/usr/lib/python3.8/lib-dynload/_decimal.cpython-38-x86_64-linux-gnu.so'>, 'decimal': <module 'decimal' from '/usr/lib/python3.8/decimal.py'>, 'jinja2.tests': <module 'jinja2.tests' from '/usr/lib/python3/dist-packages/jinja2/tests.py'>, 'jinja2.defaults': <module 'jinja2.defaults' from '/usr/lib/python3/dist-packages/jinja2/defaults.py'>, '_ast': <module '_ast' (built-in)>, 'ast': <module 'ast' from '/usr/lib/python3.8/ast.py'>, 'unicodedata': <module 'unicodedata' (built-in)>, 'jinja2._identifier': <module 'jinja2._identifier' from '/usr/lib/python3/dist-packages/jinja2/_identifier.py'>, 'jinja2.lexer': <module 'jinja2.lexer' from '/usr/lib/python3/dist-packages/jinja2/lexer.py'>, 'jinja2.parser': <module 'jinja2.parser' from '/usr/lib/python3/dist-packages/jinja2/parser.py'>, 'jinja2.environment': <module 'jinja2.environment' from '/usr/lib/python3/dist-packages/jinja2/environment.py'>, 'jinja2.loaders': <module 'jinja2.loaders' from '/usr/lib/python3/dist-packages/jinja2/loaders.py'>, 'jinja2': <module 'jinja2' from '/usr/lib/python3/dist-packages/jinja2/__init__.py'>, 'html.entities': <module 'html.entities' from '/usr/lib/python3.8/html/entities.py'>, 'html': <module 'html' from '/usr/lib/python3.8/html/__init__.py'>, '_markupbase': <module '_markupbase' from '/usr/lib/python3.8/_markupbase.py'>, 'html.parser': <module 'html.parser' from '/usr/lib/python3.8/html/parser.py'>, 'dateutil._version': <module 'dateutil._version' from '/usr/lib/python3/dist-packages/dateutil/_version.py'>, 'dateutil': <module 'dateutil' from '/usr/lib/python3/dist-packages/dateutil/__init__.py'>, 'six': <module 'six' from '/usr/lib/python3/dist-packages/six.py'>, 'dateutil._common': <module 'dateutil._common' from '/usr/lib/python3/dist-packages/dateutil/_common.py'>, 'dateutil.relativedelta': <module 'dateutil.relativedelta' from '/usr/lib/python3/dist-packages/dateutil/relativedelta.py'>, 'six.moves': <module 'six.moves' (<six._SixMetaPathImporter object at 0x7f8e53cb2e20>)>, 'dateutil.tz._common': <module 'dateutil.tz._common' from '/usr/lib/python3/dist-packages/dateutil/tz/_common.py'>, 'dateutil.tz._factories': <module 'dateutil.tz._factories' from '/usr/lib/python3/dist-packages/dateutil/tz/_factories.py'>, 'dateutil.tz.tz': <module 'dateutil.tz.tz' from '/usr/lib/python3/dist-packages/dateutil/tz/tz.py'>, 'dateutil.tz': <module 'dateutil.tz' from '/usr/lib/python3/dist-packages/dateutil/tz/__init__.py'>, 'dateutil.parser._parser': <module 'dateutil.parser._parser' from '/usr/lib/python3/dist-packages/dateutil/parser/_parser.py'>, 'dateutil.parser.isoparser': <module 'dateutil.parser.isoparser' from '/usr/lib/python3/dist-packages/dateutil/parser/isoparser.py'>, 'dateutil.parser': <module 'dateutil.parser' from '/usr/lib/python3/dist-packages/dateutil/parser/__init__.py'>, 'pytz.exceptions': <module 'pytz.exceptions' from '/usr/lib/python3/dist-packages/pytz/exceptions.py'>, 'pytz.lazy': <module 'pytz.lazy' from '/usr/lib/python3/dist-packages/pytz/lazy.py'>, 'pytz.tzinfo': <module 'pytz.tzinfo' from '/usr/lib/python3/dist-packages/pytz/tzinfo.py'>, 'pytz.tzfile': <module 'pytz.tzfile' from '/usr/lib/python3/dist-packages/pytz/tzfile.py'>, 'pytz': <module 'pytz' from '/usr/lib/python3/dist-packages/pytz/__init__.py'>, 'pelican.utils': <module 'pelican.utils' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/utils.py'>, 'pelican.cache': <module 'pelican.cache' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/cache.py'>, 'copy': <module 'copy' from '/usr/lib/python3.8/copy.py'>, 'pelican.plugins': <module 'pelican.plugins' (namespace)>, 'blinker._saferef': <module 'blinker._saferef' from '/usr/lib/python3/dist-packages/blinker/_saferef.py'>, 'blinker._utilities': <module 'blinker._utilities' from '/usr/lib/python3/dist-packages/blinker/_utilities.py'>, 'blinker.base': <module 'blinker.base' from '/usr/lib/python3/dist-packages/blinker/base.py'>, 'blinker': <module 'blinker' from '/usr/lib/python3/dist-packages/blinker/__init__.py'>, 'pelican.plugins.signals': <module 'pelican.plugins.signals' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/signals.py'>, 'pelican.settings': <module 'pelican.settings' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/settings.py'>, 'pelican.urlwrappers': <module 'pelican.urlwrappers' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/urlwrappers.py'>, 'pelican.contents': <module 'pelican.contents' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/contents.py'>, 'docutils': <module 'docutils' from '/usr/lib/python3/dist-packages/docutils/__init__.py'>, 'textwrap': <module 'textwrap' from '/usr/lib/python3.8/textwrap.py'>, 'optparse': <module 'optparse' from '/usr/lib/python3.8/optparse.py'>, 'docutils.nodes': <module 'docutils.nodes' from '/usr/lib/python3/dist-packages/docutils/nodes.py'>, 'docutils.utils.error_reporting': <module 'docutils.utils.error_reporting' from '/usr/lib/python3/dist-packages/docutils/utils/error_reporting.py'>, 'docutils.io': <module 'docutils.io' from '/usr/lib/python3/dist-packages/docutils/io.py'>, 'docutils.utils': <module 'docutils.utils' from '/usr/lib/python3/dist-packages/docutils/utils/__init__.py'>, 'docutils.frontend': <module 'docutils.frontend' from '/usr/lib/python3/dist-packages/docutils/frontend.py'>, 'docutils.parsers': <module 'docutils.parsers' from '/usr/lib/python3/dist-packages/docutils/parsers/__init__.py'>, 'docutils.languages': <module 'docutils.languages' from '/usr/lib/python3/dist-packages/docutils/languages/__init__.py'>, 'docutils.transforms': <module 'docutils.transforms' from '/usr/lib/python3/dist-packages/docutils/transforms/__init__.py'>, 'docutils.utils.smartquotes': <module 'docutils.utils.smartquotes' from '/usr/lib/python3/dist-packages/docutils/utils/smartquotes.py'>, 'docutils.transforms.universal': <module 'docutils.transforms.universal' from '/usr/lib/python3/dist-packages/docutils/transforms/universal.py'>, 'docutils.readers': <module 'docutils.readers' from '/usr/lib/python3/dist-packages/docutils/readers/__init__.py'>, 'docutils.writers': <module 'docutils.writers' from '/usr/lib/python3/dist-packages/docutils/writers/__init__.py'>, 'docutils.readers.doctree': <module 'docutils.readers.doctree' from '/usr/lib/python3/dist-packages/docutils/readers/doctree.py'>, 'docutils.core': <module 'docutils.core' from '/usr/lib/python3/dist-packages/docutils/core.py'>, 'docutils.statemachine': <module 'docutils.statemachine' from '/usr/lib/python3/dist-packages/docutils/statemachine.py'>, 'docutils.parsers.rst.languages': <module 'docutils.parsers.rst.languages' from '/usr/lib/python3/dist-packages/docutils/parsers/rst/languages/__init__.py'>, 'docutils.parsers.rst.languages.en': <module 'docutils.parsers.rst.languages.en' from '/usr/lib/python3/dist-packages/docutils/parsers/rst/languages/en.py'>, 'docutils.parsers.rst.directives': <module 'docutils.parsers.rst.directives' from '/usr/lib/python3/dist-packages/docutils/parsers/rst/directives/__init__.py'>, 'platform': <module 'platform' from '/usr/lib/python3.8/platform.py'>, 'xml': <module 'xml' from '/usr/lib/python3.8/xml/__init__.py'>, 'xml.parsers': <module 'xml.parsers' from '/usr/lib/python3.8/xml/parsers/__init__.py'>, 'pyexpat.errors': <module 'pyexpat.errors'>, 'pyexpat.model': <module 'pyexpat.model'>, 'pyexpat': <module 'pyexpat' (built-in)>, 'xml.parsers.expat.model': <module 'pyexpat.model'>, 'xml.parsers.expat.errors': <module 'pyexpat.errors'>, 'xml.parsers.expat': <module 'xml.parsers.expat' from '/usr/lib/python3.8/xml/parsers/expat.py'>, 'plistlib': <module 'plistlib' from '/usr/lib/python3.8/plistlib.py'>, 'email.errors': <module 'email.errors' from '/usr/lib/python3.8/email/errors.py'>, 'email.quoprimime': <module 'email.quoprimime' from '/usr/lib/python3.8/email/quoprimime.py'>, 'base64': <module 'base64' from '/usr/lib/python3.8/base64.py'>, 'email.base64mime': <module 'email.base64mime' from '/usr/lib/python3.8/email/base64mime.py'>, 'quopri': <module 'quopri' from '/usr/lib/python3.8/quopri.py'>, 'email.encoders': <module 'email.encoders' from '/usr/lib/python3.8/email/encoders.py'>, 'email.charset': <module 'email.charset' from '/usr/lib/python3.8/email/charset.py'>, 'email.header': <module 'email.header' from '/usr/lib/python3.8/email/header.py'>, 'email._parseaddr': <module 'email._parseaddr' from '/usr/lib/python3.8/email/_parseaddr.py'>, 'email.utils': <module 'email.utils' from '/usr/lib/python3.8/email/utils.py'>, 'email._policybase': <module 'email._policybase' from '/usr/lib/python3.8/email/_policybase.py'>, 'email.feedparser': <module 'email.feedparser' from '/usr/lib/python3.8/email/feedparser.py'>, 'email.parser': <module 'email.parser' from '/usr/lib/python3.8/email/parser.py'>, 'pkg_resources.extern': <module 'pkg_resources.extern' from '/usr/lib/python3/dist-packages/pkg_resources/extern/__init__.py'>, 'pkg_resources._vendor': <module 'pkg_resources._vendor' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/__init__.py'>, 'pkg_resources._vendor.appdirs': <module 'pkg_resources._vendor.appdirs' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/appdirs.py'>, 'pkg_resources.extern.appdirs': <module 'pkg_resources._vendor.appdirs' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/appdirs.py'>, 'pkg_resources._vendor.packaging.__about__': <module 'pkg_resources._vendor.packaging.__about__' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/__about__.py'>, 'pkg_resources._vendor.packaging': <module 'pkg_resources._vendor.packaging' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/__init__.py'>, 'pkg_resources.extern.packaging': <module 'pkg_resources._vendor.packaging' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/__init__.py'>, 'pkg_resources.extern.packaging._structures': <module 'pkg_resources.extern.packaging._structures' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/_structures.py'>, 'pkg_resources.extern.packaging._typing': <module 'pkg_resources.extern.packaging._typing' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/_typing.py'>, 'pkg_resources.extern.packaging.version': <module 'pkg_resources.extern.packaging.version' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/version.py'>, 'pkg_resources.extern.packaging._compat': <module 'pkg_resources.extern.packaging._compat' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/_compat.py'>, 'pkg_resources.extern.packaging.utils': <module 'pkg_resources.extern.packaging.utils' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/utils.py'>, 'pkg_resources.extern.packaging.specifiers': <module 'pkg_resources.extern.packaging.specifiers' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/specifiers.py'>, 'pkg_resources._vendor.pyparsing': <module 'pkg_resources._vendor.pyparsing' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/pyparsing.py'>, 'pkg_resources.extern.pyparsing': <module 'pkg_resources._vendor.pyparsing' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/pyparsing.py'>, 'pkg_resources.extern.packaging.markers': <module 'pkg_resources.extern.packaging.markers' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/markers.py'>, 'pkg_resources.extern.packaging.requirements': <module 'pkg_resources.extern.packaging.requirements' from '/usr/lib/python3/dist-packages/pkg_resources/_vendor/packaging/requirements.py'>, 'sysconfig': <module 'sysconfig' from '/usr/lib/python3.8/sysconfig.py'>, 'pkg_resources': <module 'pkg_resources' from '/usr/lib/python3/dist-packages/pkg_resources/__init__.py'>, 'pygments.util': <module 'pygments.util' from '/usr/lib/python3/dist-packages/pygments/util.py'>, 'pygments': <module 'pygments' from '/usr/lib/python3/dist-packages/pygments/__init__.py'>, 'pygments.lexers._mapping': <module 'pygments.lexers._mapping' from '/usr/lib/python3/dist-packages/pygments/lexers/_mapping.py'>, 'pygments.modeline': <module 'pygments.modeline' from '/usr/lib/python3/dist-packages/pygments/modeline.py'>, 'pygments.plugin': <module 'pygments.plugin' from '/usr/lib/python3/dist-packages/pygments/plugin.py'>, 'pygments.lexers': <module 'pygments.lexers' from '/usr/lib/python3/dist-packages/pygments/lexers/__init__.py'>, 'pygments.formatters._mapping': <module 'pygments.formatters._mapping' from '/usr/lib/python3/dist-packages/pygments/formatters/_mapping.py'>, 'pygments.formatters': <module 'pygments.formatters' from '/usr/lib/python3/dist-packages/pygments/formatters/__init__.py'>, 'pygments.styles': <module 'pygments.styles' from '/usr/lib/python3/dist-packages/pygments/styles/__init__.py'>, 'pygments.formatter': <module 'pygments.formatter' from '/usr/lib/python3/dist-packages/pygments/formatter.py'>, 'pygments.token': <module 'pygments.token' from '/usr/lib/python3/dist-packages/pygments/token.py'>, 'pygments.formatters.html': <module 'pygments.formatters.html' from '/usr/lib/python3/dist-packages/pygments/formatters/html.py'>, 'docutils.utils.code_analyzer': <module 'docutils.utils.code_analyzer' from '/usr/lib/python3/dist-packages/docutils/utils/code_analyzer.py'>, 'docutils.parsers.rst.roles': <module 'docutils.parsers.rst.roles' from '/usr/lib/python3/dist-packages/docutils/parsers/rst/roles.py'>, 'docutils.parsers.rst.tableparser': <module 'docutils.parsers.rst.tableparser' from '/usr/lib/python3/dist-packages/docutils/parsers/rst/tableparser.py'>, 'docutils.utils.punctuation_chars': <module 'docutils.utils.punctuation_chars' from '/usr/lib/python3/dist-packages/docutils/utils/punctuation_chars.py'>, 'docutils.utils.urischemes': <module 'docutils.utils.urischemes' from '/usr/lib/python3/dist-packages/docutils/utils/urischemes.py'>, 'roman': <module 'roman' from '/usr/lib/python3/dist-packages/roman.py'>, 'docutils.parsers.rst.states': <module 'docutils.parsers.rst.states' from '/usr/lib/python3/dist-packages/docutils/parsers/rst/states.py'>, 'docutils.parsers.rst': <module 'docutils.parsers.rst' from '/usr/lib/python3/dist-packages/docutils/parsers/rst/__init__.py'>, 'docutils.transforms.writer_aux': <module 'docutils.transforms.writer_aux' from '/usr/lib/python3/dist-packages/docutils/transforms/writer_aux.py'>, 'PIL._version': <module 'PIL._version' from '/usr/lib/python3/dist-packages/PIL/_version.py'>, 'PIL': <module 'PIL' from '/usr/lib/python3/dist-packages/PIL/__init__.py'>, 'xml.etree': <module 'xml.etree' from '/usr/lib/python3.8/xml/etree/__init__.py'>, 'xml.etree.ElementPath': <module 'xml.etree.ElementPath' from '/usr/lib/python3.8/xml/etree/ElementPath.py'>, '_elementtree': <module '_elementtree' (built-in)>, 'xml.etree.ElementTree': <module 'xml.etree.ElementTree' from '/usr/lib/python3.8/xml/etree/ElementTree.py'>, 'PIL.ImageMode': <module 'PIL.ImageMode' from '/usr/lib/python3/dist-packages/PIL/ImageMode.py'>, 'PIL.TiffTags': <module 'PIL.TiffTags' from '/usr/lib/python3/dist-packages/PIL/TiffTags.py'>, 'PIL._binary': <module 'PIL._binary' from '/usr/lib/python3/dist-packages/PIL/_binary.py'>, 'PIL._util': <module 'PIL._util' from '/usr/lib/python3/dist-packages/PIL/_util.py'>, 'PIL._imaging': <module 'PIL._imaging' from '/usr/lib/python3/dist-packages/PIL/_imaging.cpython-38-x86_64-linux-gnu.so'>, 'PIL.Image': <module 'PIL.Image' from '/usr/lib/python3/dist-packages/PIL/Image.py'>, 'docutils.utils.math': <module 'docutils.utils.math' from '/usr/lib/python3/dist-packages/docutils/utils/math/__init__.py'>, 'docutils.utils.math.unichar2tex': <module 'docutils.utils.math.unichar2tex' from '/usr/lib/python3/dist-packages/docutils/utils/math/unichar2tex.py'>, 'docutils.utils.math.math2html': <module 'docutils.utils.math.math2html' from '/usr/lib/python3/dist-packages/docutils/utils/math/math2html.py'>, 'docutils.utils.math.tex2unichar': <module 'docutils.utils.math.tex2unichar' from '/usr/lib/python3/dist-packages/docutils/utils/math/tex2unichar.py'>, 'docutils.utils.math.latex2mathml': <module 'docutils.utils.math.latex2mathml' from '/usr/lib/python3/dist-packages/docutils/utils/math/latex2mathml.py'>, '_posixsubprocess': <module '_posixsubprocess' (built-in)>, 'subprocess': <module 'subprocess' from '/usr/lib/python3.8/subprocess.py'>, 'docutils.utils.math.tex2mathml_extern': <module 'docutils.utils.math.tex2mathml_extern' from '/usr/lib/python3/dist-packages/docutils/utils/math/tex2mathml_extern.py'>, 'http': <module 'http' from '/usr/lib/python3.8/http/__init__.py'>, 'uu': <module 'uu' from '/usr/lib/python3.8/uu.py'>, 'email._encoded_words': <module 'email._encoded_words' from '/usr/lib/python3.8/email/_encoded_words.py'>, 'email.iterators': <module 'email.iterators' from '/usr/lib/python3.8/email/iterators.py'>, 'email.message': <module 'email.message' from '/usr/lib/python3.8/email/message.py'>, '_ssl': <module '_ssl' from '/usr/lib/python3.8/lib-dynload/_ssl.cpython-38-x86_64-linux-gnu.so'>, 'ssl': <module 'ssl' from '/usr/lib/python3.8/ssl.py'>, 'http.client': <module 'http.client' from '/usr/lib/python3.8/http/client.py'>, 'urllib.response': <module 'urllib.response' from '/usr/lib/python3.8/urllib/response.py'>, 'urllib.error': <module 'urllib.error' from '/usr/lib/python3.8/urllib/error.py'>, 'urllib.request': <module 'urllib.request' from '/usr/lib/python3.8/urllib/request.py'>, 'docutils.writers._html_base': <module 'docutils.writers._html_base' from '/usr/lib/python3/dist-packages/docutils/writers/_html_base.py'>, 'docutils.writers.html4css1': <module 'docutils.writers.html4css1' from '/usr/lib/python3/dist-packages/docutils/writers/html4css1/__init__.py'>, 'pygments.filter': <module 'pygments.filter' from '/usr/lib/python3/dist-packages/pygments/filter.py'>, 'pygments.filters': <module 'pygments.filters' from '/usr/lib/python3/dist-packages/pygments/filters/__init__.py'>, 'pygments.regexopt': <module 'pygments.regexopt' from '/usr/lib/python3/dist-packages/pygments/regexopt.py'>, 'pygments.lexer': <module 'pygments.lexer' from '/usr/lib/python3/dist-packages/pygments/lexer.py'>, 'pygments.lexers.special': <module 'pygments.lexers.special' from '/usr/lib/python3/dist-packages/pygments/lexers/special.py'>, 'pelican.rstdirectives': <module 'pelican.rstdirectives' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/rstdirectives.py'>, 'markdown.pep562': <module 'markdown.pep562' from '/usr/lib/python3/dist-packages/markdown/pep562.py'>, 'markdown.util': <module 'markdown.util' from '/usr/lib/python3/dist-packages/markdown/util.py'>, 'markdown.preprocessors': <module 'markdown.preprocessors' from '/usr/lib/python3/dist-packages/markdown/preprocessors.py'>, 'markdown.blockparser': <module 'markdown.blockparser' from '/usr/lib/python3/dist-packages/markdown/blockparser.py'>, 'markdown.blockprocessors': <module 'markdown.blockprocessors' from '/usr/lib/python3/dist-packages/markdown/blockprocessors.py'>, 'markdown.inlinepatterns': <module 'markdown.inlinepatterns' from '/usr/lib/python3/dist-packages/markdown/inlinepatterns.py'>, 'markdown.treeprocessors': <module 'markdown.treeprocessors' from '/usr/lib/python3/dist-packages/markdown/treeprocessors.py'>, 'markdown.postprocessors': <module 'markdown.postprocessors' from '/usr/lib/python3/dist-packages/markdown/postprocessors.py'>, 'markdown.extensions': <module 'markdown.extensions' from '/usr/lib/python3/dist-packages/markdown/extensions/__init__.py'>, 'markdown.serializers': <module 'markdown.serializers' from '/usr/lib/python3/dist-packages/markdown/serializers.py'>, 'markdown.core': <module 'markdown.core' from '/usr/lib/python3/dist-packages/markdown/core.py'>, 'markdown.__meta__': <module 'markdown.__meta__' from '/usr/lib/python3/dist-packages/markdown/__meta__.py'>, 'markdown': <module 'markdown' from '/usr/lib/python3/dist-packages/markdown/__init__.py'>, 'pelican.readers': <module 'pelican.readers' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/readers.py'>, 'pelican.generators': <module 'pelican.generators' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/generators.py'>, 'pelican.plugins._utils': <module 'pelican.plugins._utils' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/_utils.py'>, 'mimetypes': <module 'mimetypes' from '/usr/lib/python3.8/mimetypes.py'>, 'socketserver': <module 'socketserver' from '/usr/lib/python3.8/socketserver.py'>, 'http.server': <module 'http.server' from '/usr/lib/python3.8/http/server.py'>, 'pelican.server': <module 'pelican.server' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/server.py'>, 'feedgenerator.django': <module 'feedgenerator.django' from '/usr/lib/python3/dist-packages/feedgenerator/django/__init__.py'>, 'feedgenerator.django.utils': <module 'feedgenerator.django.utils' from '/usr/lib/python3/dist-packages/feedgenerator/django/utils/__init__.py'>, 'xml.sax.handler': <module 'xml.sax.handler' from '/usr/lib/python3.8/xml/sax/handler.py'>, 'xml.sax._exceptions': <module 'xml.sax._exceptions' from '/usr/lib/python3.8/xml/sax/_exceptions.py'>, 'xml.sax.xmlreader': <module 'xml.sax.xmlreader' from '/usr/lib/python3.8/xml/sax/xmlreader.py'>, 'xml.sax': <module 'xml.sax' from '/usr/lib/python3.8/xml/sax/__init__.py'>, 'xml.sax.saxutils': <module 'xml.sax.saxutils' from '/usr/lib/python3.8/xml/sax/saxutils.py'>, 'feedgenerator.django.utils.xmlutils': <module 'feedgenerator.django.utils.xmlutils' from '/usr/lib/python3/dist-packages/feedgenerator/django/utils/xmlutils.py'>, 'django.utils.six.moves': <module 'moves'>, 'feedgenerator.django.utils.six': <module 'feedgenerator.django.utils.six' from '/usr/lib/python3/dist-packages/feedgenerator/django/utils/six.py'>, 'feedgenerator.django.utils.functional': <module 'feedgenerator.django.utils.functional' from '/usr/lib/python3/dist-packages/feedgenerator/django/utils/functional.py'>, 'feedgenerator.django.utils.encoding': <module 'feedgenerator.django.utils.encoding' from '/usr/lib/python3/dist-packages/feedgenerator/django/utils/encoding.py'>, 'feedgenerator.django.utils.datetime_safe': <module 'feedgenerator.django.utils.datetime_safe' from '/usr/lib/python3/dist-packages/feedgenerator/django/utils/datetime_safe.py'>, 'feedgenerator.django.utils.timezone': <module 'feedgenerator.django.utils.timezone' from '/usr/lib/python3/dist-packages/feedgenerator/django/utils/timezone.py'>, 'feedgenerator.django.utils.feedgenerator': <module 'feedgenerator.django.utils.feedgenerator' from '/usr/lib/python3/dist-packages/feedgenerator/django/utils/feedgenerator.py'>, 'feedgenerator': <module 'feedgenerator' from '/usr/lib/python3/dist-packages/feedgenerator/__init__.py'>, 'pelican.paginator': <module 'pelican.paginator' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/paginator.py'>, 'pelican.writers': <module 'pelican.writers' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/writers.py'>, 'pelican': <module 'pelican' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/__init__.py'>, 'pelican.__main__': <module 'pelican.__main__' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/__main__.py'>, 'pelican.plugins.code_include.code_include': <module 'pelican.plugins.code_include.code_include' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/code_include/code_include.py'>, 'pelican.plugins.code_include': <module 'pelican.plugins.code_include' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/code_include/__init__.py'>, 'pelican.plugins.collate_content.collate_content': <module 'pelican.plugins.collate_content.collate_content' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/collate_content/collate_content.py'>, 'pelican.plugins.collate_content': <module 'pelican.plugins.collate_content' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/collate_content/__init__.py'>, 'pelican.plugins.dateish.dateish': <module 'pelican.plugins.dateish.dateish' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/dateish/dateish.py'>, 'pelican.plugins.dateish': <module 'pelican.plugins.dateish' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/dateish/__init__.py'>, 'pelican.plugins.just_table.just_table': <module 'pelican.plugins.just_table.just_table' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/just_table/just_table.py'>, 'pelican.plugins.just_table': <module 'pelican.plugins.just_table' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/just_table/__init__.py'>, 'pelican.plugins.sitemap.sitemap': <module 'pelican.plugins.sitemap.sitemap' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/sitemap/sitemap.py'>, 'pelican.plugins.sitemap': <module 'pelican.plugins.sitemap' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/sitemap/__init__.py'>, 'pelican.plugins.tag_cloud.tag_cloud': <module 'pelican.plugins.tag_cloud.tag_cloud' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/tag_cloud/tag_cloud.py'>, 'pelican.plugins.tag_cloud': <module 'pelican.plugins.tag_cloud' from '/usr/local/lib/python3.8/dist-packages/pelican-4.5.0-py3.8.egg/pelican/plugins/tag_cloud/__init__.py'>}
(Pdb) n
> /usr/lib/python3.8/importlib/util.py(92)find_spec()
```

It would appear that the search is using a simplified `m.alias` instead of some `pelican.plugins....`  
Not sure what you're trying to debug. It's not fixed. Not even in master, that's why this issue is still open. I didn't have time to make a proper PR yet.
Yeah...  turns out there's three ways to do a plugins:

https://packaging.python.org/guides/creating-and-discovering-plugins

Mmmmmm.... Looks like namespace is the way to go. 

I defer to the experts.  Discontinuing debugging.
Thanks to @avaris working on the above-linked PR, this issue should now be addressed. Feel free to test latest master and post a comment here if any follow-up changes are deemed to be warranted.
Fix for this issue is included in the just-released [Pelican 4.5.1](https://github.com/getpelican/pelican/releases/tag/4.5.1). ✨



Patch:
diff --git a/pelican/plugins/_utils.py b/pelican/plugins/_utils.py
index 78c19e549..4e6ec3c5d 100644
--- a/pelican/plugins/_utils.py
+++ b/pelican/plugins/_utils.py
@@ -40,6 +40,11 @@ def list_plugins(ns_pkg=None):
 
 
 def load_legacy_plugin(plugin, plugin_paths):
+    if '.' in plugin:
+        # it is in a package, try to resolve package first
+        package, _, _ = plugin.rpartition('.')
+        load_legacy_plugin(package, plugin_paths)
+
     # Try to find plugin in PLUGIN_PATHS
     spec = importlib.machinery.PathFinder.find_spec(plugin, plugin_paths)
     if spec is None:
diff --git a/pelican/signals.py b/pelican/signals.py
new file mode 100644
index 000000000..9b84a92aa
--- /dev/null
+++ b/pelican/signals.py
@@ -0,0 +1,4 @@
+raise ImportError(
+    'Importing from `pelican.signals` is deprecated. '
+    'Use `from pelican import signals` or `import pelican.plugins.signals` instead.'
+)


Test patch:
diff --git a/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/__init__.py b/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subpackage/__init__.py b/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subpackage/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subpackage/subpackage.py b/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subpackage/subpackage.py
new file mode 100644
index 000000000..ddb0eeca2
--- /dev/null
+++ b/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subpackage/subpackage.py
@@ -0,0 +1,5 @@
+NAME = 'normal subpackage plugin'
+
+
+def register():
+    pass
diff --git a/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subplugin.py b/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subplugin.py
new file mode 100644
index 000000000..377c788b5
--- /dev/null
+++ b/pelican/tests/dummy_plugins/normal_plugin/normal_submodule_plugin/subplugin.py
@@ -0,0 +1,5 @@
+NAME = 'normal submodule plugin'
+
+
+def register():
+    pass
diff --git a/pelican/tests/test_plugins.py b/pelican/tests/test_plugins.py
index 730aa6d52..06940884c 100644
--- a/pelican/tests/test_plugins.py
+++ b/pelican/tests/test_plugins.py
@@ -116,6 +116,21 @@ def get_plugin_names(plugins):
                 {'normal plugin'},
                 get_plugin_names(plugins))
 
+            # normal submodule/subpackage plugins
+            SETTINGS = {
+                'PLUGINS': [
+                    'normal_submodule_plugin.subplugin',
+                    'normal_submodule_plugin.subpackage.subpackage',
+                ],
+                'PLUGIN_PATHS': [self._NORMAL_PLUGIN_FOLDER]
+            }
+            plugins = load_plugins(SETTINGS)
+            self.assertEqual(len(plugins), 2, plugins)
+            self.assertEqual(
+                {'normal submodule plugin',
+                 'normal subpackage plugin'},
+                get_plugin_names(plugins))
+
             # namespace plugin short
             SETTINGS = {
                 'PLUGINS': ['ns_plugin']