Commit deee694b authored by richardARPANET's avatar richardARPANET

Initial commit

parents
#pycharm
.idea
.cache
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
.vscode
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
.idea
htmlcov/
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.vspscc
.builds
*.dotCover
## TODO: If you have NuGet Package Restore enabled, uncomment this
#packages/
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
# Visual Studio profiler
*.psess
*.vsp
# ReSharper is a .NET coding add-in
_ReSharper*
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish
# Others
[Bb]in
[Oo]bj
sql
TestResults
*.Cache
ClientBin
stylecop.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
############
## Windows
############
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
# virtual env
venv
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store
*.sqlite
.. :changelog:
Release History
---------------
0.1.0 (unreleased)
++++++++++++++++++
- Initial release.
include HISTORY.rst
include README.md
include requirements.txt
recursive-include tests *
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
recursive-include docs *.rst *.md conf.py Makefile make.bat
**NOTICE**: If you're reading this on GitHub.com please be aware this is a mirror of the primary remote located at https://code.richard.do/richardARPANET/lock-requirements.
Please direct issues and pull requests there.
# lock-requirements
A CLI tool to update your requirements.txt file package versions to be locked/fixed to the latest versions available on PyPI.
#### For example
Input file contents before locking:
```
requirements-parser
pypi-simple>=0.4.0,<1.0.0
docopt>=0.5.0,<1.0.0
wheel
```
Input file contents after locking:
```
requirements-parser==0.2.0
pypi-simple==0.4.0
docopt==0.6.2
wheel==0.32.3
```
## Installation
```
pip install lock-requirements
```
## Usage
```
lock requirements.txt
lock requirements-dev.txt
```
Use a custom PyPI simple index url to retrieve latest package versions from.
```
lock requirements.txt --index-url=https://example.com/simple/
```
## Development Installation
```
pip install -r requirements-dev.txt
python setup.py develop
```
And to the run tests:
```
tox
```
-r requirements.txt
pytest==4.2.0
ipdb==0.11
flake8==3.7.5
pep8-naming==0.8.2
mccabe==0.6.1
pytest-watch==4.2.0
pytest-vcr==1.0.1
zest.releaser==6.16.0
requirements-parser>=0.2.0,<1.0.0
pypi-simple>=0.4.0,<1.0.0
docopt>=0.5.0,<1.0.0
wheel
#!/usr/bin/env python
# -*- coding: utf-8 -*
import os
from codecs import open
from setuptools import find_packages, setup
# allow setup.py to be run from any path
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
with open('requirements.txt') as f:
install_requires = f.read().splitlines()
desc = (
'A CLI tool to update your requirements.txt file package versions '
'to be locked/fixed to the latest versions available on PyPI.'
)
with open('README.md', 'r', 'utf-8') as f:
readme = f.read()
setup(
name='lock-requirements',
version='0.1.0.dev0',
packages=find_packages('src', exclude=('tests',)),
package_dir={'': 'src'},
description=desc,
include_package_data=True,
long_description=readme,
long_description_content_type='text/markdown',
zip_safe=False,
author='Richard O\'Dwyer',
author_email='richard@richard.do',
license='Apache 2.0',
install_requires=install_requires,
entry_points={
'console_scripts': [
'lock = lock.cli:main',
],
},
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Natural Language :: English',
'License :: OSI Approved :: Apache Software License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
],
)
from .lock import * # noqa
"""
Usage: lock <file> [--index-url=<index_url>]
Locks the requirements in the given file to the latest version available.
Options:
-h --help
"""
from docopt import docopt
from lock import lock
DEFAULT_PYPI_SIMPLE_ENDPOINT = 'https://pypi.org/simple/'
def main(arguments=None):
arguments = arguments or docopt(__doc__)
reqs_path = arguments['<file>']
endpoint = arguments.get('<index_url>', DEFAULT_PYPI_SIMPLE_ENDPOINT)
try:
lock(requirements_path=reqs_path, endpoint=endpoint)
except FileNotFoundError:
print(f'Could not find file to update: {reqs_path}')
else:
print(f'Done updating {reqs_path} using index {endpoint}')
if __name__ == '__main__':
main()
from pypi_simple import PyPISimple
from .parser import parse
def lock(requirements_path, endpoint):
return _lock_requirements(
input_path=requirements_path,
output_path=requirements_path,
endpoint=endpoint,
)
def _lock_requirements(*, input_path, output_path, endpoint):
output_lines = []
with open(input_path, 'r') as file_:
for req in parse(file_):
if isinstance(req, str):
output_lines.append(f'{req}\n')
elif req.uri:
output_lines.append(f'{req.line}\n')
else:
_, version = _get_latest_versions(
package_name=req.name, endpoint=endpoint
)
extras = sorted(req.extras)
extras_str = f'[{",".join(extras)}]' if extras else ''
output_lines.append(f'{req.name}{extras_str}=={version}\n')
with open(output_path, 'w') as file_:
for line in output_lines:
file_.write(line)
return output_path
def _get_latest_versions(*, package_name, endpoint):
pypi = PyPISimple(endpoint=endpoint)
packages = pypi.get_project_files(package_name)
try:
latest_version = packages[-1].version
except IndexError:
# Package not found
latest_version = None
return (package_name, latest_version)
import warnings
from requirements.requirement import Requirement
def parse(reqstr):
try:
# Python 2.x compatibility
if not isinstance(reqstr, basestring):
reqstr = reqstr.read()
except NameError:
# Python 3.x only
if not isinstance(reqstr, str):
reqstr = reqstr.read()
for line in reqstr.splitlines():
line = line.strip()
if line == '':
continue
elif not line or line.startswith('#'):
# comments are lines that start with # only
continue
elif line.startswith('-r') or line.startswith('--requirement'):
yield line
elif line.startswith('-f') or line.startswith('--find-links') or \
line.startswith('-i') or line.startswith('--index-url') or \
line.startswith('--extra-index-url') or \
line.startswith('--no-index'):
warnings.warn('Private repos not supported. Skipping.')
continue
elif line.startswith('-Z') or line.startswith('--always-unzip'):
warnings.warn('Unused option --always-unzip. Skipping.')
continue
else:
yield Requirement.parse(line)
This diff is collapsed.
-r ../../requirements.txt
requests
-e git://github.com/mozilla/elasticutils.git#egg=elasticutils
imdbpie==0.1.0
celery[sqs,s3]
from lock.cli import main
def test_main(capsys):
arguments = {
'<file>': 'requirements.txt',
'<index_url>': 'https://pypi.org/simple/'
}
main(arguments=arguments)
captured = capsys.readouterr()
assert captured.out == (
'Done updating requirements.txt using index https://pypi.org/simple/\n'
)
def test_main_when_file_not_found(capsys):
arguments = {'<file>': 'not-found.txt'}
main(arguments=arguments)
captured = capsys.readouterr()
assert captured.out == 'Could not find file to update: not-found.txt\n'
import pytest
import vcr
from lock.lock import _get_latest_versions, _lock_requirements
PYPI_SIMPLE_ENDPOINT = 'https://pypi.org/simple/'
@pytest.mark.vcr
def test_lock_requirements(tmpdir):
input_file = 'src/tests/example-requirements.txt'
output_file = str(tmpdir.join('out.txt'))
output_file = _lock_requirements(
input_path=input_file, output_path=output_file,
endpoint=PYPI_SIMPLE_ENDPOINT,
)
with open(output_file, 'r') as file_:
data = file_.readlines()
assert data == [
'-r ../../requirements.txt\n',
'requests==2.21.0\n',
'-e git://github.com/mozilla/elasticutils.git#egg=elasticutils\n',
'imdbpie==5.6.3\n',
'celery[s3,sqs]==4.2.1\n',
]
@pytest.mark.parametrize('package_name, expected_result', [
('requests', ('requests', '2.21.0')),
('imdbpie', ('imdbpie', '5.6.3')),
('package-which-is-not-found', ('package-which-is-not-found', None)),
])
def test_get_latest_versions(package_name, expected_result):
with vcr.use_cassette(
'src/tests/cassettes/'
f'test_get_latest_versions_{package_name}.yaml'
):
output = _get_latest_versions(
package_name=package_name,
endpoint=PYPI_SIMPLE_ENDPOINT,
)
assert output == expected_result
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment