diff --git a/.github/workflows/pre_release.yaml b/.github/workflows/pre_release.yaml index 9cb576f7..41cc3948 100644 --- a/.github/workflows/pre_release.yaml +++ b/.github/workflows/pre_release.yaml @@ -32,8 +32,8 @@ jobs: python -m pip install --upgrade setuptools wheel python -m pip install nox - name: run nox - # TERM is needed needed to make the terminal a tty (i think? without this system ssh is super broken) + # TERM is needed to make the terminal a tty (i think? without this system ssh is super broken) # libssh2/ssh2-python were getting libssh2 linked incorrectly/weirdly and libraries were trying to be loaded # from the temp dir that pip used for installs. setting the DYLD_LIBRARY_PATH envvar seems to solve this -- note # that if brew macos packages get updated on runners this may break again :) - run: TERM=xterm DYLD_LIBRARY_PATH=/opt/homebrew/Cellar/libssh2/1.11.0_1/lib python -m nox -p $FRIENDLY_PYTHON_VERSION -k "not darglint" \ No newline at end of file + run: TERM=xterm DYLD_LIBRARY_PATH=/opt/homebrew/Cellar/libssh2/1.11.0_1/lib PRE_RELEASE=1 python -m nox -p $FRIENDLY_PYTHON_VERSION -k "not darglint" \ No newline at end of file diff --git a/noxfile.py b/noxfile.py index 6035d66a..676f2e08 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,5 +1,6 @@ """scrapli.noxfile""" +import os import re import sys from pathlib import Path @@ -11,6 +12,8 @@ nox.options.stop_on_first_error = False nox.options.default_venv_backend = "venv" +PRE = bool(os.environ.get("PRE_RELEASE")) + def parse_requirements(dev: bool = True) -> Dict[str, str]: """ @@ -64,6 +67,18 @@ def parse_requirements(dev: bool = True) -> Dict[str, str]: SKIP_LIST: List[str] = [] +def _get_install_test_args() -> List[str]: + args = [".[dev]"] + + if sys.platform == "darwin": + args = [".[dev-darwin]"] + + if PRE: + args.append("--pre") + + return args + + @nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]) def unit_tests(session): """ @@ -85,7 +100,7 @@ def unit_tests(session): session.run("chmod", "0600", "tests/test_data/files/scrapli_key", external=True) session.run("chmod", "0600", "tests/test_data/files/scrapli_key_encrypted", external=True) session.install("-U", "setuptools", "wheel", "pip") - session.install(".[dev]") + session.install(*_get_install_test_args()) session.run( "python", "-m", @@ -119,7 +134,7 @@ def integration_tests(session): return session.install("-U", "setuptools", "wheel", "pip") - session.install(".[dev]") + session.install(*_get_install_test_args()) # setting scrapli boxen -> 1 so that the saved scrapli replay sessions are "correctly" # pointing to the boxen dev env (i.e. port 21022 instead of 22 for iosxe, etc.) session.run( @@ -192,7 +207,7 @@ def pylama(session): N/A """ - session.install(".[dev]") + session.install(*_get_install_test_args()) session.run("python", "-m", "pylama", ".") diff --git a/pyproject.toml b/pyproject.toml index a674918c..88c9070a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,16 @@ Homepage = "https://github.com/carlmontanari/scrapli" [tool.setuptools.dynamic] version = { attr = "scrapli.__version__" } dependencies = { file = "requirements.txt" } +# dev-darwin is same as dev but excludes ssh2-python +optional-dependencies.dev-darwin = { file = [ + "requirements-dev.txt", + "requirements-textfsm.txt", + "requirements-genie.txt", + "requirements-ttp.txt", + "requirements-paramiko.txt", + "requirements-asyncssh.txt", + "requirements-community.txt", +] } optional-dependencies.dev = { file = [ "requirements-dev.txt", "requirements-textfsm.txt", diff --git a/scrapli/transport/plugins/ssh2/transport.py b/scrapli/transport/plugins/ssh2/transport.py index e8b76f0e..2a17a2e9 100644 --- a/scrapli/transport/plugins/ssh2/transport.py +++ b/scrapli/transport/plugins/ssh2/transport.py @@ -5,9 +5,11 @@ from dataclasses import dataclass from typing import Optional -from ssh2.channel import Channel -from ssh2.exceptions import AuthenticationError, SSH2Error -from ssh2.session import Session +# ignoring unable to import complaints for linters as ssh2 support is a bit lackluster due to +# upstream library staleness +from ssh2.channel import Channel # pylint: disable=E0401,E0611 +from ssh2.exceptions import AuthenticationError, SSH2Error # pylint: disable=E0401,E0611 +from ssh2.session import Session # pylint: disable=E0401,E0611 from scrapli.exceptions import ( ScrapliAuthenticationFailed, diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 0e890b5d..c8081bef 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -76,7 +76,7 @@ def device_type(request): yield request.param -@pytest.fixture(scope="function", params=["system", "ssh2", "paramiko"]) +@pytest.fixture(scope="function", params=["system", "paramiko"]) def transport(request): yield request.param diff --git a/tests/unit/transport/plugins/ssh2/test_ssh2_transport.py b/tests/unit/transport/plugins/ssh2/test_ssh2_transport.py index bb31caa1..620ce570 100644 --- a/tests/unit/transport/plugins/ssh2/test_ssh2_transport.py +++ b/tests/unit/transport/plugins/ssh2/test_ssh2_transport.py @@ -5,18 +5,24 @@ from scrapli.exceptions import ScrapliConnectionNotOpened -@pytest.mark.skipif(sys.version_info >= (3, 12), reason="skipping ssh2 on 3.12") +@pytest.mark.skipif( + (sys.version_info >= (3, 12) or sys.platform != "linux"), reason="skipping ssh2 on 3.12" +) def test_open_channel_no_session(ssh2_transport): with pytest.raises(ScrapliConnectionNotOpened): assert ssh2_transport._open_channel() -@pytest.mark.skipif(sys.version_info >= (3, 12), reason="skipping ssh2 on 3.12") +@pytest.mark.skipif( + (sys.version_info >= (3, 12) or sys.platform != "linux"), reason="skipping ssh2 on 3.12" +) def test_isalive_no_session(ssh2_transport): assert ssh2_transport.isalive() is False -@pytest.mark.skipif(sys.version_info >= (3, 12), reason="skipping ssh2 on 3.12") +@pytest.mark.skipif( + (sys.version_info >= (3, 12) or sys.platform != "linux"), reason="skipping ssh2 on 3.12" +) def test_write_exception(ssh2_transport): with pytest.raises(ScrapliConnectionNotOpened): ssh2_transport.write("blah")