From: Dario Faccin Date: Tue, 23 May 2023 15:21:38 +0000 (+0200) Subject: Update from master X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=c3e7044ae9f1b6127570187c20a8db60f378bde3;p=osm%2FN2VC.git Update from master Squashed commit of the following: commit fb79786bd154505ea9c7578e6247dea565ea9c41 Author: Mark Beierl Date: Thu May 18 22:21:06 2023 -0400 Wrapping Retry for Py3.10 The retrying_async library is not Python 3.10 ready, so we are providing a 3.10 compatible callback for it to use instead of the default one Change-Id: I15e9b64c70d4d294c9ff0c6c7048cd257f6e1b61 Signed-off-by: Mark Beierl commit 714d8874783b507cd66a37d1dcd2f1d3ac980257 Author: Mark Beierl Date: Thu May 18 15:08:06 2023 -0400 Wrapping Retry for Py3.10 The retrying_async library is not Python 3.10 ready, so we are providing a 3.10 compatible callback for it to use instead of the default one Change-Id: I6e98f6d7ebc2fe134b0e3fe37d180e383044b30b Signed-off-by: Mark Beierl commit 2c3c146360fe5ce949a81e0e55e0e62e7f805d0b Author: Mark Beierl Date: Mon May 15 16:17:02 2023 -0400 Python3.10/Ubuntu 22.04 part 2 Removal of loop from all methods Change-Id: I05bfe90f82b8c8acba3172de89c7d8e0ee08402b Signed-off-by: Mark Beierl commit fcbd881700fec0522c81e8b32e3a982fb3ccbd80 Author: Gabriel Cuba Date: Thu May 11 02:04:17 2023 -0500 Remove charset-normalizer version constraint Change-Id: I46311f74e949270278f685c50576f5884ba96227 Signed-off-by: Gabriel Cuba Signed-off-by: Mark Beierl commit 474fd958ac88b5d2275d3acbc2fabe22e5e9344f Author: Guillermo Calvino Date: Fri Apr 28 11:51:43 2023 +0200 Ubuntu 22.04 and Python 3.10 preparation Change-Id: I57a4ee39c101bdab610a6964de58eaa2653d37a3 Signed-off-by: Guillermo Calvino Signed-off-by: Mark Beierl commit 806cd5cf9456e69a849f4231e163da4f72379c1b Author: garciadeblas Date: Fri Mar 24 14:03:17 2023 +0100 Fix black errors Change-Id: I58c380853485995e2c37163a958b06072cbe24ca Signed-off-by: garciadeblas (cherry picked from commit 9831d7e8205bce462a669a8cc2b3dc1a611c924c) Change-Id: I0c9356df8f245b68f72f4d64ba90c9811f2e5ec7 Signed-off-by: Dario Faccin --- diff --git a/Dockerfile b/Dockerfile index c597522..27ab273 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ # devops-stages/stage-build.sh # -FROM ubuntu:20.04 +FROM ubuntu:22.04 ARG APT_PROXY RUN if [ ! -z $APT_PROXY ] ; then \ @@ -37,7 +37,9 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update && \ python3 \ python3-all \ python3-dev \ - python3-setuptools + python3-setuptools \ + python3-pip \ + tox -RUN python3 -m easy_install pip==21.3.1 -RUN pip install tox==3.24.5 +ENV LC_ALL C.UTF-8 +ENV LANG C.UTF-8 diff --git a/n2vc/k8s_helm_conn.py b/n2vc/k8s_helm_conn.py index 84879c8..bbe4c48 100644 --- a/n2vc/k8s_helm_conn.py +++ b/n2vc/k8s_helm_conn.py @@ -78,12 +78,9 @@ class K8sHelmConnector(K8sHelmBaseConnector): else "--skip-repos", ) try: - asyncio.ensure_future( + asyncio.create_task( self._local_async_exec(command=command, raise_exception_on_error=False) ) - # loop = asyncio.get_event_loop() - # loop.run_until_complete(self._local_async_exec(command=command, - # raise_exception_on_error=False)) except Exception as e: self.warning( msg="helm init failed (it was already initialized): {}".format(e) diff --git a/n2vc/k8s_juju_conn.py b/n2vc/k8s_juju_conn.py index babe239..c197221 100644 --- a/n2vc/k8s_juju_conn.py +++ b/n2vc/k8s_juju_conn.py @@ -51,7 +51,6 @@ class K8sJujuConnector(K8sConnector): kubectl_command: str = "/usr/bin/kubectl", juju_command: str = "/usr/bin/juju", log: object = None, - loop: object = None, on_update_db=None, ): """ @@ -60,19 +59,17 @@ class K8sJujuConnector(K8sConnector): :param kubectl_command: path to kubectl executable :param helm_command: path to helm executable :param log: logger - :param: loop: Asyncio loop """ # parent class K8sConnector.__init__(self, db, log=log, on_update_db=on_update_db) self.fs = fs - self.loop = loop or asyncio.get_event_loop() self.log.debug("Initializing K8S Juju connector") db_uri = EnvironConfig(prefixes=["OSMLCM_", "OSMMON_"]).get("database_uri") self._store = MotorStore(db_uri) - self.loading_libjuju = asyncio.Lock(loop=self.loop) + self.loading_libjuju = asyncio.Lock() self.uninstall_locks = {} self.log.debug("K8S Juju connector initialized") @@ -509,7 +506,7 @@ class K8sJujuConnector(K8sConnector): will_not_delete = False if model_name not in self.uninstall_locks: - self.uninstall_locks[model_name] = asyncio.Lock(loop=self.loop) + self.uninstall_locks[model_name] = asyncio.Lock() delete_lock = self.uninstall_locks[model_name] while delete_lock.locked(): @@ -915,11 +912,11 @@ class K8sJujuConnector(K8sConnector): if not self.libjuju: async with self.loading_libjuju: vca_connection = await get_connection(self._store) - self.libjuju = Libjuju(vca_connection, loop=self.loop, log=self.log) + self.libjuju = Libjuju(vca_connection, log=self.log) return self.libjuju else: vca_connection = await get_connection(self._store, vca_id) - return Libjuju(vca_connection, loop=self.loop, log=self.log, n2vc=self) + return Libjuju(vca_connection, log=self.log, n2vc=self) def _get_kubectl(self, credentials: str) -> Kubectl: """ diff --git a/n2vc/kubectl.py b/n2vc/kubectl.py index d6ca09a..3fe6b53 100644 --- a/n2vc/kubectl.py +++ b/n2vc/kubectl.py @@ -35,6 +35,7 @@ from kubernetes.client.models import ( V1SecretReference, ) from kubernetes.client.rest import ApiException +from n2vc.libjuju import retry_callback from retrying_async import retry @@ -319,6 +320,7 @@ class Kubectl: attempts=10, delay=1, fallback=Exception("Failed getting the secret from service account"), + callback=retry_callback, ) async def get_secret_data( self, name: str, namespace: str = "kube-system" diff --git a/n2vc/libjuju.py b/n2vc/libjuju.py index 55ca859..f36ff39 100644 --- a/n2vc/libjuju.py +++ b/n2vc/libjuju.py @@ -61,11 +61,18 @@ from retrying_async import retry RBAC_LABEL_KEY_NAME = "rbac-id" +@asyncio.coroutine +def retry_callback(attempt, exc, args, kwargs, delay=0.5, *, loop): + # Specifically overridden from upstream implementation so it can + # continue to work with Python 3.10 + yield from asyncio.sleep(attempt * delay) + return retry + + class Libjuju: def __init__( self, vca_connection: Connection, - loop: asyncio.AbstractEventLoop = None, log: logging.Logger = None, n2vc: N2VCConnector = None, ): @@ -73,7 +80,6 @@ class Libjuju: Constructor :param: vca_connection: n2vc.vca.connection object - :param: loop: Asyncio loop :param: log: Logger :param: n2vc: N2VC object """ @@ -82,15 +88,13 @@ class Libjuju: self.n2vc = n2vc self.vca_connection = vca_connection - self.loop = loop or asyncio.get_event_loop() - self.loop.set_exception_handler(self.handle_exception) - self.creating_model = asyncio.Lock(loop=self.loop) + self.creating_model = asyncio.Lock() if self.vca_connection.is_default: self.health_check_task = self._create_health_check_task() def _create_health_check_task(self): - return self.loop.create_task(self.health_check()) + return asyncio.get_event_loop().create_task(self.health_check()) async def get_controller(self, timeout: float = 60.0) -> Controller: """ @@ -155,7 +159,7 @@ class Libjuju: if controller: await controller.disconnect() - @retry(attempts=3, delay=5, timeout=None) + @retry(attempts=3, delay=5, timeout=None, callback=retry_callback) async def add_model(self, model_name: str, cloud: VcaCloud): """ Create model @@ -270,7 +274,7 @@ class Libjuju: await self.disconnect_controller(controller) return application_configs - @retry(attempts=3, delay=5) + @retry(attempts=3, delay=5, callback=retry_callback) async def get_model(self, controller: Controller, model_name: str) -> Model: """ Get model from controller @@ -1640,10 +1644,6 @@ class Libjuju: await self.disconnect_model(model) await self.disconnect_controller(controller) - def handle_exception(self, loop, context): - # All unhandled exceptions by libjuju are handled here. - pass - async def health_check(self, interval: float = 300.0): """ Health check to make sure controller and controller_model connections are OK @@ -1848,7 +1848,9 @@ class Libjuju: finally: await self.disconnect_controller(controller) - @retry(attempts=20, delay=5, fallback=JujuLeaderUnitNotFound()) + @retry( + attempts=20, delay=5, fallback=JujuLeaderUnitNotFound(), callback=retry_callback + ) async def _get_leader_unit(self, application: Application) -> Unit: unit = None for u in application.units: diff --git a/n2vc/loggable.py b/n2vc/loggable.py index cbaa116..d129b4b 100644 --- a/n2vc/loggable.py +++ b/n2vc/loggable.py @@ -131,7 +131,7 @@ class Loggable: coroutine_id = "" if include_coroutine: try: - if asyncio.Task.current_task() is not None: + if asyncio.current_task() is not None: def print_cor_name(c): import inspect @@ -143,7 +143,7 @@ class Loggable: except Exception: pass - coro = asyncio.Task.current_task()._coro + coro = asyncio.current_task()._coro coroutine_id = "coro-{} {}()".format( hex(id(coro))[2:], print_cor_name(coro) ) diff --git a/n2vc/n2vc_conn.py b/n2vc/n2vc_conn.py index 5752da7..4fa7e36 100644 --- a/n2vc/n2vc_conn.py +++ b/n2vc/n2vc_conn.py @@ -54,7 +54,6 @@ class N2VCConnector(abc.ABC, Loggable): db: object, fs: object, log: object, - loop: object, on_update_db=None, **kwargs, ): @@ -64,7 +63,6 @@ class N2VCConnector(abc.ABC, Loggable): :param object fs: FileSystem object managing the package artifacts (repo common FsBase) :param object log: the logging object to log to - :param object loop: the loop to use for asyncio (default current thread loop) :param on_update_db: callback called when n2vc connector updates database. Received arguments: table: e.g. "nsrs" @@ -85,7 +83,6 @@ class N2VCConnector(abc.ABC, Loggable): # store arguments into self self.db = db self.fs = fs - self.loop = loop or asyncio.get_event_loop() self.on_update_db = on_update_db # generate private/public key-pair diff --git a/n2vc/n2vc_juju_conn.py b/n2vc/n2vc_juju_conn.py index cbca396..9d0cdfa 100644 --- a/n2vc/n2vc_juju_conn.py +++ b/n2vc/n2vc_juju_conn.py @@ -37,7 +37,7 @@ from n2vc.exceptions import ( ) from n2vc.n2vc_conn import N2VCConnector from n2vc.n2vc_conn import obj_to_dict, obj_to_yaml -from n2vc.libjuju import Libjuju +from n2vc.libjuju import Libjuju, retry_callback from n2vc.store import MotorStore from n2vc.utils import get_ee_id_components, generate_random_alfanum_string from n2vc.vca.connection import get_connection @@ -61,7 +61,6 @@ class N2VCJujuConnector(N2VCConnector): db: object, fs: object, log: object = None, - loop: object = None, on_update_db=None, ): """ @@ -70,14 +69,11 @@ class N2VCJujuConnector(N2VCConnector): :param: db: Database object from osm_common :param: fs: Filesystem object from osm_common :param: log: Logger - :param: loop: Asyncio loop :param: on_update_db: Callback function to be called for updating the database. """ # parent class constructor - N2VCConnector.__init__( - self, db=db, fs=fs, log=log, loop=loop, on_update_db=on_update_db - ) + N2VCConnector.__init__(self, db=db, fs=fs, log=log, on_update_db=on_update_db) # silence websocket traffic log logging.getLogger("websockets.protocol").setLevel(logging.INFO) @@ -88,7 +84,7 @@ class N2VCJujuConnector(N2VCConnector): db_uri = EnvironConfig(prefixes=["OSMLCM_", "OSMMON_"]).get("database_uri") self._store = MotorStore(db_uri) - self.loading_libjuju = asyncio.Lock(loop=self.loop) + self.loading_libjuju = asyncio.Lock() self.delete_namespace_locks = {} self.log.info("N2VC juju connector initialized") @@ -359,7 +355,13 @@ class N2VCJujuConnector(N2VCConnector): # In case of native_charm is being deployed, if JujuApplicationExists error happens # it will try to add_unit - @retry(attempts=3, delay=5, retry_exceptions=(N2VCApplicationExists,), timeout=None) + @retry( + attempts=3, + delay=5, + retry_exceptions=(N2VCApplicationExists,), + timeout=None, + callback=retry_callback, + ) async def install_configuration_sw( self, ee_id: str, @@ -772,7 +774,7 @@ class N2VCJujuConnector(N2VCConnector): self.log.info("Deleting namespace={}".format(namespace)) will_not_delete = False if namespace not in self.delete_namespace_locks: - self.delete_namespace_locks[namespace] = asyncio.Lock(loop=self.loop) + self.delete_namespace_locks[namespace] = asyncio.Lock() delete_lock = self.delete_namespace_locks[namespace] while delete_lock.locked(): @@ -1148,11 +1150,11 @@ class N2VCJujuConnector(N2VCConnector): if not self.libjuju: async with self.loading_libjuju: vca_connection = await get_connection(self._store) - self.libjuju = Libjuju(vca_connection, loop=self.loop, log=self.log) + self.libjuju = Libjuju(vca_connection, log=self.log) return self.libjuju else: vca_connection = await get_connection(self._store, vca_id) - return Libjuju(vca_connection, loop=self.loop, log=self.log, n2vc=self) + return Libjuju(vca_connection, log=self.log, n2vc=self) def _write_ee_id_db(self, db_dict: dict, ee_id: str): # write ee_id to database: _admin.deployed.VCA.x @@ -1536,6 +1538,6 @@ class N2VCJujuConnector(N2VCConnector): :param: vca_id: VCA ID """ vca_connection = await get_connection(self._store, vca_id=vca_id) - libjuju = Libjuju(vca_connection, loop=self.loop, log=self.log, n2vc=self) + libjuju = Libjuju(vca_connection, log=self.log, n2vc=self) controller = await libjuju.get_controller() await libjuju.disconnect_controller(controller) diff --git a/n2vc/store.py b/n2vc/store.py index e9586d7..c8e5910 100644 --- a/n2vc/store.py +++ b/n2vc/store.py @@ -13,7 +13,6 @@ # limitations under the License. import abc -import asyncio import typing from motor.motor_asyncio import AsyncIOMotorClient @@ -183,22 +182,19 @@ class DbMongoStore(Store): class MotorStore(Store): - def __init__(self, uri: str, loop=None): + def __init__(self, uri: str): """ Constructor :param: uri: Connection string to connect to the database. - :param: loop: Asyncio Loop """ self._client = AsyncIOMotorClient(uri) - self.loop = loop or asyncio.get_event_loop() self._secret_key = None self._config = EnvironConfig(prefixes=["OSMLCM_", "OSMMON_"]) self.encryption = Encryption( uri=uri, config=self._config, encoding_type="utf-8", - loop=self.loop, logger_name="db", ) diff --git a/n2vc/tests/unit/test_k8s_juju_conn.py b/n2vc/tests/unit/test_k8s_juju_conn.py index 1cc0809..1de1288 100644 --- a/n2vc/tests/unit/test_k8s_juju_conn.py +++ b/n2vc/tests/unit/test_k8s_juju_conn.py @@ -72,7 +72,6 @@ class K8sJujuConnTestCase(asynctest.TestCase): fs=fslocal.FsLocal(), db=self.db, log=None, - loop=self.loop, on_update_db=None, ) self.k8s_juju_conn._store.get_vca_id.return_value = None diff --git a/n2vc/tests/unit/test_libjuju.py b/n2vc/tests/unit/test_libjuju.py index 9f21bc6..38d8d0e 100644 --- a/n2vc/tests/unit/test_libjuju.py +++ b/n2vc/tests/unit/test_libjuju.py @@ -78,7 +78,7 @@ class LibjujuTestCase(asynctest.TestCase): } ) logging.disable(logging.CRITICAL) - self.libjuju = Libjuju(vca_connection, self.loop) + self.libjuju = Libjuju(vca_connection) self.loop.run_until_complete(self.libjuju.disconnect()) diff --git a/n2vc/tests/unit/test_n2vc_juju_conn.py b/n2vc/tests/unit/test_n2vc_juju_conn.py index deb98ce..456ec1e 100644 --- a/n2vc/tests/unit/test_n2vc_juju_conn.py +++ b/n2vc/tests/unit/test_n2vc_juju_conn.py @@ -73,7 +73,6 @@ class N2VCJujuConnTestCase(asynctest.TestCase): db=self.db, fs=fslocal.FsLocal(), log=None, - loop=self.loop, on_update_db=None, ) N2VCJujuConnector.get_public_key.assert_not_called() diff --git a/requirements-dev.txt b/requirements-dev.txt index 1ec80de..e1118f6 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -20,19 +20,23 @@ async-timeout==4.0.2 # via # -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas # aiokafka -charset-normalizer==3.0.1 +charset-normalizer==3.1.0 # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas dataclasses==0.6 # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas +dnspython==2.3.0 + # via + # -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas + # pymongo kafka-python==2.0.2 # via # -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas # aiokafka -motor==1.3.1 +motor==3.1.2 # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas osm-common @ git+https://osm.etsi.org/gerrit/osm/common.git@paas # via -r requirements-dev.in -packaging==23.0 +packaging==23.1 # via # -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas # aiokafka @@ -42,7 +46,7 @@ protobuf==3.20.3 # temporalio pycryptodome==3.17 # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas -pymongo==3.13.0 +pymongo==4.3.3 # via # -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas # motor diff --git a/requirements-test.in b/requirements-test.in index 532c603..a0d68c4 100644 --- a/requirements-test.in +++ b/requirements-test.in @@ -13,7 +13,7 @@ # limitations under the License. asynctest -charset-normalizer<4 # Required by aiohttp in LCM +charset-normalizer coverage flake8<5.0.0 mock diff --git a/requirements-test.txt b/requirements-test.txt index 24c74eb..0704348 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -16,13 +16,13 @@ ####################################################################################### asynctest==0.13.0 # via -r requirements-test.in -certifi==2022.12.7 +certifi==2023.5.7 # via requests -charset-normalizer==3.0.1 +charset-normalizer==3.1.0 # via # -r requirements-test.in # requests -coverage==7.2.1 +coverage==7.2.5 # via -r requirements-test.in flake8==4.0.1 # via -r requirements-test.in @@ -30,19 +30,19 @@ idna==3.4 # via requests mccabe==0.6.1 # via flake8 -mock==5.0.1 +mock==5.0.2 # via -r requirements-test.in -nose2==0.12.0 +nose2==0.13.0 # via -r requirements-test.in pycodestyle==2.8.0 # via flake8 pyflakes==2.4.0 # via flake8 -requests==2.28.2 +requests==2.30.0 # via requests-mock requests-mock==1.10.0 # via -r requirements-test.in six==1.16.0 # via requests-mock -urllib3==1.26.14 +urllib3==2.0.2 # via requests diff --git a/requirements.in b/requirements.in index 843b7a6..0195351 100644 --- a/requirements.in +++ b/requirements.in @@ -11,11 +11,11 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -charset-normalizer<4 # Required by aiohttp in LCM +charset-normalizer +google-auth<2.18.0 juju==3.0.0 kubernetes -motor==1.3.1 +motor pyasn1 pyyaml==5.4.1 retrying-async diff --git a/requirements.txt b/requirements.txt index d249889..53808d1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,7 +20,7 @@ bcrypt==4.0.1 # via paramiko cachetools==5.3.0 # via google-auth -certifi==2022.12.7 +certifi==2023.5.7 # via # kubernetes # requests @@ -28,14 +28,18 @@ cffi==1.15.1 # via # cryptography # pynacl -charset-normalizer==3.0.1 +charset-normalizer==3.1.0 # via # -r requirements.in # requests -cryptography==39.0.1 +cryptography==40.0.2 # via paramiko -google-auth==2.16.1 - # via kubernetes +dnspython==2.3.0 + # via pymongo +google-auth==2.17.3 + # via + # -r requirements.in + # kubernetes idna==3.4 # via requests juju==3.0.0 @@ -50,7 +54,7 @@ macaroonbakery==1.3.1 # via # juju # theblues -motor==1.3.1 +motor==3.1.2 # via -r requirements.in mypy-extensions==1.0.0 # via typing-inspect @@ -60,19 +64,19 @@ paramiko==2.12.0 # via juju protobuf==3.20.3 # via macaroonbakery -pyasn1==0.4.8 +pyasn1==0.5.0 # via # -r requirements.in # juju # pyasn1-modules # rsa -pyasn1-modules==0.2.8 +pyasn1-modules==0.3.0 # via google-auth pycparser==2.21 # via cffi pymacaroons==0.13.0 # via macaroonbakery -pymongo==3.13.0 +pymongo==4.3.3 # via motor pynacl==1.5.0 # via @@ -85,7 +89,7 @@ pyrfc3339==1.1 # macaroonbakery python-dateutil==2.8.2 # via kubernetes -pytz==2022.7.1 +pytz==2023.3 # via pyrfc3339 pyyaml==5.4.1 # via @@ -93,7 +97,7 @@ pyyaml==5.4.1 # juju # jujubundlelib # kubernetes -requests==2.28.2 +requests==2.30.0 # via # kubernetes # macaroonbakery @@ -121,13 +125,13 @@ typing-extensions==4.5.0 # via typing-inspect typing-inspect==0.8.0 # via juju -urllib3==1.26.14 +urllib3==2.0.2 # via # kubernetes # requests websocket-client==1.5.1 # via kubernetes -websockets==7.0 +websockets==11.0.3 # via juju # The following packages are considered to be unsafe in a requirements file: diff --git a/tox.ini b/tox.ini index 5ae56bd..d4e8594 100644 --- a/tox.ini +++ b/tox.ini @@ -23,7 +23,7 @@ toxworkdir = /tmp/.tox [testenv] usedevelop = True -basepython = python3.8 +basepython = python3.10 setenv = VIRTUAL_ENV={envdir} PYTHONDONTWRITEBYTECODE = 1 deps = -r{toxinidir}/requirements.txt @@ -50,7 +50,7 @@ commands = coverage report --omit='*tests*' coverage html -d ./cover --omit='*tests*' coverage xml -o coverage.xml --omit=*tests* -whitelist_externals = sh +allowlist_externals = sh ####################################################################################### @@ -85,7 +85,7 @@ commands = [testenv:pip-compile] deps = pip-tools==6.6.2 skip_install = true -whitelist_externals = bash +allowlist_externals = bash [ commands = - bash -c "for file in requirements*.in ; do \ @@ -109,7 +109,7 @@ commands = python3 setup.py --command-packages=stdeb.command sdist_dsc sh -c 'cd deb_dist/n2vc*/ && dpkg-buildpackage -rfakeroot -uc -us' sh -c 'rm n2vc/requirements.txt' -whitelist_externals = sh +allowlist_externals = sh ####################################################################################### [flake8]