netCDF数据合规检查:compliance-checker安装与pytest自动化实践
2026/9/15 5:45:44 网站建设 项目流程

简介:这是一份用于数据合规性检查的Python第三方库 compliance-checker 4.3.1 官方源码包,主要面向处理 netCDF/CF 数据的科研人员、数据归档与共享平台管理员,解决数据集规范化校验和互操作性问题。压缩包共204个文件,以.cdl元数据模板、.nc示例数据、.py核心库代码和.txt说明文档为主,并有少量配置模板、许可证与版本信息文件,整体仅539KB,便于快速下载和离线部署。其中.cdl与.nc样例覆盖了自引用维度、有效坐标、NCEI模板等典型场景,可作为学习检验规则的活教材。当前已有106人学习下载。借助源码和配套用例,读者既能掌握该库的插件化校验机制,也可学会编写自定义检查器,并对照实际数据排查维度、坐标与元数据方面的合规性问题,是提升数据发布质量、推进数据标准化的实用工具资源。

1. compliance-checker 不是校验器,而是合规审核框架

拿到compliance-checker-4.3.1.tar.gz这个源码包,第一反应当然是解压、安装、跑一个 demo。但等你真正执行过一次compliance-checker命令,会发现它和你想象的“数据校验”不太一样:它不会告诉你某个温度值是不是超出了物理范围,也不会抓取缺失的观测时间戳,而是逐条核对你的 netCDF 文件是否满足某套元数据约定——比如 CF 公约、ACDD 属性、IOOS 模板、NCEI 档案规范。换句话说,它是在回答“这个数据文件交给别人之前,声明、维度、坐标、全局属性有没有按行业规范写好”,而不是“这份数据科学上是否正确”。

对于做环境、海洋、气象数据发布或归档的工程师,这个库的价值在于把人工 review 变成可重复的命令行检查。你不需要通读几十页标准文档,只需把.nc文件交给它,就能拿到一份带优先级的问题清单,指出哪个变量缺units、哪个全局属性少了history、哪个坐标变量没有绑定维度。本文用4.3.1源码包为对象,从tar.gz解压开始,讲到把.cdl测试样本变成真实数据并完成一次合规检查,最后给出接入 pytest 的落地方案,适合刚接触 netCDF 数据治理的 Python 工程师阅读。

2. tar.gz 解压与安装:从源码包到 CLI 命令

2.1 先看包结构:tar.gz 里不止有 Python 代码

先用一条命令把源码包内容列出来,而不是直接解压。这一步能让你在tar报错之前就确认包是否完整、是否需要 root 权限、总共有多少个文件。常见做法是使用tar -tzfz表示通过 gzip 解压读取,t只列出清单不展开,f指定文件。

tar -tzf compliance-checker-4.3.1.tar.gz | head -n 30

执行后会看到类似compliance-checker-4.3.1/setup.pycompliance-checker-4.3.1/README.mdcompliance-checker-4.3.1/compliance_checker/这样的路径。注意这里head -n 30只截取了前 30 行,目的是快速了解顶层目录,避免包内文件特别多时刷屏。如果你所在环境没有head,直接去掉管道符执行即可。

-t-z这两个参数的组合很容易被新手忽略:-z告诉tar解开的是 gzip 压缩流,少了它,命令会直接尝试把二进制压缩包当普通归档处理,最终报出Cannot open: No such file or directoryNot found in archive。严格地说,兼容性较好的写法是tar -xzf,但先列清单时用-tzf更安全。

2.2 解压异常处理:文件缺失与权限问题

确认包内容后,真正解压并进入目录:

tar -xzf compliance-checker-4.3.1.tar.gz cd compliance-checker-4.3.1

