Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
10 changes: 5 additions & 5 deletions .github/workflows/pull-request-management.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ jobs:
rust_src_or_ci_changed:
- '.github/**/*'
- 'rust/**/*'
- 'python/avdutils/**/*'
- 'pyavd-utils/**/*'
- 'Cargo.toml'

# -------------------------------------- #
Expand Down Expand Up @@ -749,7 +749,7 @@ jobs:
run: |
pip install tox tox-gh-actions --upgrade
- name: Run pytest via tox
working-directory: python/avdutils
working-directory: pyavd-utils
# Running tox which will build the package (including rust).
# For most runs without an environment set here. The environment is mapped with the tox gh-action plugin.
run: |
Expand All @@ -772,11 +772,11 @@ jobs:
run: |
pip install tox tox-gh-actions --upgrade
- name: Run pytest via tox
working-directory: python/avdutils
working-directory: pyavd-utils
run: |
tox -e coverage,report
- name: Upload coverage from pytest
uses: actions/upload-artifact@v4
with:
name: pytest-avdutils-coverage
path: python/avdutils/coverage.xml
name: pytest-pyavd-utils-coverage
path: pyavd-utils/coverage.xml
6 changes: 3 additions & 3 deletions .github/workflows/sonar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ jobs:
path: python-avd/
merge-multiple: true

- name: Download coverage from pytest avdutils (bindings for rust)
- name: Download coverage from pytest pyavd-utils (bindings for rust)
continue-on-error: true
uses: actions/download-artifact@v5
with:
name: pytest-avdutils-coverage
name: pytest-pyavd-utils-coverage
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
path: python/avdutils/
path: pyavd-utils/
merge-multiple: true

- name: Download eos_designs compiled templates from pytest
Expand Down
17 changes: 5 additions & 12 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,6 @@ __pycache__/
coverage.xml
*.so

# Python source
/python/**/build/
/python/**/dist/
/python/**/*.egg-info/
/python/**/.tox/

# pyavd ignores
/python-avd/build/
/python-avd/dist/
/python-avd/pyavd.egg-info/
/python-avd/.tox/

# Ignore cloned cloudvision-python repo created during generation of _cv/api
/python-avd/pyavd/_cv/cloudvision-apis/

Expand All @@ -40,6 +28,11 @@ coverage.xml
ansible_collections/arista/avd/.ansible

# Development
build/
dist/
*.egg-info/
.tox/
.pytest_cache/
## pyenv
.python-version
## .vscode/*
Expand Down
14 changes: 14 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,23 @@ members = [
"rust/avdschema_macros",
"rust/validation",
"rust/passwords",
"pyavd-utils/rust/pypasswords",
"pyavd-utils/rust/pyvalidation",
]
resolver = "2"

[workspace.dependencies]
derive_more = { version = "2.0.1" }
log = { version = "0.4.26" }
ordermap = { version = "0.5.4" }
pyo3 = { version = "0.26.0" }
pyo3-build-config = { version = "0.26.0"}
pyo3-log = { version = "0.13.1" }
regex = { version = "1.11.1" }
serde = { version = "1.0.217" }
serde_json = { version = "1.0.135" }
serde_yaml = { version = "0.9.33" }

[profile.release-lto]
inherits = "release"
lto = true
Expand Down
36 changes: 36 additions & 0 deletions pyavd-utils/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
CURRENT_DIR = $(shell pwd)
ANSIBLE_AVD_DIR ?= ..
SCRIPTS_DIR = $(CURRENT_DIR)/scripts

# export PYTHONPATH=$(CURRENT_DIR) # Uncomment to test from source

.PHONY: help
help: ## Display help message
@grep -E '^[0-9a-zA-Z_-]+\.*[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

.PHONY: build
build: ## Build pyavd package
pip3 install build
rm -rf $(CURRENT_DIR)/build/ $(CURRENT_DIR)/dist/ $(CURRENT_DIR)/pyavd.egg-info/
python3 -m build --wheel

.PHONY: uv-build
uv-build: ## Build pyavd package
uv pip install build
rm -rf $(CURRENT_DIR)/build/ $(CURRENT_DIR)/dist/ $(CURRENT_DIR)/pyavd.egg-info/
python3 -m build --wheel


.PHONY: publish
publish: ## Publish pyavd package to PyPI (build first)
pip3 install twine && \
twine check dist/* && \
twine upload -r testpypi dist/* && \
twine upload dist/*

.PHONY: uv-publish
uv-publish: ## Publish pyavd package to PyPI (build first)
Comment thread
ClausHolbechArista marked this conversation as resolved.
uv pip install twine && \
twine check dist/* && \
twine upload -r testpypi dist/* && \
twine upload dist/*
File renamed without changes.
File renamed without changes.
15 changes: 7 additions & 8 deletions python/avdutils/pyproject.toml → pyavd-utils/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ requires = ["setuptools", "setuptools-rust"]
build-backend = "setuptools.build_meta"

[project]
name = "avdutils"
name = "pyavd-utils"
version = "0.0.1"

[dependency-groups]
Expand All @@ -14,20 +14,19 @@ coverage = ["coverage[toml]"]
py-limited-api = "cp310"

[tool.setuptools.packages.find]
include = ["avdutils"]
include = ["pyavd_utils"]

[tool.setuptools.package-data]
"avdutils" = ["*.pyi"]
"pyavd_utils" = ["*.pyi"]

[[tool.setuptools-rust.ext-modules]]
target = "avdutils.validation"
path = "../../rust/validation/Cargo.toml"
target = "pyavd_utils.passwords"
path = "rust/pypasswords/Cargo.toml"
binding = "PyO3"
features = ["python_bindings"]

[[tool.setuptools-rust.ext-modules]]
target = "avdutils.passwords"
path = "../../rust/passwords/Cargo.toml"
target = "pyavd_utils.validation"
path = "rust/pyvalidation/Cargo.toml"
binding = "PyO3"

[tool.pytest.ini_options]
Expand Down
15 changes: 15 additions & 0 deletions pyavd-utils/rust/pypasswords/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "pypasswords"
version.workspace = true
edition = "2024"
license.workspace = true

[build-dependencies]
pyo3-build-config = { workspace = true }

[dependencies]
pyo3 = {workspace = true, "features" = ["extension-module", "abi3"] }
passwords = { path = "../../../rust/passwords" }

[lib]
crate-type = ["cdylib", "lib"]
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-env-changed=CARGO_CFG_TARGET_OS");

if let Ok(current_target_os) = env::var("CARGO_CFG_TARGET_OS") {
println!("cargo:warning=Compiling on 'macos'");
if current_target_os == "macos" {
if let Ok(current_target_os) = env::var("CARGO_CFG_TARGET_OS")
&& current_target_os == "macos" {
println!("cargo:warning=Compiling on 'macos'");
// Needed for MacOS when using pyo3 extension-module
pyo3_build_config::add_extension_module_link_args();
}
}
}
28 changes: 28 additions & 0 deletions pyavd-utils/rust/pypasswords/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2025 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the LICENSE file.

use pyo3::pymodule;

#[pymodule]
#[pyo3(name = "passwords")]
mod passwords {

use pyo3::{PyResult, pyfunction};

#[pyfunction]
/// Computes the SHA512 crypt value for the password given the salt
pub fn sha512_crypt(password: String, salt: String) -> PyResult<String> {
passwords::sha512_crypt(&password, &salt).map_err(|err| {
// Mapping our crates error to Python errors.
match err {
passwords::Sha512CryptError::InvalidSalt(_) => {
pyo3::exceptions::PyValueError::new_err(format!("{err}"))
}
passwords::Sha512CryptError::ShaCrypt(_) => {
pyo3::exceptions::PyRuntimeError::new_err(format!("{err}"))
}
}
})
}
}
27 changes: 27 additions & 0 deletions pyavd-utils/rust/pyvalidation/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "pyvalidation"
version.workspace = true
edition = "2024"
license.workspace = true

[build-dependencies]
pyo3-build-config = { workspace = true }

[dependencies]
avdschema = { path = "../../../rust/avdschema", features = ["dump_load_files"] }
included_store = { path = "../../../rust/included_store" }
validation = { path = "../../../rust/validation", features = ["python_bindings"] }

derive_more = { workspace = true, features = ["display", "from"] }
log = { workspace = true }
pyo3 = { workspace = true, "features" = ["extension-module", "abi3"] }
pyo3-log = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, features = [
"arbitrary_precision", # To support very big numbers
"preserve_order",
] }
serde_yaml = { workspace = true }

[lib]
crate-type = ["cdylib", "lib"]
17 changes: 17 additions & 0 deletions pyavd-utils/rust/pyvalidation/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) 2025 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the LICENSE file.

use std::env;

fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-env-changed=CARGO_CFG_TARGET_OS");

if let Ok(current_target_os) = env::var("CARGO_CFG_TARGET_OS")
&& current_target_os == "macos" {
println!("cargo:warning=Compiling on 'macos'");
// Needed for MacOS when using pyo3 extension-module
pyo3_build_config::add_extension_module_link_args();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ mod validation {

use pyo3::{Bound, PyResult, exceptions::PyRuntimeError, pyfunction, types::PyModule};

use crate::{
StoreValidate as _, coercion::Coercion, context::Context, validation::Validation,
validation_result::ValidationResult,
};
use validation::{Coercion as _, Context, StoreValidate as _, Validation as _, ValidationResult};

use super::{STORE, get_store};

Expand All @@ -42,7 +39,7 @@ mod validation {
}

#[pymodule_export]
use crate::feedback::{
use ::validation::feedback::{
CoercionNote, Feedback, Issue, Type, Value, Violation, ViolationValidValues,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import pytest

from avdutils.passwords import sha512_crypt
from pyavd_utils.passwords import sha512_crypt

SHA512_CRYPT_TEST_DATA = [
pytest.param(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@

import pytest

from avdutils.validation import Issue, Value, Violation, init_store_from_fragments, validate_json
from pyavd_utils.validation import Issue, Value, Violation, init_store_from_fragments, validate_json


@pytest.fixture
def init_store() -> None:
org_path = sys.path
# Insert /python-avd into the python path to be able to import constants from schema_tools.
mocked_path = [str(Path(__file__).parents[4] / "python-avd"), *org_path]
mocked_path = [str(Path(__file__).parents[3] / "python-avd")]
Comment thread
gmuloc marked this conversation as resolved.
sys.path = mocked_path
from schema_tools.constants import SCHEMAS

Expand Down
File renamed without changes.
13 changes: 2 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,11 @@ convention = "google"
"PLR0913", # Too many arguments in function definition - OK since these are data classes
"D205", # 1 blank line required between summary line and description - OK since descriptions are autogenerated and for data fields.
]
"python-avd/tests/**/*" = [
"S101", # Accept 'assert' in pytest.
"INP001", # implicit namespace package. Add an `__init__.py` - Tests are not in packages
"PLC0415", # `import` should be at the top-level of a file
]
"python/**/tests/**/*" = [
"**/tests/**/*" = [
"S101", # Accept 'assert' in pytest.
"INP001", # implicit namespace package. Add an `__init__.py` - Tests are not in packages
"PLC0415", # `import` should be at the top-level of a file
]
"ansible_collections/arista/avd/tests/**/*" = [
"S101", # Accept 'assert' in pytest.
"INP001", # implicit namespace package. Add an `__init__.py` - Tests are not in packages
]
"python-avd/pyavd/_anta/index.py" = [
"F403", # Allow wildcard imports to avoid cluttering the index
"F405", # Allow names defined in via a wildcard import
Expand All @@ -110,7 +101,7 @@ max-returns = 10
max-statements = 148

[tool.ruff.lint.isort]
known-first-party = ["avdutils", "pyavd", "schema_tools"]
known-first-party = ["pyavd_utils", "pyavd", "schema_tools"]

[tool.ruff.format]
docstring-code-format = true
Expand Down
2 changes: 0 additions & 2 deletions python/avdutils/MANIFEST.in

This file was deleted.

12 changes: 6 additions & 6 deletions rust/avdschema/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ edition = "2024"
license.workspace = true

[dependencies]
derive_more = { version = "2.0.1", features = [
derive_more = { workspace = true, features = [
"constructor",
"display",
"from",
] }
flate2 = { version = "1.1.0" }
ordermap = { version = "0.5.4", features = ["serde"] }
regex = { version = "1.11.1" }
serde = { version = "1.0.217", features = ["derive"] }
serde_json = { version = "1.0.135", features = ["preserve_order"] }
ordermap = { workspace = true, features = ["serde"] }
regex = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, features = ["preserve_order"] }
serde_with = { version = "3.12.0" }
serde_yaml = { version = "0.9.33" }
serde_yaml = { workspace = true }
walkdir = { version = "2.5.0", optional = true }
xz2 = { version = "0.1.7", optional = true }

Expand Down
2 changes: 1 addition & 1 deletion rust/included_store/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ license.workspace = true
[dependencies]
avdschema = { path = "../avdschema" }
avdschema_macros = { path = "../avdschema_macros" }
log = "0.4.26"
log = { workspace = true }
Loading
Loading