Skip to content

Commit

Permalink
Merge pull request #26 from davegallant/master
Browse files Browse the repository at this point in the history
Allow support for overriding the default PyPI index url
  • Loading branch information
alanhamlett authored Dec 20, 2019
2 parents 5e050fd + 0440082 commit 9cb1c12
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 19 deletions.
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ Options
requirements.txt file.
-n, --no-recursive Prevents updating nested requirements files.
-s, --skip TEXT Comma separated list of packages to skip updating.
--index-url TEXT Base URL of the Python Package Index. Can be
provided multiple times for extra index urls.
--only TEXT Comma separated list of packages. Only these
packages will be updated.
-m, --minor TEXT Comma separated list of packages to only update
Expand Down
52 changes: 35 additions & 17 deletions pur/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
help='Prevents updating nested requirements files.')
@click.option('-s', '--skip', type=click.STRING, help='Comma separated list ' +
'of packages to skip updating.')
@click.option('--index-url', type=click.STRING, multiple=True, help='Base ' +
'URL of the Python Package Index. Can be provided multiple ' +
'times for extra index urls.')
@click.option('--only', type=click.STRING, help='Comma separated list of ' +
'packages. Only these packages will be updated.')
@click.option('-m', '--minor', type=click.STRING, help='Comma separated ' +
Expand Down Expand Up @@ -117,6 +120,7 @@ def pur(**options):
dry_run=options['dry_run'],
no_recursive=options['no_recursive'],
echo=options['echo'],
index_urls=options['index_url'],
)

if not options['dry_run']:
Expand All @@ -131,7 +135,7 @@ def pur(**options):
def update_requirements(input_file=None, output_file=None, force=False,
interactive=False, skip=[], only=[], minor=[],
patch=[], pre=[], dry_run=False,
no_recursive=False, echo=False):
no_recursive=False, echo=False, index_urls=[]):
"""Update a requirements file.
Returns a dict of package update info.
Expand All @@ -152,6 +156,7 @@ def update_requirements(input_file=None, output_file=None, force=False,
minor or major.
:param pre: List of packages to allow updating to pre-release
versions.
:param index_urls: List of PyPI index urls.
"""

obuffer = StringIO()
Expand All @@ -161,7 +166,7 @@ def update_requirements(input_file=None, output_file=None, force=False,
_patch_pip(obuffer, updates, input_file=input_file, output_file=output_file,
force=force, interactive=interactive, skip=skip, only=only,
minor=minor, patch=patch, pre=pre, dry_run=dry_run,
no_recursive=no_recursive, echo=echo)
no_recursive=no_recursive, echo=echo, index_urls=index_urls)

_internal_update_requirements(obuffer, updates,
input_file=input_file,
Expand All @@ -175,7 +180,9 @@ def update_requirements(input_file=None, output_file=None, force=False,
interactive=interactive,
dry_run=dry_run,
no_recursive=no_recursive,
echo=echo)
echo=echo,
index_urls=index_urls,
)

if not dry_run:
if not output_file:
Expand All @@ -193,15 +200,16 @@ def _internal_update_requirements(obuffer, updates, input_file=None,
interactive=False, skip=[], only=[],
minor=[], patch=[], pre=[],
dry_run=False, no_recursive=False,
echo=False):
index_urls=[], echo=False):
global PUR_GLOBAL_UPDATED

updated = 0

try:
requirements = _get_requirements_and_latest(input_file, force=force,
minor=minor, patch=patch,
pre=pre)
pre=pre,
index_urls=index_urls)

stop = False
for line, req, spec_ver, latest_ver in requirements:
Expand Down Expand Up @@ -299,6 +307,7 @@ def patched_parse_requirements(*args, **kwargs):
dry_run=options['dry_run'],
no_recursive=options['no_recursive'],
echo=options['echo'],
index_urls=options['index_urls']
)
if not options['dry_run']:
if options['output_file']:
Expand All @@ -311,26 +320,35 @@ def patched_parse_requirements(*args, **kwargs):
req_file.parse_requirements = patched_parse_requirements


def _get_requirements_and_latest(filename, force=False, minor=[], patch=[],
pre=[]):
def _get_requirements_and_latest(
filename,
force=False,
minor=[],
patch=[],
pre=[],
index_urls=[]):
"""Parse a requirements file and get latest version for each requirement.
Yields a tuple of (original line, InstallRequirement instance,
spec_versions, latest_version).
:param filename: Path to a requirements.txt file.
:param force: Force getting latest version even for packages without
a version specified.
:param minor: List of packages to only update minor and patch versions,
never major.
:param patch: List of packages to only update patch versions, never
minor or major.
:param pre: List of packages to allow updating to pre-release
versions.
:param filename: Path to a requirements.txt file.
:param force: Force getting latest version even for packages without
a version specified.
:param minor: List of packages to only update minor and patch versions,
never major.
:param patch: List of packages to only update patch versions, never
minor or major.
:param pre: List of packages to allow updating to pre-release
versions.
:param index_urls: List of base URLs of the Python Package Index.
"""
session = PipSession()
finder = PackageFinder(
session=session, find_links=[], index_urls=[PyPI.simple_url])
session=session,
find_links=[],
index_urls=index_urls or [PyPI.simple_url],
)

_, content = get_file_content(filename, session=session)
for line_number, line, orig_line in yield_lines(content):
Expand Down
2 changes: 1 addition & 1 deletion tests/samples/requirements-with-alt-index-url.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
--index-url=http://pypi.example.com
--trusted-host=pypi.example.com

--extra-index-url=https://pypi.example2.com
--extra-index-url=https://pypi2.example.com

.
flask
35 changes: 34 additions & 1 deletion tests/test_pur.py
Original file line number Diff line number Diff line change
Expand Up @@ -941,13 +941,46 @@ def __init__(self, *args, **kwargs):

self.assertEqual(
PackageFinderSpy._spy.index_urls,
['http://pypi.example.com', 'https://pypi.example2.com']
['http://pypi.example.com', 'https://pypi2.example.com']
)
self.assertEqual(
PackageFinderSpy._spy.secure_origins,
[('*', 'pypi.example.com', '*')]
)

def test_updates_from_alt_index_url_command_line_arg(self):
requirements = 'tests/samples/requirements.txt'
tempdir = tempfile.mkdtemp()
tmpfile = os.path.join(tempdir, 'requirements.txt')
shutil.copy(requirements, tmpfile)
args = ['--index-url', 'http://pypi.example.com', '--index-url', 'http://pypi2.example.com', '-r', tmpfile]

class PackageFinderSpy(PackageFinder):

_spy = None

def __init__(self, *args, **kwargs):
super(PackageFinderSpy, self).__init__(*args, **kwargs)
PackageFinderSpy._spy = self

with utils.mock.patch('pur.PackageFinder', wraps=PackageFinderSpy) as mock_finder:
with utils.mock.patch('pip._internal.index.PackageFinder.find_all_candidates') as mock_find_all_candidates:

project = 'flask'
version = '12.1'
link = Link('')
candidate = InstallationCandidate(project, version, link)
mock_find_all_candidates.return_value = [candidate]

self.runner.invoke(pur, args)

self.assertTrue(mock_finder.called)

self.assertEqual(
PackageFinderSpy._spy.index_urls,
('http://pypi.example.com', 'http://pypi2.example.com')
)

def test_interactive_choice_default(self):
tempdir = tempfile.mkdtemp()
requirements = os.path.join(tempdir, 'requirements.txt')
Expand Down

0 comments on commit 9cb1c12

Please sign in to comment.