这里x代表 extract。如果是在 Windows 上使用 VSCode 的终端,建议打开 Git Bash 再执行,避免 PowerShell 下tar参数解析行为不一致。解压常见失败有两类:第一,当前目录没有该文件,报tar: compliance-checker-4.3.1.tar.gz: Cannot open: No such file or directory,这时先用ls -l确认文件名是否被下载成了类似compliance-checker-4.3.1.tar.gz.1的后缀;第二,目录没有写权限,报Cannot mkdir: Permission denied,这种情况多半发生在/usr/local或系统目录下,解决办法不是直接sudo tar,而是先把包拷贝到用户目录再解压。

解压完成后的第一件事不是安装,而是检查准备工作。4.3.1 要求 Python 3.8 及以上,你可以用python --versionwhich python确认当前解释器路径,避免和系统自带的 Python 混在一起。若你是在一套刚配置好的 python 环境里操作,强烈建议走下面的虚拟环境流程,而不是直接用pip install .装到全局 site-packages。

2.3 虚拟环境安装与依赖落位

源码包安装与 PyPI 安装本质不同:pip install .会重新执行setup.py解析依赖,而pip install compliance-checker==4.3.1直接安装已构建好的 wheel。源码包的优势在于你可以提前查看 setup 依赖声明,缺点是遇到编译依赖时容易失败。我一般会先建虚拟环境,再源码安装:

python -m venv venv source venv/bin/activate pip install --upgrade pip pip install -r requirements-dev.txt 2>/dev/null || true pip install .

最后pip install .会把compliance-checker的可执行文件放进venv/bin/下。安装完成后验证版本:

compliance-checker --version

如果命令找不到,检查当前 shell 是否真的激活了 venv,以及compliance-checker是否被安装到了~/.local/bin。下表整理了三种常见安装方式的适用场景:

安装方式命令适用场景
源码当前目录安装pip install .需要调试或修改库代码
PyPI 全球安装pip install compliance-checker==4.3.1仅需 CLI 使用,不关心源码
国内镜像源安装pip install compliance-checker==4.3.1 -i https://pypi.tuna.tsinghua.edu.cn/simple服务器下载慢或超时

安装过程中最容易出现的坑是cftimenetCDF4等底层库二进制不匹配。看到Failed building wheel for cftime时,先升级 pip 和 setuptools,再单独预装pip install cftime netCDF4 numpy,最后回到源码包执行pip install .。这条顺序能省掉大量排查时间。

3. 跑一次合规检查:核心参数与报告输出

3.1 标准检查器与检查流程

Compliance Checker 的可执行文件名字虽然叫compliance-checker,内部却不是一个单一检查器,而是一组按标准划分的插件。4.3.1 版本常见的有acddcfnceiioos,以及针对具体档案模板的ncei-profilencei-point等。每个插件对应一套检查项,比如cf检查 1.7/1.8 公约中关于axisstandard_namecoordinates的约定;acdd关注数据集发现层面的属性,如titlesummaryinstitutiongeospatial_bounds

先列出当前环境支持哪些检查器,再决定用哪一套标准:

compliance-checker --listers

命令输出会以列表形式展示测试名称。注意有些版本也支持--list,但--listers更接近内部命名。这一步的价值在于,不同发行版编译选项会导致可用标准数量不同,如果你后续在 CI 里写死了-t ncei,而当前环境没有该检查器,整个命令会直接退出码为 1。因此第一次运行使用--listers摸底是必须的。

3.2 命令行检查一个 netCDF 数据集

现在假设你手上有一个真实采集文件sst_2016.nc,想按 CF 公约做一遍检查。最直接的命令如下:

compliance-checker -t cf -f html -o report.html sst_2016.nc

-t指定检查器名称,可以重复出现,例如-t cf -t acdd表示同时跑两个标准;-f指定输出格式,支持texthtmljson,多数人第一次用会遗漏-o,默认输出到标准输出而不是文件;-o report.html把结果写入命名文件。命令执行后,终端只会显示检查进程和最终优先级统计,完整问题列表落在report.html里。

如果你偏好纯文本输出,使用-f text并抓取Priority标记行:

