Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 1.8.3
current_version = 1.9.0
commit = False
tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+)(?P<build>\d+))?
Expand Down
11 changes: 6 additions & 5 deletions .github/workflows/test-package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12"]
python-version: ["3.11", "3.12", "3.13"]
fail-fast: false

steps:
Expand All @@ -27,12 +27,13 @@ jobs:
python -m pip install --upgrade pip
pip install flit
flit install --deps develop --symlink
- name: Ruff
run: ruff check .
- name: Black
run: black . --check
- name: Mypy
run: mypy .
- name: License headers
run: |
apache-license-check --copyright "2019-`date +%Y` SURF" nwastdlib
- name: Run pre-commit hooks
uses: pre-commit/action@v3.0.1
- name: Test with pytest
run: pytest --cov-branch --cov=nwastdlib --cov-report=xml --ignore=tests --ignore=benchmarks
- name: "Upload coverage to Codecov"
Expand Down
21 changes: 13 additions & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v3.2.2
rev: v3.19.1
hooks:
- id: pyupgrade
exclude: tests
args:
- --py39-plus
- --py311-plus
- --keep-runtime-typing
- repo: https://github.com/psf/black
rev: 23.10.1
rev: 24.10.0
hooks:
- id: black
language_version: python3.9
- repo: https://github.com/asottile/blacken-docs
rev: 1.16.0
rev: 1.19.1
hooks:
- id: blacken-docs
additional_dependencies: [black==22.1.0]
additional_dependencies: [black==24.10.0]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
exclude: .bumpversion.cfg
Expand All @@ -30,6 +29,12 @@ repos:
- id: debug-statements
- id: requirements-txt-fixer
- id: detect-private-key
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.8.4
hooks:
- id: ruff
args: [ --fix, --exit-non-zero-on-fix, --show-fixes ]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
Expand All @@ -38,6 +43,6 @@ repos:
- id: python-check-mock-methods
- id: rst-backticks
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.9.0.6
rev: v0.10.0.1
hooks:
- id: shellcheck
71 changes: 58 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,80 @@
[![Supported python versions](https://img.shields.io/pypi/pyversions/nwa-stdlib.svg?color=%2334D058)](https://pypi.org/project/nwa-stdlib)
[![codecov](https://codecov.io/github/workfloworchestrator/nwa-stdlib/graph/badge.svg?token=9XWVHKKF06)](https://codecov.io/github/workfloworchestrator/nwa-stdlib)

This library contains the functions and utilities that are shared by most
Network Automation projects built at SURF.
This library contains the functions and utilities that are shared by most Network Automation projects built at SURF.

## Getting started
## Installation

If you want to use a virtual environment first create the environment:
To install the package from PyPI:

```bash
pip install flit
pip install nwa-stdlib
```
And then run the following commands:

If you want to enhance or develop bug fixes for `nwastdlib` it's easiest to run the following commands:
## Development

### Virtual Environment

Steps to setup a virtual environment.

#### Step 1:

Create and activate a python3 virtualenv.

#### Step 2:

Install flit to enable you to develop on this repository:

```bash
flit install --deps develop --symlink
pip install flit
```

## Development
Depending on the feature type, run bumpversion (patch|minor|major) to increment the version you are working on. For
example to update the increment the patch version use
#### Step 3:

To install all development dependencies:

```bash
bumpversion patch
flit install --deps develop
```

## To run tests
All steps combined into 1 command:

```bash
python -m venv .venv && source .venv/bin/activate && pip install -U pip && pip install flit && flit install --deps develop
```

### Unit tests

Activate the virtualenv and run the unit tests with:

```bash
pytest
```

### Pre-commit

This project uses [pre-commit](https://pre-commit.com/) to automatically run a number of checks before making a git commit.
The same checks will be performed in the CI pipeline so this can save you some time.

First ensure you have pre-commit installed.
It is recommended to install it outside the virtualenv.
On Linux and Mac, pre-commit is available in most package managers. Alternatively you can install it globally with [pipx](https://github.com/pypa/pipx).

Once pre-commit is installed, go into the project root and enable it:
```bash
pre-commit install
```

This should output `pre-commit installed at .git/hooks/pre-commit`. The next time you run `git commit` the pre-commit hooks will validate your changes.

### Bump version

Depending on the feature type, run bumpversion (patch|minor|major) to increment the version you are working on. For
example to update the increment the patch version use
```bash
bumpversion patch
```

## Supported Python versions

nwa-stdlib must support the same python versions as [orchestrator-core](https://github.com/workfloworchestrator/orchestrator-core).
Expand Down
22 changes: 11 additions & 11 deletions nwastdlib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# Copyright 2019 SURF.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Copyright 2019-2025 SURF.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
#
"""The NWA-stdlib module."""

__version__ = "1.8.3"
__version__ = "1.9.0"

from nwastdlib.f import const, identity

Expand Down
10 changes: 5 additions & 5 deletions nwastdlib/asyncio.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2019-2024 SURF.
# Copyright 2019-2025 SURF.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
Expand All @@ -13,7 +13,7 @@
import asyncio
import warnings
from collections.abc import Awaitable, Callable, Iterable
from typing import TypeVar, Union
from typing import TypeVar

A = TypeVar("A")
R = TypeVar("R")
Expand All @@ -29,7 +29,7 @@ async def gather_nice_sync(
args: Iterable[A],
limit: int = 5,
return_exceptions: bool = False,
) -> list[R]:
) -> list[R | BaseException]:
"""Run function in thread for each args, using asyncio.gather() with limited concurrency.

Example:
Expand All @@ -45,7 +45,7 @@ def my_function_2(arg1, arg2):

"""

def make_args(func_args: Union[Iterable, object]) -> Iterable:
def make_args(func_args: Iterable | object) -> Iterable:
# When one argument is passed, wrap it in a list so run_sync can unpack it again
if not isinstance(func_args, (tuple, list, set)):
return [func_args]
Expand All @@ -60,7 +60,7 @@ async def gather_nice(
coros: Iterable[Awaitable[R]],
limit: int = 5,
return_exceptions: bool = False,
) -> Iterable[R]:
) -> Iterable[R | BaseException]:
"""Run coroutines in asyncio.gather() with limited concurrency.

Example:
Expand Down
37 changes: 19 additions & 18 deletions nwastdlib/asyncio_cache.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
# Copyright 2019-2024 SURF.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Copyright 2019-2025 SURF.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
#
import hashlib
import hmac
import pickle # noqa S403
import pickle # noqa: S403
import sys
from collections.abc import Callable
from functools import wraps
from typing import Any, Callable, Protocol, Union, runtime_checkable
from typing import Any, Protocol, runtime_checkable

import structlog
from redis.asyncio import Redis as AIORedis
Expand All @@ -40,11 +41,11 @@ class DefaultSerializer:

@staticmethod
def deserialize(data: Any) -> Any:
return pickle.loads(data) # noqa S403
return pickle.loads(data) # noqa: S301

@staticmethod
def serialize(data: Union[bytes, bytearray, str]) -> Any:
return pickle.dumps(data) # noqa S403
def serialize(data: bytes | bytearray | str) -> Any:
return pickle.dumps(data)


def _deserialize(data: Any, serializer: SerializerProtocol) -> Any:
Expand All @@ -58,7 +59,7 @@ def _deserialize(data: Any, serializer: SerializerProtocol) -> Any:
return data


def get_hmac_checksum(secret: str, message: Union[bytes, bytearray, str]) -> str:
def get_hmac_checksum(secret: str, message: bytes | bytearray | str) -> str:
if isinstance(message, str):
message = message.encode()
h = hmac.new(secret.encode(), message, hashlib.sha512)
Expand Down Expand Up @@ -113,8 +114,8 @@ async def get_signed_cache_value(pool: AIORedis, secret: str, cache_key: str, se
def cached_result(
pool: AIORedis,
prefix: str,
secret: Union[str, None],
key_name: Union[str, None] = None,
secret: str | None,
key_name: str | None = None,
expiry_seconds: int = 120,
serializer: SerializerProtocol = DefaultSerializer,
) -> Callable:
Expand Down
2 changes: 1 addition & 1 deletion nwastdlib/debugging.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2019-2024 SURF.
# Copyright 2019-2025 SURF.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
Expand Down
23 changes: 11 additions & 12 deletions nwastdlib/ex.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
# Copyright 2019-2024 SURF.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Copyright 2019-2025 SURF.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
#

"""Module containing functions to deal with `Exception`s."""


import traceback
from typing import Union


def show_ex(ex: Exception, stacklimit: Union[int, None] = None) -> str:
def show_ex(ex: Exception, stacklimit: int | None = None) -> str:
"""Show an exception, including its class name, message and (limited) stacktrace.

>>> try:
Expand Down
23 changes: 12 additions & 11 deletions nwastdlib/f.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# Copyright 2019-2024 SURF.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Copyright 2019-2025 SURF.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
#

from typing import Any, Callable, TypeVar
from collections.abc import Callable
from typing import Any, TypeVar

α = TypeVar("α")
β = TypeVar("β")
Expand Down
Loading
Loading