neroued-3mf 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. neroued_3mf-0.2.0/.clang-format +17 -0
  2. neroued_3mf-0.2.0/.cursor/hooks/block-dangerous.sh +52 -0
  3. neroued_3mf-0.2.0/.cursor/hooks/check-docs-sync.sh +45 -0
  4. neroued_3mf-0.2.0/.cursor/hooks/format-cpp.sh +18 -0
  5. neroued_3mf-0.2.0/.cursor/hooks/protect-secrets.sh +43 -0
  6. neroued_3mf-0.2.0/.cursor/hooks.json +29 -0
  7. neroued_3mf-0.2.0/.cursor/rules/code-structure.mdc +25 -0
  8. neroued_3mf-0.2.0/.cursor/rules/cpp-formatting.mdc +17 -0
  9. neroued_3mf-0.2.0/.cursor/rules/cross-platform-cpp.mdc +27 -0
  10. neroued_3mf-0.2.0/.cursor/rules/git-policy.mdc +11 -0
  11. neroued_3mf-0.2.0/.cursor/rules/sync-docs.mdc +17 -0
  12. neroued_3mf-0.2.0/.github/workflows/ci.yml +230 -0
  13. neroued_3mf-0.2.0/.github/workflows/wheels.yml +158 -0
  14. neroued_3mf-0.2.0/.gitignore +42 -0
  15. neroued_3mf-0.2.0/AGENTS.md +130 -0
  16. neroued_3mf-0.2.0/CMakeLists.txt +127 -0
  17. neroued_3mf-0.2.0/COMMERCIAL_LICENSE.md +20 -0
  18. neroued_3mf-0.2.0/LICENSE +661 -0
  19. neroued_3mf-0.2.0/PKG-INFO +24 -0
  20. neroued_3mf-0.2.0/README.md +115 -0
  21. neroued_3mf-0.2.0/cmake/neroued_3mf-config.cmake.in +4 -0
  22. neroued_3mf-0.2.0/docs/API.md +126 -0
  23. neroued_3mf-0.2.0/docs/BUILDING.md +143 -0
  24. neroued_3mf-0.2.0/docs/DESIGN.md +456 -0
  25. neroued_3mf-0.2.0/docs/EXAMPLES.md +214 -0
  26. neroued_3mf-0.2.0/include/neroued/3mf/builder.h +96 -0
  27. neroued_3mf-0.2.0/include/neroued/3mf/document.h +124 -0
  28. neroued_3mf-0.2.0/include/neroued/3mf/error.h +26 -0
  29. neroued_3mf-0.2.0/include/neroued/3mf/fwd.h +45 -0
  30. neroued_3mf-0.2.0/include/neroued/3mf/materials.h +27 -0
  31. neroued_3mf-0.2.0/include/neroued/3mf/neroued_3mf.h +16 -0
  32. neroued_3mf-0.2.0/include/neroued/3mf/types.h +107 -0
  33. neroued_3mf-0.2.0/include/neroued/3mf/version.h.in +11 -0
  34. neroued_3mf-0.2.0/include/neroued/3mf/writer.h +43 -0
  35. neroued_3mf-0.2.0/pyproject.toml +76 -0
  36. neroued_3mf-0.2.0/python/CMakeLists.txt +28 -0
  37. neroued_3mf-0.2.0/python/neroued_3mf/__init__.py +70 -0
  38. neroued_3mf-0.2.0/python/neroued_3mf/py.typed +0 -0
  39. neroued_3mf-0.2.0/python/src/bind.cpp +549 -0
  40. neroued_3mf-0.2.0/python/tests/conftest.py +10 -0
  41. neroued_3mf-0.2.0/python/tests/test_basic.py +388 -0
  42. neroued_3mf-0.2.0/src/builder.cpp +234 -0
  43. neroued_3mf-0.2.0/src/internal/omp_config.h +18 -0
  44. neroued_3mf-0.2.0/src/internal/opc_types.h +24 -0
  45. neroued_3mf-0.2.0/src/internal/validate.h +163 -0
  46. neroued_3mf-0.2.0/src/internal/xml_stream_buffer.h +90 -0
  47. neroued_3mf-0.2.0/src/internal/xml_util.h +80 -0
  48. neroued_3mf-0.2.0/src/opc.cpp +311 -0
  49. neroued_3mf-0.2.0/src/opc.h +400 -0
  50. neroued_3mf-0.2.0/src/types.cpp +233 -0
  51. neroued_3mf-0.2.0/src/writer.cpp +204 -0
  52. neroued_3mf-0.2.0/src/zip.cpp +607 -0
  53. neroued_3mf-0.2.0/src/zip.h +41 -0
  54. neroued_3mf-0.2.0/tests/CMakeLists.txt +20 -0
  55. neroued_3mf-0.2.0/tests/test_builder.cpp +562 -0
  56. neroued_3mf-0.2.0/tests/test_types.cpp +162 -0
  57. neroued_3mf-0.2.0/tests/test_writer.cpp +607 -0