compliance-checker -t cf -f text sst_2016.nc 2>/dev/null | head -n 40

这里的2>/dev/null是为了屏蔽底层 netCDF 库的告警日志。输出中你会看到若干形如[Severity: HIGH]的行,前面跟着具体检查项说明。高优先级通常代表变量名、维度缺失等会导致工具无法正确读取数据的问题;低优先级多为建议性属性补齐。实际项目里,我会先处理 HIGH,再集中看 MEDIUM,LOW 级别除非发布对外共享数据,否则可以延后。

3.3 常用参数速查表

下表是我整理的一份常用运行参数清单,后续写自动化脚本时可以对照抄:

参数含义示例
-t选择检查器-t cf -t acdd
-f输出格式-f json
-o输出文件名-o result.json
-v增加日志级别-v显示 debug 信息
-l只列出检查器并退出--listers
-a指定检查替代模式-a t限制为默认检查项

-v在排错时很有用。当你发现某条检查项一直不出现,用-v可以看到内部运行时是否跳过了某个数据集,原因往往是输入文件根本不是 netCDF 格式,或者扩展名是.nc但内部是 HDF4 结构。这类情况在气象行业尤其常见,拿到.ncfile sst_2016.nc确认格式再跑命令,能少走很多弯路。

一个容易混淆的概念是--limits参数。它用于调整检查失败阈值,比如--limits priority=2表示只报告优先级小于等于 2 的问题,也就是忽略 LOW 级建议。很多人以为这是“指定标准”,实际上标准还是要靠-t来选。这个参数在批量检测海量文件时价值很大,配合下面要讲的 CDL 样本集,可以快速识别哪些文件不满足关键约束。

4. CDL 样本与测试数据重构

4.1 CDL 是 netCDF 的文本表示

源码包里那十几个.cdl文件,比如valid_coordinates.cdlself_referencing.cdlncei_gold_point_1.cdl,不是数据文件,而是 netCDF 的文本描述格式 CDL(Common Data Language)。一个.nc文件用ncdump导出后得到的就是 CDL 文本;反过来,ncgen可以把.cdl生成二进制.nc文件。这组测试样本存在的意义,就是让使用者不需要手工构造数据,直接验证检查器对不同边界条件的响应。

先看其中一个文件的开头,理解 CDL 的结构:

head -n 25 ncei_gold_point_1.cdl

常见的 CDL 结构分为三部分:dimensions声明维度名和长度,variables声明变量类型、维度绑定和属性,末尾是data段直接写数值。ncgen解析时只要dimensionsvariables定义完整,就算data为空也能生成一个 size 为 0 的有效 netCDF 文件。

4.2 用 ncgen 生成 netCDF 数据

把包内所有.cdl批量转成.nc的常见做法是用 shell 循环:

for f in *.cdl; do ncgen -o "${f%.cdl}.nc" "$f" done

${f%.cdl}.nc是 Bash 参数扩展,去掉文件名的.cdl后缀再拼上.nc,等价于把valid_coordinates.cdl变成valid_coordinates.ncncgen -o指定输出文件名,不加-o时默认输出到标准输出,在终端里会直接打印二进制乱码,所以这个选项必须带上。如果系统提示ncgen: command not found,说明你没有安装 netCDF4 的命令行工具,conda install -c conda-forge netcdf4pip install netcdf4都能把它带进来。

生成成功后,用ncdump -h valid_coordinates.nc检查头信息,确认维度变量是否正常。接着跑一个快速检测:

compliance-checker -t cf -f json valid_coordinates.nc -o valid_coordinates_cf.json

因为valid_coordinates.cdl本身就是为了测试“坐标变量是否被正确声明”而设计的,这条命令正常情况下会报出若干与coordinates属性相关的问题。此时打开 json 文件,特别注意errors数组里每项的severitydescription字段。

4.3 从样本命名反推设计意图

