Skip to content

Instantly share code, notes, and snippets.

@v--
Last active February 23, 2026 21:47
Show Gist options
  • Select an option

  • Save v--/72ef9029249c2362e2dc8ca6e864a3b9 to your computer and use it in GitHub Desktop.

Select an option

Save v--/72ef9029249c2362e2dc8ca6e864a3b9 to your computer and use it in GitHub Desktop.
A naive scripts that iterates through version specifiers of the form "package>=version" or "package (>=version)" and updates the version based on the lockfile.
import re
import tomllib
import click
def sync_dependencies(raw_pyproject: str, dep_list: list[str], lockfile: dict) -> str:
for dep_string in dep_list:
match = re.fullmatch(r'(?P<name>[^(@\s]+)\s*\(?>=?(?P<version>[^),]+)\)?\s*', dep_string)
if match is None:
continue
name = match.group('name')
version = match.group('version')
for pkginfo in lockfile['package']:
if pkginfo['name'] == name:
if version != pkginfo['version']:
click.echo(f'Changing version of {name} from {version} to {pkginfo['version']}')
updated_dep_string = dep_string.replace(version, pkginfo['version'])
raw_pyproject = raw_pyproject.replace(dep_string, updated_dep_string)
break
return raw_pyproject
@click.command(help='A naive scripts that iterates through version specifiers of the form "package>=version" or "package (>=version)" and updates the version based on the lockfile.')
@click.option('-p', '--pyproject', default='pyproject.toml', type=click.Path(readable=True, exists=True, dir_okay=False))
@click.option('-l', '--lockfile', type=click.Path(readable=True, exists=False, dir_okay=False))
def merge_lockfile(pyproject: str, lockfile: str | None = None) -> None:
with open(pyproject) as file:
raw_pyproject = file.read()
pyproject_toml = tomllib.loads(raw_pyproject)
if lockfile is None:
for stem in ['pylock', 'uv', 'poetry']:
try:
with open(stem + '.lock', 'rb') as file:
lockfile_toml = tomllib.load(file)
break
except FileNotFoundError:
pass
else:
raise click.ClickException('Could not find a lock file automatically. Consider using the --lockfile option.') from None
else:
with open(lockfile, 'rb') as file:
lockfile_toml = tomllib.load(file)
if project_section := pyproject_toml.get('project'):
if dep_list := project_section.get('dependencies'):
raw_pyproject = sync_dependencies(raw_pyproject, dep_list, lockfile_toml)
if optional := project_section.get('optional-dependencies'):
for dep_list in optional.values():
raw_pyproject = sync_dependencies(raw_pyproject, dep_list, lockfile_toml)
if groups := pyproject_toml.get('dependency-groups'):
for dep_list in groups.values():
raw_pyproject = sync_dependencies(raw_pyproject, dep_list, lockfile_toml)
with open(pyproject, 'w') as file:
file.write(raw_pyproject)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment