Last active
February 23, 2026 21:47
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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