源码包里每个.cdl文件对应一类边界场景。下表是我根据文件命名和 4.3.1 源码中测试用例推测的检查重点,实际使用时可以作为你自己的测试覆盖参考:

样本文件重点验证方向
valid_coordinates.cdl坐标变量是否满足建立坐标轴映射
self_referencing.cdl维度名引用自身时的容错处理
index_ragged.cdl索引方式存储的不规则数组
ncei_gold_point_1.cdlNCEI 单点观测模板最低属性集
20160919092000-ABOM-L3S_GHRSST-SSTfnd-AVHRR_D-1d_dn_truncate.cdl长时间序列的海表温度格点数据

以我个人的经验,self_referencing.cdl最容易让新手困惑。它里面的维度可能写成time = UNLIMITED,同时coordinates属性里包含time自身,这在 CDL 语义上不算错误,但是检查器要读懂它需要额外的解引用逻辑。当你用这类文件做回归测试时,不要期望所有检查都能通过,它的价值在于验证程序不会因循环引用而崩溃。理解这个设计后,你会明白这些内置样本更适合作为测试夹具,而不是“标准答案”。

5. 把合规检查接入 pytest 的一个折中方案

5.1 用 Python API 代替 shell 调用

在 CI 里直接调subprocess运行compliance-checker虽然简单,但每次启动都要加载全部检查器,速度慢。更合理的做法是在测试进程内使用 4.3.1 提供的 Python API。需要说明的是,4.x 的 API 与早期版本有差异,以下是常见的兼容写法:

from compliance_checker.runner import ComplianceChecker, CheckSuite check_suite = CheckSuite() check_suite.load_all_available_checkers()

load_all_available_checkers()会把当前环境注册过的全部检查器实例化。接下来用ComplianceChecker运行具体检查:

checker = ComplianceChecker( checker_names=["cf"], ds_loc="valid_coordinates.nc", verbose=True, criteria="normal", ) checker.run()

参数说明:checker_names接收一个字符串列表,对应命令行的-tds_loc是数据文件路径;verbose等价于命令行-vcriteria控制严格级别,可选strictnormallenientnormal会保留 HIGH 和 MEDIUM 级问题。run()执行后不会直接抛异常,而是把结果存在对象的raw_results属性里。

5.2 只保留关键错误,控制退出码

拿到原始结果后,可以按优先级过滤,再决定测试是否失败:

failures = [] for checker_name, result in checker.raw_results.items(): for severity in (0, 1): failures.extend(result[severity]) assert not failures, f"发现 {len(failures)} 个 HIGH/MEDIUM 问题"

这里result是一个按优先级分组的字典,0代表 HIGH,1代表 MEDIUM。实际使用中,我会把criteria="strict"留给归档环节,测试环境用normal更符合项目节奏,因为 strict 会把一些 LOW 级建议也算作失败,容易让团队疲于应付非关键属性。

5.3 用 pytest fixture 缓存数据集准备成本

最后提供一个与 pytest 结合的小技巧,避免每个测试用例都重新解析 nc 文件:

import pytest @pytest.fixture(scope="session") def dataset_path(tmp_path_factory): out = tmp_path_factory.mktemp("data") / "valid_coordinates.nc" subprocess.run(["ncgen", "-o", str(out), "valid_coordinates.cdl"], check=True) return out def test_cf_check_passes(dataset_path): checker = ComplianceChecker(checker_names=["cf"], ds_loc=str(dataset_path), verbose=False, criteria="normal") checker.run() assert len(checker.raw_results["cf"][2]) >= 0

tmp_path_factory是 pytest 内置的会话级临时目录,多个用例都使用同一个转换后的 nc 文件;ncgen只执行一次,检查多次,缩短整体测试时间。自定义参数数量较多时,建议封装一个run_check(nc_path, checker_names)函数,统一处理ComplianceChecker的构造和结果过滤,后续切换严格级别或增加-t acdd只需要改一处。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询