Skip to content

Instantly share code, notes, and snippets.

@ingvaldlorentzen
Last active February 11, 2022 10:18
Show Gist options
  • Save ingvaldlorentzen/d58fe2843069cee9c524d28c12c6eb13 to your computer and use it in GitHub Desktop.
Save ingvaldlorentzen/d58fe2843069cee9c524d28c12c6eb13 to your computer and use it in GitHub Desktop.
Get Outdated Dependencies pyproject.toml
import json
import os
import subprocess
import requests
from tomlkit.toml_file import TOMLFile
# Hosted on: https://gist.github.com/ingvaldlorentzen/d58fe2843069cee9c524d28c12c6eb13
# Raw: https://gist.githubusercontent.com/ingvaldlorentzen/d58fe2843069cee9c524d28c12c6eb13/raw/update_pyproject.py
# Get outdated packages from Poetry
poetry_outdated = subprocess.run(
['poetry', 'show', '-o', '--no-ansi'], check=True, stdout=subprocess.PIPE
).stdout.decode('utf-8')
print(poetry_outdated)
# Read pyproject package info and format into pure simple python objects with roundtrip to json
pyproject_toml = TOMLFile('pyproject.toml')
pyproject_toml_data = pyproject_toml.read()
# Sort TOML items except python which should be at top
pyproject_dependencies = dict(sorted(list(pyproject_toml_data['tool']['poetry']['dependencies'].items())))
python = pyproject_dependencies.pop('python')
pyproject_dependencies = {
'python': python,
**pyproject_dependencies,
}
pyproject_toml_data['tool']['poetry']['dependencies'] = pyproject_dependencies
pyproject_toml_data['tool']['poetry']['dev-dependencies'] = dict(
sorted(list(pyproject_toml_data['tool']['poetry']['dev-dependencies'].items()))
)
if pyproject_toml_data['tool'].get('pipeline', {}).get('ignored-outdated-dependencies', {}):
pyproject_toml_data['tool']['pipeline']['ignored-outdated-dependencies'] = dict(
sorted(list(pyproject_toml_data['tool']['pipeline']['ignored-outdated-dependencies'].items()))
)
# Format toml info into pure simple python objects with roundtrip to json
pyproject_plain = json.loads(str(pyproject_toml_data.value).replace("'", '"'))
pyproject_dependencies = pyproject_plain['tool']['poetry']['dependencies']
pyproject_dev_dependencies = pyproject_plain['tool']['poetry']['dev-dependencies']
ignored_outdated_dependencies = pyproject_plain['tool']['pipeline']['ignored-outdated-dependencies']
# Format shell output into python objects
outdated_packages = [
{
'package': line.split()[0],
'current_version': line.split()[2 if os.environ.get('CI') else 1],
'new_version': line.split()[3 if os.environ.get('CI') else 2], # In CI there is a (!) column for some reason
}
for line in poetry_outdated.split('\n')
if line and line.split()[0]
]
# Format pyproject package info to same format as poetry output
pyproject_packages = [
{'package': key, 'type': 'dependencies', 'version': value if type(value) is str else value['version']}
for key, value in pyproject_dependencies.items()
]
pyproject_dev_packages = [
{'package': key, 'type': 'dev-dependencies', 'version': value if type(value) is str else value['version']}
for key, value in pyproject_dev_dependencies.items()
]
pyproject_packages_combined = pyproject_packages + pyproject_dev_packages
# Filter out outdated packages that are not top-level defined dependencies and add info on ignore packages
filtered_outdated_packages = [
{
**outdated_package,
'reason': ignored_outdated_dependencies.get(outdated_package['package']) or '',
'type': 'ignored'
if ignored_outdated_dependencies.get(outdated_package['package'])
else next(
package['type']
for package in pyproject_packages_combined
if package['package'] == outdated_package['package']
),
}
for outdated_package in outdated_packages
if outdated_package['package'] in [package['package'] for package in pyproject_packages_combined]
]
# Write updates to pyproject.toml
for outdated_package in filtered_outdated_packages:
if outdated_package['type'] != 'ignored':
pyproject_package = pyproject_toml_data['tool']['poetry'][outdated_package['type']]
if isinstance(pyproject_package[outdated_package['package']], str):
pyproject_package[outdated_package['package']] = outdated_package['new_version']
else:
pyproject_package[outdated_package['package']]['version'] = outdated_package['new_version']
pyproject_toml.write(pyproject_toml_data)
for outdated_package in filtered_outdated_packages:
response = requests.get(f"https://pypi.org/pypi/{outdated_package['package']}/json").json()['info']
outdated_package['home_page'] = response['home_page']
outdated_package['package_url'] = response['package_url']
outdated_package['project_urls'] = response['project_urls'] or {}
# Write updates to json file for easy MR description parsing in later stage
with open('updates.json', 'w') as file:
json.dump(filtered_outdated_packages, file, indent=2)
file.write('\n')
file.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment