Skip to content

Instantly share code, notes, and snippets.

@nathants
Last active August 20, 2022 08:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nathants/edaae4554aeb9e1bbe604922edb3c4d9 to your computer and use it in GitHub Desktop.
Save nathants/edaae4554aeb9e1bbe604922edb3c4d9 to your computer and use it in GitHub Desktop.
check for updates and optionally upgrade packages via pip
#!/usr/bin/env python3
# The MIT License (MIT)
# Copyright (c) 2022-present Nathan Todd-Stone
# https://en.wikipedia.org/wiki/MIT_License#License_terms
"""
check for updates and optionally upgrade packages via pip
"""
import os
import subprocess
import sys
import termios
import tty
_trace = lambda x: print(f'$ {x} [cwd={os.getcwd()}]', file=sys.stderr) or x
_kw = dict(shell=True, executable='/bin/bash')
_fmt = lambda a: _trace(' '.join(map(str, a)))
co = lambda *a: subprocess.check_output(_fmt(a), **_kw).decode('utf-8').strip()
cc = lambda *a: subprocess.check_call(_fmt(a), **_kw)
def getch():
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
try:
tty.setraw(fd)
val = sys.stdin.read(1).lower()
if val == '\x03':
sys.exit(1)
else:
return val
except KeyboardInterrupt:
sys.exit(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)
def pip_checks():
checks = co('pip check || echo failed: $?').splitlines()
failed = (checks[-1].startswith('failed: ')
and len(checks[-1].split()) == 2
and checks[-1].split()[1].isdigit())
if failed:
gits = co('pip freeze').splitlines()
gits = {x.split('egg=')[-1]
.split('&')[0]
.replace('-', '_')
for x in gits
if 'egg=' in x}
checks = {x.split()[0].replace('-', '_')
for x in checks[:-1]}
return checks - gits
else:
return []
def pip_packages():
pip = os.environ.get('pip', 'pip')
for outdated in co(pip, 'list --outdated').splitlines()[2:]:
try:
name, old, new, kind, location = outdated.split()
print('skip:', name, location)
continue
except ValueError:
name, old, new, kind = outdated.split()
print('upgrade:', name, old, '->', new)
yield name
if __name__ == '__main__':
packages = list(pip_packages())
if packages:
print('\nwould you like to proceed? y/n\n')
assert getch() == 'y', 'abort'
cc('pip install --upgrade', *packages)
else:
print('nothing to upgrade')
for package in pip_checks():
cc('pip install', package)
checks = pip_checks()
if checks:
print('error: pip check failed', file=sys.stderr)
print('\n'.join(checks))
sys.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment