diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 855d954..b9c179a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,16 +3,14 @@ updates: - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "weekly" - day: "sunday" + interval: "monthly" timezone: "PST8PDT" time: "03:00" target-branch: "develop" - package-ecosystem: "pip" directory: "/" schedule: - interval: "weekly" - day: "sunday" + interval: "monthly" timezone: "PST8PDT" time: "03:00" target-branch: "develop" diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml index cb4e1d2..97d8558 100644 --- a/.github/workflows/commit.yaml +++ b/.github/workflows/commit.yaml @@ -9,7 +9,7 @@ jobs: max-parallel: 1 matrix: os: [ubuntu-latest] - version: [3.9] + version: ["3.10"] steps: - uses: actions/checkout@v2 - name: set up python ${{ matrix.version }} @@ -27,10 +27,10 @@ jobs: build_posix: runs-on: ${{ matrix.os }} strategy: - max-parallel: 12 + max-parallel: 8 matrix: os: [ubuntu-latest, macos-latest] - version: [3.6, 3.7, 3.8, 3.9, 3.10.0-beta.4] + version: ["3.7", "3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v2 - name: set up python ${{ matrix.version }} @@ -42,11 +42,11 @@ jobs: # version we are targeting with nox, while still having versions like 3.9.0a4 run: | echo "FRIENDLY_PYTHON_VERSION=$(python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")" >> $GITHUB_ENV - - name: install libxml2 and libxslt seems to only be needed for 3.9+ image for some reason - if: matrix.os == 'ubuntu-latest' && matrix.version == '3.9' || matrix.os == 'ubuntu-latest' && matrix.version == '3.10.0-beta.4' + - name: ensure openssl installed for macos + # openssl missing/being linked incorrectly causes ssh2-python install failures + if: matrix.os == 'macos-latest' run: | - sudo apt install libxml2-dev - sudo apt install libxslt-dev + brew install openssl - name: setup test env run: | python -m pip install --upgrade pip @@ -63,7 +63,18 @@ jobs: steps: - uses: actions/checkout@v2 - run: docker run -v $(pwd):/docs --entrypoint "" squidfunk/mkdocs-material:latest ash -c 'pip install mdx_gh_links && mkdocs build --clean --strict' + - name: Cache htmltest external links + uses: actions/cache@v2 + with: + path: tmp/.htmltest + # key will contain hash of all md files to check if files have changed + # when files are changed, a new key name is formed, and thus a new cache will be saved + key: htmltest-${{ hashFiles('docs/**/*.md') }} + # the restore key will fetch any previously saved cache even if there is no match on key + # this allows to use cache from prev runs and update it + restore-keys: | + htmltest- - name: htmltest - run: | - curl https://htmltest.wjdp.uk | bash - ./bin/htmltest -c docs/htmltest.yml + uses: wjdp/htmltest-action@v0.13.0-rc1 + with: + config: docs/htmltest.yml diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 6718604..6f015b4 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -9,10 +9,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: set up python 3.9 + - name: set up python 3.10 uses: actions/setup-python@v2 with: - python-version: 3.9 + python-version: "3.10" - name: setup publish env run: | python -m pip install --upgrade pip @@ -27,7 +27,7 @@ jobs: python setup.py sdist bdist_wheel python -m twine upload dist/* - name: create release branch - uses: peterjgrainger/action-create-branch@v2.0.1 + uses: peterjgrainger/action-create-branch@v2.1.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/weekly.yaml b/.github/workflows/weekly.yaml index 7708817..6109cad 100644 --- a/.github/workflows/weekly.yaml +++ b/.github/workflows/weekly.yaml @@ -13,7 +13,7 @@ jobs: max-parallel: 1 matrix: os: [ubuntu-latest] - version: [3.9] + version: ["3.10"] steps: - uses: actions/checkout@v2 - name: set up python ${{ matrix.version }} @@ -31,10 +31,10 @@ jobs: build_posix: runs-on: ${{ matrix.os }} strategy: - max-parallel: 12 + max-parallel: 8 matrix: os: [ubuntu-latest, macos-latest] - version: [3.6, 3.7, 3.8, 3.9, 3.10.0-beta.4] + version: ["3.7", "3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v2 - name: set up python ${{ matrix.version }} @@ -46,11 +46,11 @@ jobs: # version we are targeting with nox, while still having versions like 3.9.0a4 run: | echo "FRIENDLY_PYTHON_VERSION=$(python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")" >> $GITHUB_ENV - - name: install libxml2 and libxslt seems to only be needed for 3.9+ image for some reason - if: matrix.os == 'ubuntu-latest' && matrix.version == '3.9' || matrix.os == 'ubuntu-latest' && matrix.version == '3.10.0-beta.4' + - name: ensure openssl installed for macos + # openssl missing/being linked incorrectly causes ssh2-python install failures + if: matrix.os == 'macos-latest' run: | - sudo apt install libxml2-dev - sudo apt install libxslt-dev + brew install openssl - name: setup test env run: | python -m pip install --upgrade pip diff --git a/README.md b/README.md index 33ae55c..320a891 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ nornir_scrapli -- scrapli's plugin for nornir ## Requirements -MacOS or \*nix1, Python 3.6+ +MacOS or \*nix1, Python 3.7+ 1 Although many parts of scrapli *do* run on Windows, Windows is not officially supported diff --git a/docs/api_docs/connection.md b/docs/api_docs/connection.md index 71ae4d7..23739c7 100644 --- a/docs/api_docs/connection.md +++ b/docs/api_docs/connection.md @@ -519,7 +519,7 @@ Raises: ##### close -`close(self) ‑> NoneType` +`close(self) ‑> None` ```text Override close method of normal nornir connection so we never close things @@ -541,7 +541,7 @@ Raises: ##### open -`open(self, *args: Any, **kwargs: Any) ‑> NoneType` +`open(self, *args: Any, **kwargs: Any) ‑> None` ```text Override open method of normal nornir connection so we can coopt an existing conn @@ -671,7 +671,7 @@ class ScrapliCore: ##### close -`close(self) ‑> NoneType` +`close(self) ‑> None` ```text Close a scrapli connection to a device @@ -691,7 +691,7 @@ Raises: ##### open -`open(self, hostname: Optional[str], username: Optional[str], password: Optional[str], port: Optional[int], platform: Optional[str], extras: Optional[Dict[str, Any]] = None, configuration: Optional[nornir.core.configuration.Config] = None) ‑> NoneType` +`open(self, hostname: Optional[str], username: Optional[str], password: Optional[str], port: Optional[int], platform: Optional[str], extras: Optional[Dict[str, Any]] = None, configuration: Optional[nornir.core.configuration.Config] = None) ‑> None` ```text Open a scrapli connection to a device @@ -813,7 +813,7 @@ class ScrapliNetconf: ##### close -`close(self) ‑> NoneType` +`close(self) ‑> None` ```text Close a scrapli netconf connection to a device @@ -833,7 +833,7 @@ Raises: ##### open -`open(self, hostname: Optional[str], username: Optional[str], password: Optional[str], port: Optional[int], platform: Optional[str], extras: Optional[Dict[str, Any]] = None, configuration: Optional[nornir.core.configuration.Config] = None) ‑> NoneType` +`open(self, hostname: Optional[str], username: Optional[str], password: Optional[str], port: Optional[int], platform: Optional[str], extras: Optional[Dict[str, Any]] = None, configuration: Optional[nornir.core.configuration.Config] = None) ‑> None` ```text Open a scrapli connection to a device diff --git a/docs/api_docs/functions.md b/docs/api_docs/functions.md index 75241b5..b11d35e 100644 --- a/docs/api_docs/functions.md +++ b/docs/api_docs/functions.md @@ -43,7 +43,7 @@ __all__ = ("print_structured_result",) #### print_structured_result -`print_structured_result(result: nornir.core.task.AggregatedResult, failed: bool = False, severity_level: int = 20, parser: str = 'textfsm', to_dict: bool = True, fail_to_string: bool = False) ‑> NoneType` +`print_structured_result(result: nornir.core.task.AggregatedResult, failed: bool = False, severity_level: int = 20, parser: str = 'textfsm', to_dict: bool = True, fail_to_string: bool = False) ‑> None` ```text Prints the :obj:`nornir.core.task.Result` from a previous task to screen diff --git a/docs/api_docs/tasks.md b/docs/api_docs/tasks.md index 7211e0f..871c2fa 100644 --- a/docs/api_docs/tasks.md +++ b/docs/api_docs/tasks.md @@ -400,7 +400,7 @@ Raises: #### netconf_get_config -`netconf_get_config(task: nornir.core.task.Task, source: str = 'running', filters: Union[str, List[str], NoneType] = None, filter_type: str = 'subtree') ‑> nornir.core.task.Result` +`netconf_get_config(task: nornir.core.task.Task, source: str = 'running', filter_: Union[str, List[str], ForwardRef(None)] = None, filter_type: str = 'subtree') ‑> nornir.core.task.Result` ```text Get config from the device with scrapli_netconf @@ -408,7 +408,7 @@ Get config from the device with scrapli_netconf Args: task: nornir task object source: configuration source to get; typically one of running|startup|candidate - filters: string or list of strings of filters to apply to configuration + filter_: string of filter(s) to apply to configuration filter_type: type of filter; subtree|xpath Returns: @@ -517,7 +517,7 @@ Raises: #### send_command -`send_command(task: nornir.core.task.Task, command: str, strip_prompt: bool = True, failed_when_contains: Union[str, List[str], NoneType] = None, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` +`send_command(task: nornir.core.task.Task, command: str, strip_prompt: bool = True, failed_when_contains: Union[str, List[str], ForwardRef(None)] = None, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` ```text Send a single command to device using scrapli @@ -546,7 +546,7 @@ Raises: #### send_commands -`send_commands(task: nornir.core.task.Task, commands: List[str], strip_prompt: bool = True, failed_when_contains: Union[str, List[str], NoneType] = None, stop_on_failed: bool = False, eager: bool = False, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` +`send_commands(task: nornir.core.task.Task, commands: List[str], strip_prompt: bool = True, failed_when_contains: Union[str, List[str], ForwardRef(None)] = None, stop_on_failed: bool = False, eager: bool = False, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` ```text Send a list of commands to device using scrapli @@ -580,7 +580,7 @@ Raises: #### send_commands_from_file -`send_commands_from_file(task: nornir.core.task.Task, file: str, strip_prompt: bool = True, failed_when_contains: Union[str, List[str], NoneType] = None, stop_on_failed: bool = False, eager: bool = False, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` +`send_commands_from_file(task: nornir.core.task.Task, file: str, strip_prompt: bool = True, failed_when_contains: Union[str, List[str], ForwardRef(None)] = None, stop_on_failed: bool = False, eager: bool = False, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` ```text Send a list of commands from a file to device using scrapli @@ -613,7 +613,7 @@ Raises: #### send_config -`send_config(task: nornir.core.task.Task, config: str, dry_run: Optional[bool] = None, strip_prompt: bool = True, failed_when_contains: Union[str, List[str], NoneType] = None, stop_on_failed: bool = False, privilege_level: str = '', eager: bool = False, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` +`send_config(task: nornir.core.task.Task, config: str, dry_run: Optional[bool] = None, strip_prompt: bool = True, failed_when_contains: Union[str, List[str], ForwardRef(None)] = None, stop_on_failed: bool = False, privilege_level: str = '', eager: bool = False, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` ```text Send a config to device using scrapli @@ -656,7 +656,7 @@ Raises: #### send_configs -`send_configs(task: nornir.core.task.Task, configs: List[str], dry_run: Optional[bool] = None, strip_prompt: bool = True, failed_when_contains: Union[str, List[str], NoneType] = None, stop_on_failed: bool = False, privilege_level: str = '', eager: bool = False, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` +`send_configs(task: nornir.core.task.Task, configs: List[str], dry_run: Optional[bool] = None, strip_prompt: bool = True, failed_when_contains: Union[str, List[str], ForwardRef(None)] = None, stop_on_failed: bool = False, privilege_level: str = '', eager: bool = False, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` ```text Send configs to device using scrapli @@ -699,7 +699,7 @@ Raises: #### send_configs_from_file -`send_configs_from_file(task: nornir.core.task.Task, file: str, dry_run: Optional[bool] = None, strip_prompt: bool = True, failed_when_contains: Union[str, List[str], NoneType] = None, stop_on_failed: bool = False, privilege_level: str = '', eager: bool = False, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` +`send_configs_from_file(task: nornir.core.task.Task, file: str, dry_run: Optional[bool] = None, strip_prompt: bool = True, failed_when_contains: Union[str, List[str], ForwardRef(None)] = None, stop_on_failed: bool = False, privilege_level: str = '', eager: bool = False, timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` ```text Send configs from a file to device using scrapli @@ -742,7 +742,7 @@ Raises: #### send_interactive -`send_interactive(task: nornir.core.task.Task, interact_events: List[Tuple[str, str, Optional[bool]]], failed_when_contains: Union[str, List[str], NoneType] = None, privilege_level: str = '', timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` +`send_interactive(task: nornir.core.task.Task, interact_events: List[Tuple[str, str, Optional[bool]]], failed_when_contains: Union[str, List[str], ForwardRef(None)] = None, privilege_level: str = '', timeout_ops: Optional[float] = None) ‑> nornir.core.task.Result` ```text Send inputs in an interactive fashion using scrapli; usually used to handle prompts diff --git a/docs/htmltest.yml b/docs/htmltest.yml index 579c571..476b32a 100644 --- a/docs/htmltest.yml +++ b/docs/htmltest.yml @@ -10,3 +10,9 @@ IgnoreSSLVerify: true IgnoreDirs: - overrides IgnoreInternalEmptyHash: true +ExternalTimeout: 60 +HTTPHeaders: + "Range": "bytes=0-10" + "Accept": "*/*" +CacheExpires: "96h" +HTTPConcurrencyLimit: 1 \ No newline at end of file diff --git a/nornir_scrapli/tasks/netconf/get_config.py b/nornir_scrapli/tasks/netconf/get_config.py index dc9e7c8..95e8152 100644 --- a/nornir_scrapli/tasks/netconf/get_config.py +++ b/nornir_scrapli/tasks/netconf/get_config.py @@ -8,7 +8,7 @@ def netconf_get_config( task: Task, source: str = "running", - filters: Optional[Union[str, List[str]]] = None, + filter_: Optional[Union[str, List[str]]] = None, filter_type: str = "subtree", ) -> Result: """ @@ -17,7 +17,7 @@ def netconf_get_config( Args: task: nornir task object source: configuration source to get; typically one of running|startup|candidate - filters: string or list of strings of filters to apply to configuration + filter_: string of filter(s) to apply to configuration filter_type: type of filter; subtree|xpath Returns: @@ -30,7 +30,7 @@ def netconf_get_config( """ scrapli_conn = task.host.get_connection("scrapli_netconf", task.nornir.config) scrapli_response = scrapli_conn.get_config( - source=source, filters=filters, filter_type=filter_type + source=source, filter_=filter_, filter_type=filter_type ) result = ScrapliResult( diff --git a/noxfile.py b/noxfile.py index 6ad4723..3ea29f7 100644 --- a/noxfile.py +++ b/noxfile.py @@ -26,9 +26,9 @@ def parse_requirements(dev: bool = True) -> Dict[str, str]: """ requirements = {} - requirements_file = "requirements.txt" if dev is False else "requirements-dev.txt" + requirements_file = "requirements.txt" if not dev else "requirements-dev.txt" - with open(requirements_file, "r") as f: + with open(requirements_file, "r", encoding="utf-8") as f: requirements_file_lines = f.readlines() requirements_lines: List[str] = [ @@ -63,7 +63,7 @@ def parse_requirements(dev: bool = True) -> Dict[str, str]: SKIP_LIST: List[str] = [] -@nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10"]) +@nox.session(python=["3.7", "3.8", "3.9", "3.10"]) def unit_tests(session): """ Nox run unit tests @@ -97,7 +97,7 @@ def unit_tests(session): ) -@nox.session(python=["3.9"]) +@nox.session(python=["3.10"]) def isort(session): """ Nox run isort @@ -116,7 +116,7 @@ def isort(session): session.run("python", "-m", "isort", "-c", ".") -@nox.session(python=["3.9"]) +@nox.session(python=["3.10"]) def black(session): """ Nox run black @@ -135,7 +135,7 @@ def black(session): session.run("python", "-m", "black", "--check", ".") -@nox.session(python=["3.9"]) +@nox.session(python=["3.10"]) def pylama(session): """ Nox run pylama @@ -154,7 +154,7 @@ def pylama(session): session.run("python", "-m", "pylama", ".") -@nox.session(python=["3.9"]) +@nox.session(python=["3.10"]) def pydocstyle(session): """ Nox run pydocstyle @@ -173,7 +173,7 @@ def pydocstyle(session): session.run("python", "-m", "pydocstyle", ".") -@nox.session(python=["3.9"]) +@nox.session(python=["3.10"]) def mypy(session): """ Nox run mypy @@ -193,7 +193,7 @@ def mypy(session): session.run("python", "-m", "mypy", "--strict", "nornir_scrapli/") -@nox.session(python=["3.9"]) +@nox.session(python=["3.10"]) def darglint(session): """ Nox run darglint diff --git a/pyproject.toml b/pyproject.toml index 96a9361..c4d119b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,4 @@ [tool.black] line-length = 100 -target-version = ['py38'] +target-version = ['py310'] + diff --git a/requirements-dev.txt b/requirements-dev.txt index b105bd1..be6aa26 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,13 +1,13 @@ -black==21.7b0 -darglint==1.8.0 -isort==5.9.3 -mypy==0.910 -nox==2021.6.12 -pycodestyle==2.7.0 -pydocstyle==6.1.1 -pylama==7.7.1 -pylint==2.9.6 -pytest-cov==2.12.1 -pytest==6.2.4 +black==21.12b0 +darglint==1.8.1,<2.0.0 +isort>=5.10.1,<6.0.0 +mypy==0.931 +nox==2022.01.07 +pycodestyle==2.8.0,<3.0.0 +pydocstyle==6.1.1,<7.0.0 +pylama==8.3.7,<9.0.0 +pylint==2.12.2 +pytest-cov>=3.0.0,<4.0.0 +pytest>=6.2.5,<7.0.0 -r requirements-genie.txt -r requirements.txt \ No newline at end of file diff --git a/requirements-docs.txt b/requirements-docs.txt index 76fbbb4..f4ac22b 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,5 +1,5 @@ -mdx-gh-links==0.2 -mkdocs==1.2.2 -mkdocs-material==7.2.2 -mkdocs-material-extensions==1.0.1 -pdoc3==0.10.0 ; sys_platform != "win32" \ No newline at end of file +mdx-gh-links>=0.2,<1.0 +mkdocs>=1.2.3,<2.0.0 +mkdocs-material>=8.1.6,<9.0.0 +mkdocs-material-extensions>=1.0.3,<2.0.0 +pdoc3>=0.10.0,<1.0.0 ; sys_platform != "win32" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index c8ab3cc..913eb77 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -nornir>=3.0.0,<4.0.0 +nornir>=3.0.0 nornir_utils>=0.1.0 -ntc_templates>=1.1.0,<3.0.0 -scrapli>=2021.07.30 -scrapli_cfg>=2021.07.30 +ntc_templates>=1.1.0 +scrapli>=2022.01.30 +scrapli_cfg>=2022.01.30 scrapli_community>=2021.01.30 -scrapli_netconf>=2021.01.30 -textfsm>=1.1.0,<2.0.0 +scrapli_netconf>=2022.01.30 +textfsm>=1.1.0 diff --git a/setup.cfg b/setup.cfg index 6c0b20a..b133d60 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,7 +42,7 @@ strictness = full ignore = DAR202 [mypy] -python_version = 3.9 +python_version = 3.10 pretty = True ignore_missing_imports = True warn_redundant_casts = True diff --git a/setup.py b/setup.py index 78da663..88e1eb5 100644 --- a/setup.py +++ b/setup.py @@ -2,13 +2,13 @@ """nornir_scrapli""" import setuptools -__version__ = "2021.07.30" +__version__ = "2022.01.30" __author__ = "Carl Montanari" with open("README.md", "r", encoding="utf-8") as f: README = f.read() -with open("requirements.txt", "r") as f: +with open("requirements.txt", "r", encoding="utf-8") as f: INSTALL_REQUIRES = f.read().splitlines() EXTRAS_REQUIRE = { @@ -16,7 +16,7 @@ } for extra in EXTRAS_REQUIRE: - with open(f"requirements-{extra}.txt", "r") as f: + with open(f"requirements-{extra}.txt", "r", encoding="utf-8") as f: EXTRAS_REQUIRE[extra] = f.read().splitlines() full_requirements = [requirement for extra in EXTRAS_REQUIRE.values() for requirement in extra] @@ -48,7 +48,6 @@ "Operating System :: POSIX :: Linux", "Operating System :: MacOS", "Programming Language :: Python", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", @@ -56,7 +55,7 @@ "Programming Language :: Python :: 3 :: Only", "Topic :: Software Development :: Libraries :: Python Modules", ], - python_requires=">=3.6", + python_requires=">=3.7", entry_points=""" [nornir.plugins.connections] scrapli=nornir_scrapli.connection:ScrapliCore diff --git a/tests/unit/tasks/test_netconf_get_config.py b/tests/unit/tasks/test_netconf_get_config.py index b315409..bebd16a 100644 --- a/tests/unit/tasks/test_netconf_get_config.py +++ b/tests/unit/tasks/test_netconf_get_config.py @@ -8,7 +8,7 @@ def test_netconf_get_config(nornir_netconf, monkeypatch): def mock_open(cls): pass - def mock_get_config(cls, source, filters, filter_type): + def mock_get_config(cls, source, filter_, filter_type): response = Response(host="fake_as_heck", channel_input="blah") response.record_response(b"some stuff about whatever") return response