From a33e8de922627fd7c318e711e6ff9d909751c535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 31 Jan 2022 00:29:01 +0100 Subject: [PATCH] doc: Defer parsing version_txt to fix an obscure bug Defer parsing the version read from version.txt until it's about to be used, in order to fix an obscure bug involving indirect pkg_resources. When pkg_resources are imported, they override packaging with their own pkg_resources.extern.packaging. Depending on the system, this could either wrap the vendored pkg_resources._vendor.packaging or system packaging. For some reason, in the latter case the Version objects created prior to the wrapping are incompatible with the objects created afterwards. This causes the doc build to fail with: ``` Exception occurred: File "/tmp/polybar/build/doc/conf.py", line 249, in run if directive_version > version_txt: TypeError: '>' not supported between instances of 'Version' and 'Version' ``` This happens because apparently pkg_resources are imported indirectly somewhere between conf.py processing and running VersionDirective. Deferring version parsing until the latter guarantees that both objects are constructed at the same point in program flow and therefore use the same packaging package. --- doc/conf.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 22c1008e..b6672c71 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -26,7 +26,9 @@ def get_version(root_path): with open(path, "r") as f: for line in f.readlines(): if not line.startswith("#"): - return packaging.version.parse(line) + # NB: we can't parse it yet since sphinx could import + # pkg_resources later on and it could patch packaging.version + return line raise RuntimeError("No version found in {}".format(path)) @@ -245,8 +247,9 @@ if packaging.version.parse(sphinx.__version__) >= packaging.version.parse("1.8.5 """ def run(self) -> List[Node]: directive_version = packaging.version.parse(self.arguments[0]) + parsed_version_txt = packaging.version.parse(version_txt) - if directive_version > version_txt: + if directive_version > parsed_version_txt: self.arguments[0] += " (unreleased)" return super().run()