← 输入框|github.com|刷新
Skip to content

Py313 replace pkgutil get loader for 3.14 - #130

Merged
jwp merged 3 commits into
python-postgres:masterfrom
pattems:py313-replace-pkgutil-get-loader-for-3-14
Oct 31, 2026
Merged

jwp merged 3 commits into
python-postgres:masterfrom
pattems:py313-replace-pkgutil-get-loader-for-3-14

Conversation

@pattems

@pattems pattems commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

Three commits.

1. Replace pkgutil.get_loader for 3.14

postgresql/python/command.py does from pkgutil import get_loader as module_loader. pkgutil.get_loader was deprecated in Python 3.12 and removed in 3.14, so on 3.14

>>> import postgresql.python.command
ImportError: cannot import name 'get_loader' from 'pkgutil'

which also takes down postgresql.bin.pg_python (the pg_python script). On 3.12/3.13 it emits a DeprecationWarning on every -m/-C module: use.

The change defines module_loader(name) on top of importlib.util.find_spec() (available since 3.4, so fine for requires-python >= 3.7), returning the spec's loader or None, which is what Execution expects.

2. Always set version; fixes pg_dotconf import

postgresql/__init__.py does

from .project import version_info, version, \
    author as __author__, date as __date__
__version__ = version

inside try/except ImportError. project.py no longer defines author or date, so the import fails after binding version and before __version__ is set; the error is swallowed. As a result, on any Python version:

>>> import postgresql.bin.pg_dotconf
ImportError: cannot import name '__version__' from 'postgresql'
>>> from postgresql import *
AttributeError: module 'postgresql' has no attribute '__author__'

The change imports only version_info and version, sets __version__ after the try, and drops __author__/__date__ from __all__.

3. Fix pg_dotconf -f/--file

With the import fixed, pg_dotconf -f settings.conf postgresql.conf hits NameError: name 'comment' is not defined: the loop uses bare comment and unquote instead of configfile.comment/configfile.unquote. It also tested line[pl[0].start] (the first character of the key) for the comment marker, so a commented-out setting in the settings file would have been applied. It now checks line[:pl[0].start], as configfile.alter_config() does.

Testing

Driving postgresql.python.command.command() directly with ['pg_python', '-C', 'module:pgcmd_ctx', '-m', 'pgcmd_main', 'a1', 'a2'] (two small throwaway modules on sys.path), plus -m no_such_module_xyz, with DeprecationWarning turned into errors:

  • Before (f71e4b2): 3.14.3 -> ImportError on import; 3.12.13 and 3.13.14 -> DeprecationWarning: 'pkgutil.get_loader' is deprecated and slated for removal in Python 3.14.
  • After, CPython 3.12.13, 3.13.14 and 3.14.3: main module runs as __main__ with argv ['a1', 'a2'] and the context module's globals, returns 0; the missing module raises ImportError: Python module 'no_such_module_xyz' does not exist or cannot be read as before.
  • python -m unittest postgresql.test.test_python: OK on all three.

Commits 2 and 3: import postgresql, from postgresql import *, then pg_dotconf.command(['pg_dotconf', '--stdout', '-f', 'settings.conf', 'postgresql.conf']) with a settings file holding port = 5433 and #work_mem = 64MB, and a postgresql.conf holding #port = 5432, max_connections = 100, #work_mem = 4MB:

  • Before (f71e4b2 + commit 1): __version__ missing, star import AttributeError, import postgresql.bin.pg_dotconf ImportError (CPython 3.12.13 and 3.13.14).
  • After commit 2 only: NameError comment in command().
  • After commit 3, CPython 3.12.13, 3.13.14 and 3.14.3: __version__ == '1.3.1', star import OK, output port = '5433', max_connections = 100, #work_mem = 4MB (the commented work_mem line in the settings file is skipped).
  • python -m unittest postgresql.test.test_configfile: OK on all three.

pkgutil.get_loader was deprecated in Python 3.12 and removed in 3.14,
so importing postgresql.python.command (and with it pg_python) fails
with ImportError on 3.14. Resolve the loader with
importlib.util.find_spec instead, which is available on every
supported version.
project.py no longer defines author or date, so the combined import
from .project raised ImportError after binding version and before
__version__ was assigned. The error was swallowed, leaving the package
without __version__ and breaking "from postgresql import *" (__all__
lists __author__ and __date__) and postgresql.bin.pg_dotconf, which
does "from .. import __version__".

Import only version_info and version, assign __version__ outside the
try, and drop __author__ and __date__ from __all__.
The settings-file loop referenced the undefined names comment and
unquote (NameError) instead of configfile.comment and
configfile.unquote, and it tested the first character of the key
rather than the text before it, so commented-out settings in the file
would have been applied. Check line[:start], as alter_config() does.
@jwp
jwp merged commit ee2e380 into python-postgres:master Oct 31, 2026
@jwp

jwp commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants