diff --git a/dpgen/auto_test/common_equi.py b/dpgen/auto_test/common_equi.py index f456be083..863fdbdbe 100644 --- a/dpgen/auto_test/common_equi.py +++ b/dpgen/auto_test/common_equi.py @@ -12,7 +12,7 @@ from dpgen.auto_test.calculator import make_calculator from dpgen.auto_test.mpdb import get_structure from dpgen.dispatcher.Dispatcher import make_dispatcher -from distutils.version import LooseVersion +from packaging.version import Version from dpgen.dispatcher.Dispatcher import make_submission from dpgen.remote.decide_machine import convert_mdata from dpgen.auto_test.lib.utils import create_path @@ -177,7 +177,7 @@ def run_equi(confs, print("%s --> Runing... " % (work_path)) api_version = mdata.get('api_version', '0.9') - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") disp = make_dispatcher(machine, resources, work_path, run_tasks, group_size) @@ -191,7 +191,7 @@ def run_equi(confs, backward_files, outlog='outlog', errlog='errlog') - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): submission = make_submission( mdata_machine=machine, diff --git a/dpgen/auto_test/common_prop.py b/dpgen/auto_test/common_prop.py index e0a3645e6..7a5f61930 100644 --- a/dpgen/auto_test/common_prop.py +++ b/dpgen/auto_test/common_prop.py @@ -1,4 +1,4 @@ -from distutils.version import LooseVersion +from packaging.version import Version import glob import os import warnings @@ -191,7 +191,7 @@ def worker(work_path, run_tasks = [os.path.basename(ii) for ii in all_task] machine, resources, command, group_size = util.get_machine_info(mdata, inter_type) api_version = mdata.get('api_version', '0.9') - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") disp = make_dispatcher(machine, resources, work_path, run_tasks, group_size) @@ -205,7 +205,7 @@ def worker(work_path, backward_files, outlog='outlog', errlog='errlog') - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): submission = make_submission( mdata_machine=machine, mdata_resources=resources, diff --git a/dpgen/auto_test/lib/lammps.py b/dpgen/auto_test/lib/lammps.py index a47fcfeb6..7cbbb0c1b 100644 --- a/dpgen/auto_test/lib/lammps.py +++ b/dpgen/auto_test/lib/lammps.py @@ -4,7 +4,7 @@ import dpdata import subprocess as sp import dpgen.auto_test.lib.util as util -from distutils.version import LooseVersion +from packaging.version import Version from dpdata.periodic_table import Element @@ -103,7 +103,7 @@ def inter_deepmd(param): model_list = "" for ii in models: model_list += ii + " " - if LooseVersion(deepmd_version) < LooseVersion('1'): + if Version(deepmd_version) < Version('1'): ## DeePMD-kit version == 0.x if len(models) > 1: ret += '%s 10 model_devi.out\n' % model_list diff --git a/dpgen/data/gen.py b/dpgen/data/gen.py index c64eb4703..952090793 100644 --- a/dpgen/data/gen.py +++ b/dpgen/data/gen.py @@ -20,7 +20,7 @@ import dpgen.data.tools.bcc as bcc import dpgen.data.tools.diamond as diamond import dpgen.data.tools.sc as sc -from distutils.version import LooseVersion +from packaging.version import Version from dpgen.generator.lib.vasp import incar_upper from dpgen.generator.lib.utils import symlink_user_forward_files from dpgen.generator.lib.abacus_scf import get_abacus_input_parameters, get_abacus_STRU, make_supercell_abacus, make_abacus_scf_stru\ @@ -1061,7 +1061,7 @@ def run_vasp_relax(jdata, mdata): run_tasks = [os.path.basename(ii) for ii in relax_run_tasks] api_version = mdata.get('api_version', '0.9') - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") dispatcher = make_dispatcher(mdata['fp_machine'], mdata['fp_resources'], work_dir, run_tasks, fp_group_size) @@ -1074,7 +1074,7 @@ def run_vasp_relax(jdata, mdata): forward_files, backward_files) - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): submission = make_submission( mdata['fp_machine'], mdata['fp_resources'], @@ -1197,7 +1197,7 @@ def run_abacus_relax(jdata, mdata): run_tasks = [os.path.basename(ii) for ii in relax_run_tasks] api_version = mdata.get('api_version', '0.9') - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") dispatcher = make_dispatcher(mdata['fp_machine'], mdata['fp_resources'], work_dir, run_tasks, fp_group_size) @@ -1210,7 +1210,7 @@ def run_abacus_relax(jdata, mdata): forward_files, backward_files) - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): submission = make_submission( mdata['fp_machine'], mdata['fp_resources'], @@ -1264,7 +1264,7 @@ def run_vasp_md(jdata, mdata): #dlog.info("md_work_dir", work_dir) #dlog.info("run_tasks",run_tasks) api_version = mdata.get('api_version', '0.9') - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") dispatcher = make_dispatcher(mdata['fp_machine'], mdata['fp_resources'], work_dir, run_tasks, fp_group_size) @@ -1277,7 +1277,7 @@ def run_vasp_md(jdata, mdata): forward_files, backward_files) - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): submission = make_submission( mdata['fp_machine'], mdata['fp_resources'], @@ -1344,7 +1344,7 @@ def run_abacus_md(jdata, mdata): #dlog.info("md_work_dir", work_dir) #dlog.info("run_tasks",run_tasks) api_version = mdata.get('api_version', '0.9') - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") dispatcher = make_dispatcher(mdata['fp_machine'], mdata['fp_resources'], work_dir, run_tasks, fp_group_size) @@ -1357,7 +1357,7 @@ def run_abacus_md(jdata, mdata): forward_files, backward_files) - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): submission = make_submission( mdata['fp_machine'], mdata['fp_resources'], diff --git a/dpgen/generator/lib/lammps.py b/dpgen/generator/lib/lammps.py index 62cdbe291..0fb3b47ae 100644 --- a/dpgen/generator/lib/lammps.py +++ b/dpgen/generator/lib/lammps.py @@ -4,7 +4,7 @@ import numpy as np import subprocess as sp import scipy.constants as pc -from distutils.version import LooseVersion +from packaging.version import Version def _sample_sphere() : while True: @@ -33,7 +33,7 @@ def make_lammps_input(ensemble, max_seed = 1000000, nopbc = False, deepmd_version = '0.1') : - if (ele_temp_f is not None or ele_temp_a is not None) and LooseVersion(deepmd_version) < LooseVersion('1'): + if (ele_temp_f is not None or ele_temp_a is not None) and Version(deepmd_version) < Version('1'): raise RuntimeError('the electron temperature is only supported by deepmd-kit >= 1.0.0, please upgrade your deepmd-kit') if ele_temp_f is not None and ele_temp_a is not None: raise RuntimeError('the frame style ele_temp and atom style ele_temp should not be set at the same time') @@ -68,7 +68,7 @@ def make_lammps_input(ensemble, graph_list = "" for ii in graphs : graph_list += ii + " " - if LooseVersion(deepmd_version) < LooseVersion('1'): + if Version(deepmd_version) < Version('1'): # 0.x ret+= "pair_style deepmd %s ${THERMO_FREQ} model_devi.out\n" % graph_list else: diff --git a/dpgen/generator/lib/run_calypso.py b/dpgen/generator/lib/run_calypso.py index f43af2e31..4f1512ef7 100644 --- a/dpgen/generator/lib/run_calypso.py +++ b/dpgen/generator/lib/run_calypso.py @@ -19,7 +19,7 @@ from ase.io.trajectory import Trajectory from pathlib import Path from itertools import combinations -from distutils.version import LooseVersion +from packaging.version import Version from dpgen import dlog from dpgen.generator.lib.utils import create_path from dpgen.generator.lib.utils import make_iter_name @@ -122,7 +122,7 @@ def gen_structures(iter_index, jdata, mdata, caly_run_path, current_idx, length_ run_tasks = [os.path.basename(ii) for ii in run_tasks_] - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") dispatcher=make_dispatcher(mdata['model_devi_machine'],mdata['model_devi_resources'],'./', run_tasks, model_devi_group_size) @@ -136,7 +136,7 @@ def gen_structures(iter_index, jdata, mdata, caly_run_path, current_idx, length_ backward_files, outlog = 'model_devi.log', errlog = 'model_devi.log') - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): os.chdir(cwd) submission = make_submission( mdata['model_devi_machine'], @@ -169,7 +169,7 @@ def gen_structures(iter_index, jdata, mdata, caly_run_path, current_idx, length_ # to traj shutil.copyfile(os.path.join('task.%03d'%(jjj),'traj.traj'),os.path.join('traj','%s.traj'%str(jjj+1)),) - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): os.rename('jr.json','jr_%s.json'%(str(ii))) tlist = glob.glob('task.*') @@ -232,7 +232,7 @@ def gen_structures(iter_index, jdata, mdata, caly_run_path, current_idx, length_ run_tasks = [os.path.basename(ii) for ii in run_tasks_] - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") dispatcher=make_dispatcher(mdata['model_devi_machine'],mdata['model_devi_resources'],'./', run_tasks, model_devi_group_size) @@ -246,7 +246,7 @@ def gen_structures(iter_index, jdata, mdata, caly_run_path, current_idx, length_ backward_files, outlog = 'model_devi.log', errlog = 'model_devi.log') - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): os.chdir(cwd) submission = make_submission( mdata['model_devi_machine'], diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index 0483b540a..40183e5e4 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -28,7 +28,7 @@ import scipy.constants as pc from collections import Counter from collections.abc import Iterable -from distutils.version import LooseVersion +from packaging.version import Version from typing import List from numpy.linalg import norm from dpgen import dlog @@ -328,7 +328,7 @@ def make_train (iter_index, except KeyError: mdata = set_version(mdata) # setup data systems - if LooseVersion(mdata["deepmd_version"]) >= LooseVersion('1') and LooseVersion(mdata["deepmd_version"]) < LooseVersion('2'): + if Version(mdata["deepmd_version"]) >= Version('1') and Version(mdata["deepmd_version"]) < Version('2'): # 1.x jinput['training']['systems'] = init_data_sys jinput['training']['batch_size'] = init_batch_size @@ -344,7 +344,7 @@ def make_train (iter_index, jinput['model']['fitting_net'].pop('numb_fparam', None) else: raise RuntimeError('invalid setting for use_ele_temp ' + str(use_ele_temp)) - elif LooseVersion(mdata["deepmd_version"]) >= LooseVersion('2') and LooseVersion(mdata["deepmd_version"]) < LooseVersion('3'): + elif Version(mdata["deepmd_version"]) >= Version('2') and Version(mdata["deepmd_version"]) < Version('3'): # 2.x jinput['training']['training_data'] = {} jinput['training']['training_data']['systems'] = init_data_sys @@ -369,11 +369,11 @@ def make_train (iter_index, jinput['training']['numb_steps'] = training_reuse_stop_batch elif 'stop_batch' in jinput['training'] and training_reuse_stop_batch is not None: jinput['training']['stop_batch'] = training_reuse_stop_batch - if LooseVersion('1') <= LooseVersion(mdata["deepmd_version"]) < LooseVersion('2'): + if Version('1') <= Version(mdata["deepmd_version"]) < Version('2'): jinput['training']['auto_prob_style'] \ ="prob_sys_size; 0:%d:%f; %d:%d:%f" \ %(old_range, training_reuse_old_ratio, old_range, len(init_data_sys), 1.-training_reuse_old_ratio) - elif LooseVersion('2') <= LooseVersion(mdata["deepmd_version"]) < LooseVersion('3'): + elif Version('2') <= Version(mdata["deepmd_version"]) < Version('3'): jinput['training']['training_data']['auto_prob'] \ ="prob_sys_size; 0:%d:%f; %d:%d:%f" \ %(old_range, training_reuse_old_ratio, old_range, len(init_data_sys), 1.-training_reuse_old_ratio) @@ -400,7 +400,7 @@ def make_train (iter_index, raise RuntimeError ("data sys %s does not exists, cwd is %s" % (jj, os.getcwd())) os.chdir(cwd) # set random seed for each model - if LooseVersion(mdata["deepmd_version"]) >= LooseVersion('1') and LooseVersion(mdata["deepmd_version"]) < LooseVersion('3'): + if Version(mdata["deepmd_version"]) >= Version('1') and Version(mdata["deepmd_version"]) < Version('3'): # 1.x if jinput['model']['descriptor']['type'] == 'hybrid': for desc in jinput['model']['descriptor']['list']: @@ -417,7 +417,7 @@ def make_train (iter_index, raise RuntimeError("DP-GEN currently only supports for DeePMD-kit 1.x or 2.x version!" ) # set model activation function if model_devi_activation_func is not None: - if LooseVersion(mdata["deepmd_version"]) < LooseVersion('1'): + if Version(mdata["deepmd_version"]) < Version('1'): raise RuntimeError('model_devi_activation_func does not suppport deepmd version', mdata['deepmd_version']) assert(type(model_devi_activation_func) is list and len(model_devi_activation_func) == numb_models) if len(np.array(model_devi_activation_func).shape) == 2 : # 2-dim list for emd/fitting net-resolved assignment of actF @@ -525,7 +525,7 @@ def run_train (iter_index, task_path = os.path.join(work_path, train_task_fmt % ii) all_task.append(task_path) commands = [] - if LooseVersion(mdata["deepmd_version"]) >= LooseVersion('1') and LooseVersion(mdata["deepmd_version"]) < LooseVersion('3'): + if Version(mdata["deepmd_version"]) >= Version('1') and Version(mdata["deepmd_version"]) < Version('3'): # 1.x ## Commands are like `dp train` and `dp freeze` @@ -600,7 +600,7 @@ def run_train (iter_index, user_forward_files = mdata.get("train" + "_user_forward_files", []) forward_files += [os.path.basename(file) for file in user_forward_files] backward_files += mdata.get("train" + "_user_backward_files", []) - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") dispatcher = make_dispatcher(mdata['train_machine'], mdata['train_resources'], work_path, run_tasks, train_group_size) @@ -615,7 +615,7 @@ def run_train (iter_index, outlog = 'train.log', errlog = 'train.log') - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): submission = make_submission( mdata['train_machine'], mdata['train_resources'], @@ -762,7 +762,7 @@ def find_only_one_key(lmp_lines, key): def revise_lmp_input_model(lmp_lines, task_model_list, trj_freq, deepmd_version = '1'): idx = find_only_one_key(lmp_lines, ['pair_style', 'deepmd']) graph_list = ' '.join(task_model_list) - if LooseVersion(deepmd_version) < LooseVersion('1'): + if Version(deepmd_version) < Version('1'): lmp_lines[idx] = "pair_style deepmd %s %d model_devi.out\n" % (graph_list, trj_freq) else: lmp_lines[idx] = "pair_style deepmd %s out_freq %d out_file model_devi.out\n" % (graph_list, trj_freq) @@ -1072,7 +1072,7 @@ def _make_model_devi_revmat(iter_index, jdata, mdata, conf_systems): template_has_pair_deepmd=0 template_pair_deepmd_idx=line_idx if template_has_pair_deepmd == 0: - if LooseVersion(deepmd_version) < LooseVersion('1'): + if Version(deepmd_version) < Version('1'): if len(lmp_lines[template_pair_deepmd_idx].split()) != (len(models) + len(["pair_style","deepmd","10", "model_devi.out"])): lmp_lines = revise_lmp_input_model(lmp_lines, task_model_list, trj_freq, deepmd_version = deepmd_version) else: @@ -1238,7 +1238,7 @@ def _make_model_devi_native_gromacs(iter_index, jdata, mdata, conf_systems): except ImportError as e: raise RuntimeError("GromacsWrapper>=0.8.0 is needed for DP-GEN + Gromacs.") from e # only support for deepmd v2.0 - if LooseVersion(mdata['deepmd_version']) < LooseVersion('2.0'): + if Version(mdata['deepmd_version']) < Version('2.0'): raise RuntimeError("Only support deepmd-kit 2.x for model_devi_engine='gromacs'") model_devi_jobs = jdata['model_devi_jobs'] if (iter_index >= len(model_devi_jobs)) : @@ -1600,7 +1600,7 @@ def run_md_model_devi (iter_index, api_version = mdata.get('api_version', '0.9') if(len(run_tasks) == 0): raise RuntimeError("run_tasks for model_devi should not be empty! Please check your files.") - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") dispatcher = make_dispatcher(mdata['model_devi_machine'], mdata['model_devi_resources'], work_path, run_tasks, model_devi_group_size) @@ -1615,7 +1615,7 @@ def run_md_model_devi (iter_index, outlog = 'model_devi.log', errlog = 'model_devi.log') - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): submission = make_submission( mdata['model_devi_machine'], mdata['model_devi_resources'], @@ -3133,7 +3133,7 @@ def run_fp_inner (iter_index, backward_files += mdata.get("fp" + "_user_backward_files", []) api_version = mdata.get('api_version', '0.9') - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") dispatcher = make_dispatcher(mdata['fp_machine'], mdata['fp_resources'], work_path, run_tasks, fp_group_size) @@ -3149,7 +3149,7 @@ def run_fp_inner (iter_index, outlog = log_file, errlog = log_file) - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): submission = make_submission( mdata['fp_machine'], mdata['fp_resources'], diff --git a/dpgen/remote/decide_machine.py b/dpgen/remote/decide_machine.py index c551be44b..34486dba3 100644 --- a/dpgen/remote/decide_machine.py +++ b/dpgen/remote/decide_machine.py @@ -9,7 +9,7 @@ import os import json import numpy as np -from distutils.version import LooseVersion +from packaging.version import Version def convert_mdata(mdata, task_types=["train", "model_devi", "fp"]): @@ -54,7 +54,7 @@ def convert_mdata(mdata, task_types=["train", "model_devi", "fp"]): # def decide_train_machine(mdata): -# if LooseVersion(mdata.get('api_version', '0.9')) >= LooseVersion('1.0'): +# if Version(mdata.get('api_version', '0.9')) >= Version('1.0'): # mdata['train_group_size'] = mdata['train'][0]['resources']['group_size'] # if 'train' in mdata: # continue_flag = False @@ -173,7 +173,7 @@ def convert_mdata(mdata, task_types=["train", "model_devi", "fp"]): # return mdata # # def decide_model_devi_machine(mdata): -# if LooseVersion(mdata.get('api_version', '0.9')) >= LooseVersion('1.0'): +# if Version(mdata.get('api_version', '0.9')) >= Version('1.0'): # mdata['model_devi_group_size'] = mdata['model_devi'][0]['resources']['group_size'] # if 'model_devi' in mdata: # continue_flag = False @@ -251,7 +251,7 @@ def convert_mdata(mdata, task_types=["train", "model_devi", "fp"]): # json.dump(profile, _outfile, indent = 4) # return mdata # def decide_fp_machine(mdata): -# if LooseVersion(mdata.get('api_version', '0.9')) >= LooseVersion('1.0'): +# if Version(mdata.get('api_version', '0.9')) >= Version('1.0'): # mdata['fp_group_size'] = mdata['fp'][0]['resources']['group_size'] # if 'fp' in mdata: # #ssert isinstance(mdata['fp']['machine'], list) diff --git a/dpgen/simplify/simplify.py b/dpgen/simplify/simplify.py index 1aeabe14c..245b3ff85 100644 --- a/dpgen/simplify/simplify.py +++ b/dpgen/simplify/simplify.py @@ -24,7 +24,7 @@ from dpgen import dlog from dpgen import SHORT_CMD from dpgen.util import sepline, expand_sys_str, normalize -from distutils.version import LooseVersion +from packaging.version import Version from dpgen.dispatcher.Dispatcher import Dispatcher, _split_tasks, make_dispatcher, make_submission from dpgen.generator.run import make_train, run_train, post_train, run_fp, post_fp, fp_name, model_devi_name, train_name, train_task_fmt, sys_link_fp_vasp_pp, make_fp_vasp_incar, make_fp_vasp_kp, make_fp_vasp_cp_cvasp, data_system_fmt, model_devi_task_fmt, fp_task_fmt # TODO: maybe the following functions can be moved to dpgen.util @@ -202,7 +202,7 @@ def run_model_devi(iter_index, jdata, mdata): backward_files = [detail_file_name] api_version = mdata.get('api_version', '0.9') - if LooseVersion(api_version) < LooseVersion('1.0'): + if Version(api_version) < Version('1.0'): warnings.warn(f"the dpdispatcher will be updated to new version." f"And the interface may be changed. Please check the documents for more details") dispatcher = make_dispatcher(mdata['model_devi_machine'], mdata['model_devi_resources'], work_path, run_tasks, model_devi_group_size) @@ -217,7 +217,7 @@ def run_model_devi(iter_index, jdata, mdata): outlog = 'model_devi.log', errlog = 'model_devi.log') - elif LooseVersion(api_version) >= LooseVersion('1.0'): + elif Version(api_version) >= Version('1.0'): submission = make_submission( mdata['model_devi_machine'], mdata['model_devi_resources'], diff --git a/pyproject.toml b/pyproject.toml index 4449240e5..d271c4d4e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,7 @@ dependencies = [ 'h5py', 'pymatgen-analysis-defects', 'openbabel-wheel', + 'packaging', ] requires-python = ">=3.8" readme = "README.md"