@@ -0,0 +1,17 @@
1
+ BasedOnStyle: LLVM
2
+ IndentWidth: 4
3
+ ColumnLimit: 100
4
+ AllowShortFunctionsOnASingleLine: Inline
5
+ AllowShortIfStatementsOnASingleLine: AllIfsAndElse
6
+ AllowShortLoopsOnASingleLine: true
7
+ AllowShortBlocksOnASingleLine: Always
8
+ BreakBeforeBraces: Attach
9
+ SortIncludes: CaseInsensitive
10
+ IncludeBlocks: Regroup
11
+ IncludeCategories:
12
+ - Regex: '^"neroued/'
13
+ Priority: 1
14
+ - Regex: '^"'
15
+ Priority: 2
16
+ - Regex: '^<'
17
+ Priority: 3
@@ -0,0 +1,52 @@
1
+ #!/bin/bash
2
+ # beforeShellExecution hook: block destructive commands
3
+
4
+ input=$(cat)
5
+ command=$(echo "$input" | python3 -c "import sys,json; print(json.load(sys.stdin).get('command',''))" 2>/dev/null)
6
+
7
+ [ -z "$command" ] && { echo '{"permission":"allow"}'; exit 0; }
8
+
9
+ deny_with() {
10
+ cat <<EOF
11
+ {"permission":"deny","user_message":"$1","agent_message":"$1 请使用更安全的替代方案。"}
12
+ EOF
13
+ exit 0
14
+ }
15
+
16
+ ask_with() {
17
+ cat <<EOF
18
+ {"permission":"ask","user_message":"$1"}
19
+ EOF
20
+ exit 0
21
+ }
22
+
23
+ # --- hard block ---
24
+
25
+ if echo "$command" | grep -qE 'rm\s+(-[^ ]*)?r[^ ]*f[^ ]*\s+/\s*$|rm\s+(-[^ ]*)?r[^ ]*f[^ ]*\s+/\*'; then
26
+ deny_with "已拦截:递归删除根文件系统"
27
+ fi
28
+
29
+ if echo "$command" | grep -qE 'git\s+push\s+.*--force.*\s+(origin\s+)?(master|main)\b|git\s+push\s+-f\s+.*\s+(origin\s+)?(master|main)\b'; then
30
+ deny_with "已拦截:禁止 force push 到 master/main"
31
+ fi
32
+
33
+ if echo "$command" | grep -qE 'mkfs\.|>\s*/dev/sd|:\(\)\{|fork\s*bomb'; then
34
+ deny_with "已拦截:潜在的破坏性系统命令"
35
+ fi
36
+
37
+ if echo "$command" | grep -qE 'dd\s+.*of=/dev/sd'; then
38
+ deny_with "已拦截:直接写入块设备"
39
+ fi
40
+
41
+ # --- ask confirmation ---
42
+
43
+ if echo "$command" | grep -qE 'git\s+reset\s+--hard'; then
44
+ ask_with "git reset --hard 将丢弃所有未提交的更改,是否继续?"
45
+ fi
46
+
47
+ if echo "$command" | grep -qE 'git\s+clean\s+-[^ ]*f'; then
48
+ ask_with "git clean -f 将删除未跟踪的文件,是否继续?"
49
+ fi
50
+
51
+ echo '{"permission":"allow"}'
52
+ exit 0
@@ -0,0 +1,45 @@
1
+ #!/bin/bash
2
+ # stop hook: remind to sync docs when API/build files changed but docs weren't
3
+
4
+ input=$(cat)
5
+ status=$(echo "$input" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status',''))" 2>/dev/null)
6
+
7
+ [ "$status" != "completed" ] && { echo '{}'; exit 0; }
8
+
9
+ project_dir="${CURSOR_PROJECT_DIR:-$(pwd)}"
10
+ cd "$project_dir" || { echo '{}'; exit 0; }
11
+
12
+ changed=$(git diff --name-only HEAD 2>/dev/null; git diff --cached --name-only 2>/dev/null)
13
+ [ -z "$changed" ] && { echo '{}'; exit 0; }
14
+
15
+ needs_docs=false
16
+
17
+ if echo "$changed" | grep -qE '(include/.*\.(h|hpp))'; then
18
+ needs_docs=true
19
+ fi
20
+ if echo "$changed" | grep -qE '(src/.*\.(cpp|h|hpp))'; then
21
+ needs_docs=true
22
+ fi
23
+ if echo "$changed" | grep -qE '(CMakeLists\.txt|cmake/)'; then
24
+ needs_docs=true
25
+ fi
26
+
27
+ if [ "$needs_docs" = false ]; then
28
+ echo '{}'
29
+ exit 0
30
+ fi
31
+
32
+ docs_updated=false
33
+ if echo "$changed" | grep -qE '(^docs/|^README\.md|^AGENTS\.md)'; then
34
+ docs_updated=true
35
+ fi
36
+
37
+ if [ "$docs_updated" = false ]; then
38
+ cat <<'EOF'
39
+ {"followup_message":"检测到公共头文件、实现代码或构建配置有变更,但 docs/ 和 README.md 未同步更新。请检查是否需要更新文档(参考 .cursor/rules/sync-docs.mdc 中的触发条件)。如果本次变更不涉及用户可见 API 或构建选项,可以忽略此提醒。"}
40
+ EOF
41
+ else
42
+ echo '{}'
43
+ fi
44
+
45
+ exit 0
@@ -0,0 +1,18 @@
1
+ #!/bin/bash
2
+ # afterFileEdit hook: auto-format C++ files with clang-format
3
+
4
+ input=$(cat)
5
+ file_path=$(echo "$input" | python3 -c "import sys,json; print(json.load(sys.stdin).get('file_path',''))" 2>/dev/null)
6
+
7
+ [ -z "$file_path" ] && exit 0
8
+ [ ! -f "$file_path" ] && exit 0
9
+
10
+ case "$file_path" in
11
+ *.cpp|*.h|*.hpp|*.cc|*.cxx)
12
+ if command -v clang-format &>/dev/null; then
13
+ clang-format -i "$file_path" 2>/dev/null
14
+ fi
15
+ ;;
16
+ esac
17
+
18
+ exit 0
@@ -0,0 +1,43 @@
1
+ #!/bin/bash
2
+ # beforeReadFile hook: block reading sensitive files
3
+
4
+ input=$(cat)
5
+ file_path=$(echo "$input" | python3 -c "import sys,json; print(json.load(sys.stdin).get('file_path',''))" 2>/dev/null)
6
+
7
+ [ -z "$file_path" ] && { echo '{"permission":"allow"}'; exit 0; }
8
+
9
+ filename=$(basename "$file_path")
10
+
11
+ deny_with() {
12
+ cat <<EOF
13
+ {"permission":"deny","user_message":"已阻止读取敏感文件: $filename — $1"}
14
+ EOF
15
+ exit 0
16
+ }
17
+
18
+ case "$filename" in
19
+ .env|.env.local|.env.production|.env.staging)
20
+ deny_with "环境变量文件可能包含密钥"
21
+ ;;
22
+ .env.*.local)
23
+ deny_with "本地环境变量文件可能包含密钥"
24
+ ;;
25
+ credentials.json|service-account*.json)
26
+ deny_with "凭据文件"
27
+ ;;
28
+ id_rsa|id_ed25519|id_ecdsa|*.pem)
29
+ deny_with "私钥文件"
30
+ ;;
31
+ .git-credentials|.netrc)
32
+ deny_with "Git 凭据文件"
33
+ ;;
34
+ esac
35
+
36
+ case "$file_path" in
37
+ */.ssh/*)
38
+ deny_with "SSH 目录中的文件"
39
+ ;;
40
+ esac
41
+
42
+ echo '{"permission":"allow"}'
43
+ exit 0
@@ -0,0 +1,29 @@
1
+ {
2
+ "version": 1,
3
+ "hooks": {
4
+ "afterFileEdit": [
5
+ {
6
+ "command": ".cursor/hooks/format-cpp.sh"
7
+ }
8
+ ],
9
+ "beforeShellExecution": [
10
+ {
11
+ "command": ".cursor/hooks/block-dangerous.sh",
12
+ "timeout": 5
13
+ }
14
+ ],
15
+ "beforeReadFile": [
16
+ {
17
+ "command": ".cursor/hooks/protect-secrets.sh",
18
+ "timeout": 5
19
+ }
20
+ ],
21
+ "stop": [
22
+ {
23
+ "command": ".cursor/hooks/check-docs-sync.sh",
24
+ "timeout": 15,
25
+ "loop_limit": 1
26
+ }
27
+ ]
28
+ }
29
+ }
@@ -0,0 +1,25 @@
1
+ ---
2
+ description: 工具函数复用与实现结构规范
3
+ globs: "**/*.cpp,**/*.h"
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # 工具函数复用与实现结构
8
+
9
+ ## 工具函数复用
10
+
11
+ - 禁止重复编写语义相同的工具函数。
12
+ - 新增工具函数前,先检索项目内是否已有可复用实现。
13
+ - 跨模块复用的函数应放入 `src/internal/` 目录下的内部头文件。
14
+ - 仅当前文件使用的工具函数应保留为匿名命名空间局部实现。
15
+
16
+ ## .cpp 文件结构
17
+
18
+ - 避免在 .cpp 内做非必要前向声明;优先通过合理的函数定义顺序解决依赖。
19
+ - 实现文件应按"工具函数 → 核心流程 → 对外接口"组织。
20
+
21
+ ## 命名空间约定
22
+
23
+ - 公共 API 使用 `neroued_3mf` 命名空间。
24
+ - 内部实现使用 `neroued_3mf::detail` 命名空间。
25
+ - 公共头文件位于 `include/neroued/3mf/`,内部头文件位于 `src/` 及 `src/internal/`。
@@ -0,0 +1,17 @@
1
+ ---
2
+ description: C++ 代码格式化规范
3
+ globs: "**/*.cpp,**/*.h,**/*.hpp,**/*.cc,**/*.cxx"
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # C++ 代码格式化
8
+
9
+ 每次修改 `.cpp`、`.h`、`.hpp`、`.cc`、`.cxx` 文件后,必须使用项目根目录的 `.clang-format` 配置对修改的文件运行格式化:
10
+
11
+ ```bash
12
+ clang-format -i <modified-files>
13
+ ```
14
+
15
+ - 仅对本次修改过的文件执行,不要全量格式化
16
+ - 在所有编辑完成后统一执行一次即可,无需每次编辑后都执行
17
+ - 格式化风格基于 LLVM,缩进 4 空格,列宽限制 100
@@ -0,0 +1,27 @@
1
+ ---
2
+ description: C++ 跨平台编译规范
3
+ globs: "**/*.cpp,**/*.h,**/*.hpp,**/CMakeLists.txt,**/*.cmake"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # C++ 跨平台编译规范
8
+
9
+ ## 文件系统路径
10
+
11
+ 禁止硬编码 POSIX 路径,一律使用 `std::filesystem`(C++17)。
12
+
13
+ ## 随机数 / ID 生成
14
+
15
+ 禁止直接读取 `/dev/urandom`,使用 `std::random_device`。
16
+
17
+ ## CMake 外部库链接
18
+
19
+ 禁止硬编码 Linux 特有的库名,使用 find_package 或条件分支。
20
+
21
+ ## 平台宏判断
22
+
23
+ 需要平台差异时,使用标准宏:`_WIN32`、`__APPLE__`。
24
+
25
+ ## 变更检查
26
+
27
+ 每次新增系统调用或文件操作时,必须确认跨平台兼容性。
@@ -0,0 +1,11 @@
1
+ ---
2
+ description: Git 提交与合并规范
3
+ globs: "**/*"
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # Git 提交与合并规范
8
+
9
+ - 禁止在 master/main 分支直接提交代码并推送。
10
+ - 所有代码改动必须在独立分支完成,并通过 Pull Request 合并。
11
+ - 分支命名:feat/<topic>、fix/<topic>、refactor/<topic>、docs/<topic>、chore/<topic>
@@ -0,0 +1,17 @@
1
+ ---
2
+ description: 文档同步规范
3
+ globs: "**/*"
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # 文档同步
8
+
9
+ 当修改涉及以下内容时,检查对应文档是否需要同步更新:
10
+
11
+ - 公共 API 变更(头文件增删、函数签名变化)→ `docs/API.md`、`AGENTS.md`
12
+ - Document 模型变更(字段增删、校验规则变化)→ `docs/DESIGN.md`
13
+ - 配置参数增删(WriteOptions 等)→ `docs/BUILDING.md`
14
+ - 构建选项变化(CMake 选项、依赖变化)→ `docs/BUILDING.md`
15
+ - 用法示例变更 → `docs/EXAMPLES.md`
16
+ - 仓库结构变化(新增/删除/重命名文件或目录)→ `AGENTS.md`
17
+ - 核心亮点或定位变更 → `README.md`
@@ -0,0 +1,230 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+ workflow_dispatch:
9
+
10
+ concurrency:
11
+ group: ci-${{ github.event.pull_request.number || github.sha }}
12
+ cancel-in-progress: true
13
+
14
+ env:
15
+ WIN_VCPKG_ROOT: C:/vcpkg
16
+ WIN_VCPKG_TRIPLET: x64-windows
17
+
18
+ jobs:
19
+ # ── C++ format check (changed files only) ─────────────────────────────────
20
+ format-check:
21
+ name: clang-format
22
+ runs-on: ubuntu-latest
23
+ if: github.event_name == 'pull_request'
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ with:
27
+ fetch-depth: 0
28
+
29
+ - name: Install clang-format-18
30
+ run: |
31
+ sudo apt-get update
32
+ sudo apt-get install -y --no-install-recommends clang-format-18
33
+
34
+ - name: Check formatting of changed files
35
+ run: |
36
+ BASE="${{ github.event.pull_request.base.sha }}"
37
+ FILES=$(git diff --name-only --diff-filter=ACM "$BASE" HEAD \
38
+ | grep -E '\.(cpp|h|hpp|cc|cxx)$' \
39
+ | grep -E '^(src|include|python|tests)/' || true)
40
+
41
+ if [ -z "$FILES" ]; then
42
+ echo "No C++ files changed, skipping."
43
+ exit 0
44
+ fi
45
+
46
+ echo "Checking formatting for:"
47
+ echo "$FILES"
48
+ FAILED=0
49
+ for f in $FILES; do
50
+ if ! clang-format-18 --dry-run --Werror "$f" 2>/dev/null; then
51
+ echo "::error file=$f::Format mismatch. Run: clang-format -i $f"
52
+ FAILED=1
53
+ fi
54
+ done
55
+
56
+ if [ "$FAILED" -eq 1 ]; then
57
+ echo "::error::Some files need formatting."
58
+ exit 1
59
+ fi
60
+ echo "All changed C++ files are correctly formatted."
61
+
62
+ # ── C++ build & test ──────────────────────────────────────────────────────
63
+ cpp-build:
64
+ name: C++ (${{ matrix.os }})
65
+ runs-on: ${{ matrix.os }}
66
+ strategy:
67
+ fail-fast: false
68
+ matrix:
69
+ os: [ubuntu-22.04, macos-14, windows-latest]
70
+
71
+ steps:
72
+ - uses: actions/checkout@v4
73
+
74
+ # ── Linux ─────────────────────────────────────────────────────────────
75
+ - name: Install dependencies (Linux)
76
+ if: runner.os == 'Linux'
77
+ run: |
78
+ sudo apt-get update
79
+ sudo apt-get install -y --no-install-recommends zlib1g-dev ninja-build ccache
80
+ mkdir -p ~/.cache/ccache
81
+
82
+ - name: Cache ccache (Linux)
83
+ if: runner.os == 'Linux'
84
+ uses: actions/cache@v4
85
+ with:
86
+ path: ~/.cache/ccache
87
+ key: ccache-linux-${{ hashFiles('CMakeLists.txt') }}
88
+ restore-keys: ccache-linux-
89
+
90
+ - name: Configure (Linux)
91
+ if: runner.os == 'Linux'
92
+ env:
93
+ CMAKE_C_COMPILER_LAUNCHER: ccache
94
+ CMAKE_CXX_COMPILER_LAUNCHER: ccache
95
+ run: |
96
+ ccache --set-config=max_size=500M
97
+ ccache -z
98
+ cmake -S . -B build -G Ninja \
99
+ -DCMAKE_BUILD_TYPE=Release \
100
+ -DN3MF_BUILD_TESTS=ON
101
+
102
+ # ── macOS ─────────────────────────────────────────────────────────────
103
+ - name: Install dependencies (macOS)
104
+ if: runner.os == 'macOS'
105
+ run: brew install ninja ccache libomp
106
+
107
+ - name: Cache ccache (macOS)
108
+ if: runner.os == 'macOS'
109
+ uses: actions/cache@v4
110
+ with:
111
+ path: ~/Library/Caches/ccache
112
+ key: ccache-macos-${{ hashFiles('CMakeLists.txt') }}
113
+ restore-keys: ccache-macos-
114
+
115
+ - name: Configure (macOS)
116
+ if: runner.os == 'macOS'
117
+ env:
118
+ CMAKE_C_COMPILER_LAUNCHER: ccache
119
+ CMAKE_CXX_COMPILER_LAUNCHER: ccache
120
+ run: |
121
+ ccache --set-config=max_size=500M
122
+ ccache -z
123
+ cmake -S . -B build -G Ninja \
124
+ -DCMAKE_BUILD_TYPE=Release \
125
+ -DN3MF_BUILD_TESTS=ON \
126
+ -DOpenMP_ROOT=$(brew --prefix libomp)
127
+
128
+ # ── Windows ───────────────────────────────────────────────────────────
129
+ - name: Cache vcpkg packages (Windows)
130
+ if: runner.os == 'Windows'
131
+ uses: actions/cache@v4
132
+ with:
133
+ path: ${{ env.WIN_VCPKG_ROOT }}/installed
134
+ key: vcpkg-win-zlib-${{ runner.os }}
135
+ restore-keys: vcpkg-win-zlib-
136
+
137
+ - name: Install dependencies (Windows)
138
+ if: runner.os == 'Windows'
139
+ run: vcpkg install zlib:${{ env.WIN_VCPKG_TRIPLET }}
140
+
141
+ - uses: ilammy/msvc-dev-cmd@v1
142
+ if: runner.os == 'Windows'
143
+
144
+ - name: Configure (Windows)
145
+ if: runner.os == 'Windows'
146
+ run: >
147
+ cmake -S . -B build -G Ninja
148
+ -DCMAKE_TOOLCHAIN_FILE="${{ env.WIN_VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake"
149
+ -DVCPKG_TARGET_TRIPLET=${{ env.WIN_VCPKG_TRIPLET }}
150
+ -DCMAKE_BUILD_TYPE=Release
151
+ -DN3MF_BUILD_TESTS=ON
152
+
153
+ # ── Build & test ──────────────────────────────────────────────────────
154
+ - name: Build
155
+ run: cmake --build build --config Release -j4
156
+
157
+ - name: Test
158
+ run: ctest --test-dir build --build-config Release --output-on-failure
159
+
160
+ - name: ccache stats
161
+ if: always() && runner.os != 'Windows'
162
+ run: ccache -s
163
+
164
+ # ── Python bindings build & test ──────────────────────────────────────────
165
+ python-test:
166
+ name: Python ${{ matrix.python-version }} (${{ matrix.os }})
167
+ runs-on: ${{ matrix.os }}
168
+ strategy:
169
+ fail-fast: false
170
+ matrix:
171
+ os: [ubuntu-22.04, macos-14, windows-latest]
172
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
173
+
174
+ steps:
175
+ - uses: actions/checkout@v4
176
+ with:
177
+ fetch-depth: 0
178
+
179
+ - name: Install system dependencies (Linux)
180
+ if: runner.os == 'Linux'
181
+ run: |
182
+ sudo apt-get update
183
+ sudo apt-get install -y --no-install-recommends zlib1g-dev
184
+
185
+ - name: Install system dependencies (macOS)
186
+ if: runner.os == 'macOS'
187
+ run: brew install libomp
188
+
189
+ - name: Cache vcpkg packages (Windows)
190
+ if: runner.os == 'Windows'
191
+ uses: actions/cache@v4
192
+ with:
193
+ path: ${{ env.WIN_VCPKG_ROOT }}/installed
194
+ key: vcpkg-win-zlib-${{ runner.os }}
195
+ restore-keys: vcpkg-win-zlib-
196
+
197
+ - name: Install system dependencies (Windows)
198
+ if: runner.os == 'Windows'
199
+ run: vcpkg install zlib:${{ env.WIN_VCPKG_TRIPLET }}
200
+
201
+ - uses: ilammy/msvc-dev-cmd@v1
202
+ if: runner.os == 'Windows'
203
+
204
+ - uses: actions/setup-python@v5
205
+ with:
206
+ python-version: ${{ matrix.python-version }}
207
+
208
+ - name: Install package (Linux)
209
+ if: runner.os == 'Linux'
210
+ run: pip install --verbose .
211
+
212
+ - name: Install package (macOS)
213
+ if: runner.os == 'macOS'
214
+ run: |
215
+ export SKBUILD_CMAKE_DEFINE="OpenMP_ROOT=$(brew --prefix libomp)"
216
+ pip install --verbose .
217
+
218
+ - name: Install package (Windows)
219
+ if: runner.os == 'Windows'
220
+ run: pip install --verbose .
221
+ env:
222
+ CMAKE_TOOLCHAIN_FILE: ${{ env.WIN_VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake
223
+ SKBUILD_CMAKE_DEFINE: "VCPKG_TARGET_TRIPLET=${{ env.WIN_VCPKG_TRIPLET }}"
224
+
225
+ - name: Run tests
226
+ run: |
227
+ pip install pytest
228
+ pytest python/tests -v
229
+ env:
230
+ N3MF_DLL_DIR: ${{ runner.os == 'Windows' && format('{0}/installed/{1}/bin', env.WIN_VCPKG_ROOT, env.WIN_VCPKG_TRIPLET) || '' }}