无依赖包的语义版本比较与精准标记方案问询
版本分类标记解决方案需求
原始DataFrame结构
api_spec_id label info_version commitDate 803 2.3.0 2019-09-12 803 2.4.1 2019-10-04 803 2.4.2 2019-10-07 803 2.5.3 2019-10-08 803 2.6.1 2019-10-08 803 2.6.3 2019-11-25 803 2.6.5 2019-12-10 803 2.6.6 2019-12-11 803 2.7.2 2019-12-11 803 2.8.0 2019-12-19
现有工具局限与特殊需求
使用packaging.Version仅能标记单一版本段变更(如major、minor),但数据集存在以下特殊场景,需要更精准的分类:
- 部分版本升级同时变更多个版本段(如2.5.3 → 2.6.1),单一标签会影响分析准确性
- 存在Major.Minor与Patch同时变更的场景(如2.3.0 → 2.4.1)
- 预发布版本处理:当major.minor.patch完全相同时,需按
alpha < beta < rc < pre < dev规则比较;标识符相同时,比较后续数字 - 四位版本(如1.2.6.7)需将第四位归为micro类别
- 版本完全相同时标记为
no change
预期输出
api_spec_id label info_version commitDate 803 - 2.3.0 2019-09-12 803 minor.patch 2.4.1 2019-10-04 803 patch 2.4.2 2019-10-07 803 minor.patch 2.5.3 2019-10-08 803 minor.patch 2.6.1 2019-10-08 803 patch 2.6.3 2019-11-25 803 patch 2.6.5 2019-12-10 803 patch 2.6.6 2019-12-11 803 minor.patch 2.7.2 2019-12-11 803 major 2.8.0 2019-12-19 803 pre 2.8.0a1 2019-12-24 803 pre 2.8.0a2 2019-12-27 803 pre 2.9.0.dev 2021-01-03 803 micro 2.9.0.2 2021-01-10 803 no change 2.9.0.2 2021-01-15
解决方案建议
1. 自定义版本解析函数
基于PEP440规范扩展解析逻辑,将版本字符串转换为结构化数据:
- 对四位版本(如
2.9.0.2),拆分出major=2, minor=9, patch=0, micro=2 - 对预发布版本(如
2.8.0a1),提取预发布类型(alpha/a)和数字(1),并映射为权重值(alpha=0, beta=1, rc=2, pre=3, dev=4),方便比较
2. 逐组逐行对比版本差异
- 按
api_spec_id分组,每组内按commitDate排序,确保版本顺序符合时间线 - 使用
pandas.Series.shift()获取前一个版本,逐行对比当前版本与前版本的各字段:- 若major不同:标记
major - 若major相同,minor不同:检查patch是否变化,同时变化则标记
minor.patch,仅minor变化则标记minor - 若major+minor相同,patch不同:标记
patch - 若前三项相同,micro不同:标记
micro - 若前四项相同,预发布信息不同:标记
pre - 所有字段完全相同:标记
no change - 组内第一行版本标记为
-
- 若major不同:标记
3. 结合packaging.Version简化基础解析
先用packaging.Version解析基础的major、minor、patch字段,再补充自定义逻辑处理四位版本的micro字段和预发布标识符的权重映射,减少重复开发。
4. 代码示例框架
import pandas as pd from packaging import Version # 预发布类型权重映射 PRE_RELEASE_WEIGHT = { 'alpha': 0, 'a': 0, 'beta': 1, 'b': 1, 'rc': 2, 'pre': 3, 'dev': 4 } def parse_version(version_str): """自定义版本解析,返回结构化字典""" try: ver = Version(version_str) parsed = { 'major': ver.major, 'minor': ver.minor, 'patch': ver.micro if ver.micro is not None else 0, 'micro': 0, 'pre_type': None, 'pre_num': 0, 'pre_weight': -1 } # 处理四位版本(如2.9.0.2) if len(version_str.split('.')) == 4: parts = version_str.split('.') parsed['patch'] = int(parts[2]) parsed['micro'] = int(parts[3]) # 处理预发布版本 if ver.pre: pre_type, pre_num = ver.pre parsed['pre_type'] = pre_type parsed['pre_num'] = pre_num parsed['pre_weight'] = PRE_RELEASE_WEIGHT.get(pre_type, -1) return parsed except: # 处理非标准版本,可根据需求调整 return None def get_version_change_label(current, prev): """对比两个解析后的版本,返回变更标签""" if prev is None: return '-' # 比较major if current['major'] != prev['major']: return 'major' # 比较minor if current['minor'] != prev['minor']: if current['patch'] != prev['patch']: return 'minor.patch' return 'minor' # 比较patch if current['patch'] != prev['patch']: return 'patch' # 比较micro if current['micro'] != prev['micro']: return 'micro' # 比较预发布版本 if current['pre_weight'] != prev['pre_weight'] or current['pre_num'] != prev['pre_num']: return 'pre' # 无变化 return 'no change' # 加载数据 df = pd.read_csv('your_data.csv') # 替换为实际数据加载方式 # 解析版本 df['parsed_version'] = df['info_version'].apply(parse_version) # 分组排序 df = df.sort_values(['api_spec_id', 'commitDate']) # 获取前一个版本的解析结果 df['prev_parsed_version'] = df.groupby('api_spec_id')['parsed_version'].shift(1) # 生成标签 df['label'] = df.apply(lambda row: get_version_change_label(row['parsed_version'], row['prev_parsed_version']), axis=1) # 整理输出 df = df[['api_spec_id', 'label', 'info_version', 'commitDate']] print(df.to_string(index=False))
内容的提问来源于stack exchange,提问作者Brie MerryWeather
相关产品推荐
相关产品推荐

