diff --git a/CHANGES.md b/CHANGES.md index cdc413c641..ce48c8120c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,13 @@ ones in. --> ## 2.1.0 (Released 2023-07-21) +### Breaking Changes + +[2736](https://github.com/metomi/rose/pull/2736) +Rose now ignores `PYTHONPATH` to make it more robust to task environments +which set this value. If you want to add to the Rose environment itself, +e.g. to write a rose-ana test, use `ROSE_PYTHONPATH`. + ### Fixes [#2699](https://github.com/metomi/rose/pull/2699) - diff --git a/metomi/rose/rose.py b/metomi/rose/rose.py index be4606cffb..b167c40f8e 100644 --- a/metomi/rose/rose.py +++ b/metomi/rose/rose.py @@ -14,11 +14,39 @@ # # You should have received a copy of the GNU General Public License # along with Rose. If not, see . + +import os +import sys + + +def pythonpath_manip(): + """Stop PYTHONPATH contaminating the Cylc Environment + + * Remove PYTHONPATH items from sys.path to prevent PYTHONPATH + contaminating the Cylc Environment. + * Add items from ROSE_PYTHONPATH to sys.path. + + See Also: + https://github.com/cylc/cylc-flow/issues/5124 + """ + if 'ROSE_PYTHONPATH' in os.environ: + for item in os.environ['ROSE_PYTHONPATH'].split(os.pathsep): + print(f'extracted {item} from ROSE_PYTHONPATH') + abspath = os.path.abspath(item) + sys.path.insert(0, abspath) + if 'PYTHONPATH' in os.environ: + for item in os.environ['PYTHONPATH'].split(os.pathsep): + abspath = os.path.abspath(item) + if abspath in sys.path: + sys.path.remove(abspath) + + +pythonpath_manip() + + import argparse from inspect import signature -import os from pathlib import Path -import sys from pkg_resources import ( DistributionNotFound, diff --git a/metomi/rose/tests/test_rose.py b/metomi/rose/tests/test_rose.py new file mode 100644 index 0000000000..81745fd568 --- /dev/null +++ b/metomi/rose/tests/test_rose.py @@ -0,0 +1,44 @@ +# Copyright (C) British Crown (Met Office) & Contributors. +# +# This file is part of Rose, a framework for meteorological suites. +# +# Rose is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Rose is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Rose. If not, see . +"""Test metomi/rose/rose.py +""" + +import os +import sys + +from metomi.rose.rose import pythonpath_manip + + +def test_pythonpath_manip(monkeypatch): + """pythonpath_manip removes items in PYTHONPATH from sys.path + and adds items from ROSE_PYTHONPATH + """ + # If PYTHONPATH is set... + monkeypatch.setenv('PYTHONPATH', '/remove-from-sys.path') + monkeypatch.setattr('sys.path', ['/leave-alone', '/remove-from-sys.path']) + pythonpath_manip() + # ... we don't change PYTHONPATH + assert os.environ['PYTHONPATH'] == '/remove-from-sys.path' + # ... but we do remove PYTHONPATH items from sys.path, and don't remove + # items there not in PYTHONPATH + assert sys.path == ['/leave-alone'] + + # If CYLC_PYTHONPATH is set we retrieve its contents and + # add them to the sys.path: + monkeypatch.setenv('ROSE_PYTHONPATH', '/add-to-sys.path') + pythonpath_manip() + assert sys.path == ['/add-to-sys.path', '/leave-alone'] diff --git a/t/rose-ana/00-run-basic/flow.cylc b/t/rose-ana/00-run-basic/flow.cylc index 0b35076ef9..b0d4be2692 100644 --- a/t/rose-ana/00-run-basic/flow.cylc +++ b/t/rose-ana/00-run-basic/flow.cylc @@ -4,7 +4,7 @@ UTC mode=True [[events]] abort on stalled = True mail events = - timeout=PT30S + timeout=PT5S [scheduling] [[dependencies]] diff --git a/tox.ini b/tox.ini index 8dad1c4452..83a93c182c 100644 --- a/tox.ini +++ b/tox.ini @@ -13,3 +13,5 @@ ignore= E731, # no longer best practice: W503 + ; module level import not at top of file + E402,