mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 14:50:16 +00:00
Remove vendored pipreqs
Also remove dependencies:
yarg
docopt
This commit is contained in:
@@ -15,7 +15,6 @@ recursive-include pipenv *.rst
|
||||
|
||||
include pipenv/patched/notpip/_vendor/vendor.txt
|
||||
include pipenv/patched/safety.zip pipenv/patched/patched.txt
|
||||
include pipenv/vendor/pipreqs/stdlib pipenv/vendor/pipreqs/mapping
|
||||
include pipenv/vendor/*.txt pipenv/vendor/pexpect/bashrc.sh
|
||||
include pipenv/vendor/Makefile
|
||||
include pipenv/pipenv.1
|
||||
|
||||
Vendored
+1
-1
@@ -809,7 +809,7 @@ class BaseCommand:
|
||||
parsing methods that do not depend on the Click parser.
|
||||
|
||||
For instance, this can be used to bridge Click and other systems like
|
||||
argparse or docopt.
|
||||
argparse.
|
||||
|
||||
Because base commands do not implement a lot of the API that other
|
||||
parts of Click take for granted, they are not supported for all
|
||||
|
||||
Vendored
-19
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2012 Vladimir Keleshev, <vladimir@keleshev.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Vendored
-579
@@ -1,579 +0,0 @@
|
||||
"""Pythonic command-line interface parser that will make you smile.
|
||||
|
||||
* http://docopt.org
|
||||
* Repository and issue-tracker: https://github.com/docopt/docopt
|
||||
* Licensed under terms of MIT license (see LICENSE-MIT)
|
||||
* Copyright (c) 2013 Vladimir Keleshev, vladimir@keleshev.com
|
||||
|
||||
"""
|
||||
import sys
|
||||
import re
|
||||
|
||||
|
||||
__all__ = ['docopt']
|
||||
__version__ = '0.6.2'
|
||||
|
||||
|
||||
class DocoptLanguageError(Exception):
|
||||
|
||||
"""Error in construction of usage-message by developer."""
|
||||
|
||||
|
||||
class DocoptExit(SystemExit):
|
||||
|
||||
"""Exit in case user invoked program with incorrect arguments."""
|
||||
|
||||
usage = ''
|
||||
|
||||
def __init__(self, message=''):
|
||||
SystemExit.__init__(self, (message + '\n' + self.usage).strip())
|
||||
|
||||
|
||||
class Pattern(object):
|
||||
|
||||
def __eq__(self, other):
|
||||
return repr(self) == repr(other)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
|
||||
def fix(self):
|
||||
self.fix_identities()
|
||||
self.fix_repeating_arguments()
|
||||
return self
|
||||
|
||||
def fix_identities(self, uniq=None):
|
||||
"""Make pattern-tree tips point to same object if they are equal."""
|
||||
if not hasattr(self, 'children'):
|
||||
return self
|
||||
uniq = list(set(self.flat())) if uniq is None else uniq
|
||||
for i, c in enumerate(self.children):
|
||||
if not hasattr(c, 'children'):
|
||||
assert c in uniq
|
||||
self.children[i] = uniq[uniq.index(c)]
|
||||
else:
|
||||
c.fix_identities(uniq)
|
||||
|
||||
def fix_repeating_arguments(self):
|
||||
"""Fix elements that should accumulate/increment values."""
|
||||
either = [list(c.children) for c in self.either.children]
|
||||
for case in either:
|
||||
for e in [c for c in case if case.count(c) > 1]:
|
||||
if type(e) is Argument or type(e) is Option and e.argcount:
|
||||
if e.value is None:
|
||||
e.value = []
|
||||
elif type(e.value) is not list:
|
||||
e.value = e.value.split()
|
||||
if type(e) is Command or type(e) is Option and e.argcount == 0:
|
||||
e.value = 0
|
||||
return self
|
||||
|
||||
@property
|
||||
def either(self):
|
||||
"""Transform pattern into an equivalent, with only top-level Either."""
|
||||
# Currently the pattern will not be equivalent, but more "narrow",
|
||||
# although good enough to reason about list arguments.
|
||||
ret = []
|
||||
groups = [[self]]
|
||||
while groups:
|
||||
children = groups.pop(0)
|
||||
types = [type(c) for c in children]
|
||||
if Either in types:
|
||||
either = [c for c in children if type(c) is Either][0]
|
||||
children.pop(children.index(either))
|
||||
for c in either.children:
|
||||
groups.append([c] + children)
|
||||
elif Required in types:
|
||||
required = [c for c in children if type(c) is Required][0]
|
||||
children.pop(children.index(required))
|
||||
groups.append(list(required.children) + children)
|
||||
elif Optional in types:
|
||||
optional = [c for c in children if type(c) is Optional][0]
|
||||
children.pop(children.index(optional))
|
||||
groups.append(list(optional.children) + children)
|
||||
elif AnyOptions in types:
|
||||
optional = [c for c in children if type(c) is AnyOptions][0]
|
||||
children.pop(children.index(optional))
|
||||
groups.append(list(optional.children) + children)
|
||||
elif OneOrMore in types:
|
||||
oneormore = [c for c in children if type(c) is OneOrMore][0]
|
||||
children.pop(children.index(oneormore))
|
||||
groups.append(list(oneormore.children) * 2 + children)
|
||||
else:
|
||||
ret.append(children)
|
||||
return Either(*[Required(*e) for e in ret])
|
||||
|
||||
|
||||
class ChildPattern(Pattern):
|
||||
|
||||
def __init__(self, name, value=None):
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r, %r)' % (self.__class__.__name__, self.name, self.value)
|
||||
|
||||
def flat(self, *types):
|
||||
return [self] if not types or type(self) in types else []
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
pos, match = self.single_match(left)
|
||||
if match is None:
|
||||
return False, left, collected
|
||||
left_ = left[:pos] + left[pos + 1:]
|
||||
same_name = [a for a in collected if a.name == self.name]
|
||||
if type(self.value) in (int, list):
|
||||
if type(self.value) is int:
|
||||
increment = 1
|
||||
else:
|
||||
increment = ([match.value] if type(match.value) is str
|
||||
else match.value)
|
||||
if not same_name:
|
||||
match.value = increment
|
||||
return True, left_, collected + [match]
|
||||
same_name[0].value += increment
|
||||
return True, left_, collected
|
||||
return True, left_, collected + [match]
|
||||
|
||||
|
||||
class ParentPattern(Pattern):
|
||||
|
||||
def __init__(self, *children):
|
||||
self.children = list(children)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%s)' % (self.__class__.__name__,
|
||||
', '.join(repr(a) for a in self.children))
|
||||
|
||||
def flat(self, *types):
|
||||
if type(self) in types:
|
||||
return [self]
|
||||
return sum([c.flat(*types) for c in self.children], [])
|
||||
|
||||
|
||||
class Argument(ChildPattern):
|
||||
|
||||
def single_match(self, left):
|
||||
for n, p in enumerate(left):
|
||||
if type(p) is Argument:
|
||||
return n, Argument(self.name, p.value)
|
||||
return None, None
|
||||
|
||||
@classmethod
|
||||
def parse(class_, source):
|
||||
name = re.findall('(<\S*?>)', source)[0]
|
||||
value = re.findall('\[default: (.*)\]', source, flags=re.I)
|
||||
return class_(name, value[0] if value else None)
|
||||
|
||||
|
||||
class Command(Argument):
|
||||
|
||||
def __init__(self, name, value=False):
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
def single_match(self, left):
|
||||
for n, p in enumerate(left):
|
||||
if type(p) is Argument:
|
||||
if p.value == self.name:
|
||||
return n, Command(self.name, True)
|
||||
else:
|
||||
break
|
||||
return None, None
|
||||
|
||||
|
||||
class Option(ChildPattern):
|
||||
|
||||
def __init__(self, short=None, long=None, argcount=0, value=False):
|
||||
assert argcount in (0, 1)
|
||||
self.short, self.long = short, long
|
||||
self.argcount, self.value = argcount, value
|
||||
self.value = None if value is False and argcount else value
|
||||
|
||||
@classmethod
|
||||
def parse(class_, option_description):
|
||||
short, long, argcount, value = None, None, 0, False
|
||||
options, _, description = option_description.strip().partition(' ')
|
||||
options = options.replace(',', ' ').replace('=', ' ')
|
||||
for s in options.split():
|
||||
if s.startswith('--'):
|
||||
long = s
|
||||
elif s.startswith('-'):
|
||||
short = s
|
||||
else:
|
||||
argcount = 1
|
||||
if argcount:
|
||||
matched = re.findall('\[default: (.*)\]', description, flags=re.I)
|
||||
value = matched[0] if matched else None
|
||||
return class_(short, long, argcount, value)
|
||||
|
||||
def single_match(self, left):
|
||||
for n, p in enumerate(left):
|
||||
if self.name == p.name:
|
||||
return n, p
|
||||
return None, None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.long or self.short
|
||||
|
||||
def __repr__(self):
|
||||
return 'Option(%r, %r, %r, %r)' % (self.short, self.long,
|
||||
self.argcount, self.value)
|
||||
|
||||
|
||||
class Required(ParentPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
l = left
|
||||
c = collected
|
||||
for p in self.children:
|
||||
matched, l, c = p.match(l, c)
|
||||
if not matched:
|
||||
return False, left, collected
|
||||
return True, l, c
|
||||
|
||||
|
||||
class Optional(ParentPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
for p in self.children:
|
||||
m, left, collected = p.match(left, collected)
|
||||
return True, left, collected
|
||||
|
||||
|
||||
class AnyOptions(Optional):
|
||||
|
||||
"""Marker/placeholder for [options] shortcut."""
|
||||
|
||||
|
||||
class OneOrMore(ParentPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
assert len(self.children) == 1
|
||||
collected = [] if collected is None else collected
|
||||
l = left
|
||||
c = collected
|
||||
l_ = None
|
||||
matched = True
|
||||
times = 0
|
||||
while matched:
|
||||
# could it be that something didn't match but changed l or c?
|
||||
matched, l, c = self.children[0].match(l, c)
|
||||
times += 1 if matched else 0
|
||||
if l_ == l:
|
||||
break
|
||||
l_ = l
|
||||
if times >= 1:
|
||||
return True, l, c
|
||||
return False, left, collected
|
||||
|
||||
|
||||
class Either(ParentPattern):
|
||||
|
||||
def match(self, left, collected=None):
|
||||
collected = [] if collected is None else collected
|
||||
outcomes = []
|
||||
for p in self.children:
|
||||
matched, _, _ = outcome = p.match(left, collected)
|
||||
if matched:
|
||||
outcomes.append(outcome)
|
||||
if outcomes:
|
||||
return min(outcomes, key=lambda outcome: len(outcome[1]))
|
||||
return False, left, collected
|
||||
|
||||
|
||||
class TokenStream(list):
|
||||
|
||||
def __init__(self, source, error):
|
||||
self += source.split() if hasattr(source, 'split') else source
|
||||
self.error = error
|
||||
|
||||
def move(self):
|
||||
return self.pop(0) if len(self) else None
|
||||
|
||||
def current(self):
|
||||
return self[0] if len(self) else None
|
||||
|
||||
|
||||
def parse_long(tokens, options):
|
||||
"""long ::= '--' chars [ ( ' ' | '=' ) chars ] ;"""
|
||||
long, eq, value = tokens.move().partition('=')
|
||||
assert long.startswith('--')
|
||||
value = None if eq == value == '' else value
|
||||
similar = [o for o in options if o.long == long]
|
||||
if tokens.error is DocoptExit and similar == []: # if no exact match
|
||||
similar = [o for o in options if o.long and o.long.startswith(long)]
|
||||
if len(similar) > 1: # might be simply specified ambiguously 2+ times?
|
||||
raise tokens.error('%s is not a unique prefix: %s?' %
|
||||
(long, ', '.join(o.long for o in similar)))
|
||||
elif len(similar) < 1:
|
||||
argcount = 1 if eq == '=' else 0
|
||||
o = Option(None, long, argcount)
|
||||
options.append(o)
|
||||
if tokens.error is DocoptExit:
|
||||
o = Option(None, long, argcount, value if argcount else True)
|
||||
else:
|
||||
o = Option(similar[0].short, similar[0].long,
|
||||
similar[0].argcount, similar[0].value)
|
||||
if o.argcount == 0:
|
||||
if value is not None:
|
||||
raise tokens.error('%s must not have an argument' % o.long)
|
||||
else:
|
||||
if value is None:
|
||||
if tokens.current() is None:
|
||||
raise tokens.error('%s requires argument' % o.long)
|
||||
value = tokens.move()
|
||||
if tokens.error is DocoptExit:
|
||||
o.value = value if value is not None else True
|
||||
return [o]
|
||||
|
||||
|
||||
def parse_shorts(tokens, options):
|
||||
"""shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;"""
|
||||
token = tokens.move()
|
||||
assert token.startswith('-') and not token.startswith('--')
|
||||
left = token.lstrip('-')
|
||||
parsed = []
|
||||
while left != '':
|
||||
short, left = '-' + left[0], left[1:]
|
||||
similar = [o for o in options if o.short == short]
|
||||
if len(similar) > 1:
|
||||
raise tokens.error('%s is specified ambiguously %d times' %
|
||||
(short, len(similar)))
|
||||
elif len(similar) < 1:
|
||||
o = Option(short, None, 0)
|
||||
options.append(o)
|
||||
if tokens.error is DocoptExit:
|
||||
o = Option(short, None, 0, True)
|
||||
else: # why copying is necessary here?
|
||||
o = Option(short, similar[0].long,
|
||||
similar[0].argcount, similar[0].value)
|
||||
value = None
|
||||
if o.argcount != 0:
|
||||
if left == '':
|
||||
if tokens.current() is None:
|
||||
raise tokens.error('%s requires argument' % short)
|
||||
value = tokens.move()
|
||||
else:
|
||||
value = left
|
||||
left = ''
|
||||
if tokens.error is DocoptExit:
|
||||
o.value = value if value is not None else True
|
||||
parsed.append(o)
|
||||
return parsed
|
||||
|
||||
|
||||
def parse_pattern(source, options):
|
||||
tokens = TokenStream(re.sub(r'([\[\]\(\)\|]|\.\.\.)', r' \1 ', source),
|
||||
DocoptLanguageError)
|
||||
result = parse_expr(tokens, options)
|
||||
if tokens.current() is not None:
|
||||
raise tokens.error('unexpected ending: %r' % ' '.join(tokens))
|
||||
return Required(*result)
|
||||
|
||||
|
||||
def parse_expr(tokens, options):
|
||||
"""expr ::= seq ( '|' seq )* ;"""
|
||||
seq = parse_seq(tokens, options)
|
||||
if tokens.current() != '|':
|
||||
return seq
|
||||
result = [Required(*seq)] if len(seq) > 1 else seq
|
||||
while tokens.current() == '|':
|
||||
tokens.move()
|
||||
seq = parse_seq(tokens, options)
|
||||
result += [Required(*seq)] if len(seq) > 1 else seq
|
||||
return [Either(*result)] if len(result) > 1 else result
|
||||
|
||||
|
||||
def parse_seq(tokens, options):
|
||||
"""seq ::= ( atom [ '...' ] )* ;"""
|
||||
result = []
|
||||
while tokens.current() not in [None, ']', ')', '|']:
|
||||
atom = parse_atom(tokens, options)
|
||||
if tokens.current() == '...':
|
||||
atom = [OneOrMore(*atom)]
|
||||
tokens.move()
|
||||
result += atom
|
||||
return result
|
||||
|
||||
|
||||
def parse_atom(tokens, options):
|
||||
"""atom ::= '(' expr ')' | '[' expr ']' | 'options'
|
||||
| long | shorts | argument | command ;
|
||||
"""
|
||||
token = tokens.current()
|
||||
result = []
|
||||
if token in '([':
|
||||
tokens.move()
|
||||
matching, pattern = {'(': [')', Required], '[': [']', Optional]}[token]
|
||||
result = pattern(*parse_expr(tokens, options))
|
||||
if tokens.move() != matching:
|
||||
raise tokens.error("unmatched '%s'" % token)
|
||||
return [result]
|
||||
elif token == 'options':
|
||||
tokens.move()
|
||||
return [AnyOptions()]
|
||||
elif token.startswith('--') and token != '--':
|
||||
return parse_long(tokens, options)
|
||||
elif token.startswith('-') and token not in ('-', '--'):
|
||||
return parse_shorts(tokens, options)
|
||||
elif token.startswith('<') and token.endswith('>') or token.isupper():
|
||||
return [Argument(tokens.move())]
|
||||
else:
|
||||
return [Command(tokens.move())]
|
||||
|
||||
|
||||
def parse_argv(tokens, options, options_first=False):
|
||||
"""Parse command-line argument vector.
|
||||
|
||||
If options_first:
|
||||
argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
|
||||
else:
|
||||
argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
|
||||
|
||||
"""
|
||||
parsed = []
|
||||
while tokens.current() is not None:
|
||||
if tokens.current() == '--':
|
||||
return parsed + [Argument(None, v) for v in tokens]
|
||||
elif tokens.current().startswith('--'):
|
||||
parsed += parse_long(tokens, options)
|
||||
elif tokens.current().startswith('-') and tokens.current() != '-':
|
||||
parsed += parse_shorts(tokens, options)
|
||||
elif options_first:
|
||||
return parsed + [Argument(None, v) for v in tokens]
|
||||
else:
|
||||
parsed.append(Argument(None, tokens.move()))
|
||||
return parsed
|
||||
|
||||
|
||||
def parse_defaults(doc):
|
||||
# in python < 2.7 you can't pass flags=re.MULTILINE
|
||||
split = re.split('\n *(<\S+?>|-\S+?)', doc)[1:]
|
||||
split = [s1 + s2 for s1, s2 in zip(split[::2], split[1::2])]
|
||||
options = [Option.parse(s) for s in split if s.startswith('-')]
|
||||
#arguments = [Argument.parse(s) for s in split if s.startswith('<')]
|
||||
#return options, arguments
|
||||
return options
|
||||
|
||||
|
||||
def printable_usage(doc):
|
||||
# in python < 2.7 you can't pass flags=re.IGNORECASE
|
||||
usage_split = re.split(r'([Uu][Ss][Aa][Gg][Ee]:)', doc)
|
||||
if len(usage_split) < 3:
|
||||
raise DocoptLanguageError('"usage:" (case-insensitive) not found.')
|
||||
if len(usage_split) > 3:
|
||||
raise DocoptLanguageError('More than one "usage:" (case-insensitive).')
|
||||
return re.split(r'\n\s*\n', ''.join(usage_split[1:]))[0].strip()
|
||||
|
||||
|
||||
def formal_usage(printable_usage):
|
||||
pu = printable_usage.split()[1:] # split and drop "usage:"
|
||||
return '( ' + ' '.join(') | (' if s == pu[0] else s for s in pu[1:]) + ' )'
|
||||
|
||||
|
||||
def extras(help, version, options, doc):
|
||||
if help and any((o.name in ('-h', '--help')) and o.value for o in options):
|
||||
print(doc.strip("\n"))
|
||||
sys.exit()
|
||||
if version and any(o.name == '--version' and o.value for o in options):
|
||||
print(version)
|
||||
sys.exit()
|
||||
|
||||
|
||||
class Dict(dict):
|
||||
def __repr__(self):
|
||||
return '{%s}' % ',\n '.join('%r: %r' % i for i in sorted(self.items()))
|
||||
|
||||
|
||||
def docopt(doc, argv=None, help=True, version=None, options_first=False):
|
||||
"""Parse `argv` based on command-line interface described in `doc`.
|
||||
|
||||
`docopt` creates your command-line interface based on its
|
||||
description that you pass as `doc`. Such description can contain
|
||||
--options, <positional-argument>, commands, which could be
|
||||
[optional], (required), (mutually | exclusive) or repeated...
|
||||
|
||||
Parameters
|
||||
----------
|
||||
doc : str
|
||||
Description of your command-line interface.
|
||||
argv : list of str, optional
|
||||
Argument vector to be parsed. sys.argv[1:] is used if not
|
||||
provided.
|
||||
help : bool (default: True)
|
||||
Set to False to disable automatic help on -h or --help
|
||||
options.
|
||||
version : any object
|
||||
If passed, the object will be printed if --version is in
|
||||
`argv`.
|
||||
options_first : bool (default: False)
|
||||
Set to True to require options preceed positional arguments,
|
||||
i.e. to forbid options and positional arguments intermix.
|
||||
|
||||
Returns
|
||||
-------
|
||||
args : dict
|
||||
A dictionary, where keys are names of command-line elements
|
||||
such as e.g. "--verbose" and "<path>", and values are the
|
||||
parsed values of those elements.
|
||||
|
||||
Example
|
||||
-------
|
||||
>>> from docopt import docopt
|
||||
>>> doc = '''
|
||||
Usage:
|
||||
my_program tcp <host> <port> [--timeout=<seconds>]
|
||||
my_program serial <port> [--baud=<n>] [--timeout=<seconds>]
|
||||
my_program (-h | --help | --version)
|
||||
|
||||
Options:
|
||||
-h, --help Show this screen and exit.
|
||||
--baud=<n> Baudrate [default: 9600]
|
||||
'''
|
||||
>>> argv = ['tcp', '127.0.0.1', '80', '--timeout', '30']
|
||||
>>> docopt(doc, argv)
|
||||
{'--baud': '9600',
|
||||
'--help': False,
|
||||
'--timeout': '30',
|
||||
'--version': False,
|
||||
'<host>': '127.0.0.1',
|
||||
'<port>': '80',
|
||||
'serial': False,
|
||||
'tcp': True}
|
||||
|
||||
See also
|
||||
--------
|
||||
* For video introduction see http://docopt.org
|
||||
* Full documentation is available in README.rst as well as online
|
||||
at https://github.com/docopt/docopt#readme
|
||||
|
||||
"""
|
||||
if argv is None:
|
||||
argv = sys.argv[1:]
|
||||
DocoptExit.usage = printable_usage(doc)
|
||||
options = parse_defaults(doc)
|
||||
pattern = parse_pattern(formal_usage(DocoptExit.usage), options)
|
||||
# [default] syntax for argument is disabled
|
||||
#for a in pattern.flat(Argument):
|
||||
# same_name = [d for d in arguments if d.name == a.name]
|
||||
# if same_name:
|
||||
# a.value = same_name[0].value
|
||||
argv = parse_argv(TokenStream(argv, DocoptExit), list(options),
|
||||
options_first)
|
||||
pattern_options = set(pattern.flat(Option))
|
||||
for ao in pattern.flat(AnyOptions):
|
||||
doc_options = parse_defaults(doc)
|
||||
ao.children = list(set(doc_options) - pattern_options)
|
||||
#if any_options:
|
||||
# ao.children += [Option(o.short, o.long, o.argcount)
|
||||
# for o in argv if type(o) is Option]
|
||||
extras(help, version, argv, doc)
|
||||
matched, left, collected = pattern.fix().match(argv)
|
||||
if matched and left == []: # better error message if left?
|
||||
return Dict((a.name, a.value) for a in (pattern.flat() + collected))
|
||||
raise DocoptExit()
|
||||
Vendored
-202
@@ -1,202 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
__author__ = 'Vadim Kravcenko'
|
||||
__email__ = 'vadim.kravcenko@gmail.com'
|
||||
__version__ = '0.4.10'
|
||||
Vendored
-1142
File diff suppressed because it is too large
Load Diff
Vendored
-476
@@ -1,476 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""pipreqs - Generate pip requirements.txt file based on imports
|
||||
|
||||
Usage:
|
||||
pipreqs [options] [<path>]
|
||||
|
||||
Arguments:
|
||||
<path> The path to the directory containing the application
|
||||
files for which a requirements file should be
|
||||
generated (defaults to the current working
|
||||
directory).
|
||||
|
||||
Options:
|
||||
--use-local Use ONLY local package info instead of querying PyPI.
|
||||
--pypi-server <url> Use custom PyPi server.
|
||||
--proxy <url> Use Proxy, parameter will be passed to requests
|
||||
library. You can also just set the environments
|
||||
parameter in your terminal:
|
||||
$ export HTTP_PROXY="http://10.10.1.10:3128"
|
||||
$ export HTTPS_PROXY="https://10.10.1.10:1080"
|
||||
--debug Print debug information.
|
||||
--ignore <dirs>... Ignore extra directories, each separated by a comma.
|
||||
--no-follow-links Do not follow symbolic links in the project
|
||||
--encoding <charset> Use encoding parameter for file open
|
||||
--savepath <file> Save the list of requirements in the given file
|
||||
--print Output the list of requirements in the standard
|
||||
output.
|
||||
--force Overwrite existing requirements.txt
|
||||
--diff <file> Compare modules in requirements.txt to project
|
||||
imports.
|
||||
--clean <file> Clean up requirements.txt by removing modules
|
||||
that are not imported in project.
|
||||
--no-pin Omit version of output packages.
|
||||
"""
|
||||
from __future__ import print_function, absolute_import
|
||||
from contextlib import contextmanager
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import logging
|
||||
import codecs
|
||||
import ast
|
||||
import traceback
|
||||
from pipenv.vendor.docopt import docopt
|
||||
import pipenv.vendor.requests as requests
|
||||
from pipenv.vendor.yarg import json2package
|
||||
from pipenv.vendor.yarg.exceptions import HTTPError
|
||||
|
||||
from pipenv.vendor.pipreqs import __version__
|
||||
|
||||
REGEXP = [
|
||||
re.compile(r'^import (.+)$'),
|
||||
re.compile(r'^from ((?!\.+).*?) import (?:.*)$')
|
||||
]
|
||||
|
||||
if sys.version_info[0] > 2:
|
||||
open_func = open
|
||||
py2 = False
|
||||
else:
|
||||
open_func = codecs.open
|
||||
py2 = True
|
||||
py2_exclude = ["concurrent", "concurrent.futures"]
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _open(filename=None, mode='r'):
|
||||
"""Open a file or ``sys.stdout`` depending on the provided filename.
|
||||
|
||||
Args:
|
||||
filename (str): The path to the file that should be opened. If
|
||||
``None`` or ``'-'``, ``sys.stdout`` or ``sys.stdin`` is
|
||||
returned depending on the desired mode. Defaults to ``None``.
|
||||
mode (str): The mode that should be used to open the file.
|
||||
|
||||
Yields:
|
||||
A file handle.
|
||||
|
||||
"""
|
||||
if not filename or filename == '-':
|
||||
if not mode or 'r' in mode:
|
||||
file = sys.stdin
|
||||
elif 'w' in mode:
|
||||
file = sys.stdout
|
||||
else:
|
||||
raise ValueError('Invalid mode for file: {}'.format(mode))
|
||||
else:
|
||||
file = open(filename, mode)
|
||||
|
||||
try:
|
||||
yield file
|
||||
finally:
|
||||
if file not in (sys.stdin, sys.stdout):
|
||||
file.close()
|
||||
|
||||
|
||||
def get_all_imports(
|
||||
path, encoding=None, extra_ignore_dirs=None, follow_links=True):
|
||||
imports = set()
|
||||
raw_imports = set()
|
||||
candidates = []
|
||||
ignore_errors = False
|
||||
ignore_dirs = [".hg", ".svn", ".git", ".tox", "__pycache__", "env", "venv"]
|
||||
|
||||
if extra_ignore_dirs:
|
||||
ignore_dirs_parsed = []
|
||||
for e in extra_ignore_dirs:
|
||||
ignore_dirs_parsed.append(os.path.basename(os.path.realpath(e)))
|
||||
ignore_dirs.extend(ignore_dirs_parsed)
|
||||
|
||||
walk = os.walk(path, followlinks=follow_links)
|
||||
for root, dirs, files in walk:
|
||||
dirs[:] = [d for d in dirs if d not in ignore_dirs]
|
||||
|
||||
candidates.append(os.path.basename(root))
|
||||
files = [fn for fn in files if os.path.splitext(fn)[1] == ".py"]
|
||||
|
||||
candidates += [os.path.splitext(fn)[0] for fn in files]
|
||||
for file_name in files:
|
||||
file_name = os.path.join(root, file_name)
|
||||
with open_func(file_name, "r", encoding=encoding) as f:
|
||||
contents = f.read()
|
||||
try:
|
||||
tree = ast.parse(contents)
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Import):
|
||||
for subnode in node.names:
|
||||
raw_imports.add(subnode.name)
|
||||
elif isinstance(node, ast.ImportFrom):
|
||||
raw_imports.add(node.module)
|
||||
except Exception as exc:
|
||||
if ignore_errors:
|
||||
traceback.print_exc(exc)
|
||||
logging.warn("Failed on file: %s" % file_name)
|
||||
continue
|
||||
else:
|
||||
logging.error("Failed on file: %s" % file_name)
|
||||
raise exc
|
||||
|
||||
# Clean up imports
|
||||
for name in [n for n in raw_imports if n]:
|
||||
# Sanity check: Name could have been None if the import
|
||||
# statement was as ``from . import X``
|
||||
# Cleanup: We only want to first part of the import.
|
||||
# Ex: from django.conf --> django.conf. But we only want django
|
||||
# as an import.
|
||||
cleaned_name, _, _ = name.partition('.')
|
||||
imports.add(cleaned_name)
|
||||
|
||||
packages = imports - (set(candidates) & imports)
|
||||
logging.debug('Found packages: {0}'.format(packages))
|
||||
|
||||
with open(join("stdlib"), "r") as f:
|
||||
data = {x.strip() for x in f}
|
||||
|
||||
data = {x for x in data if x not in py2_exclude} if py2 else data
|
||||
return list(packages - data)
|
||||
|
||||
|
||||
def filter_line(l):
|
||||
return len(l) > 0 and l[0] != "#"
|
||||
|
||||
|
||||
def generate_requirements_file(path, imports):
|
||||
with _open(path, "w") as out_file:
|
||||
logging.debug('Writing {num} requirements: {imports} to {file}'.format(
|
||||
num=len(imports),
|
||||
file=path,
|
||||
imports=", ".join([x['name'] for x in imports])
|
||||
))
|
||||
fmt = '{name}=={version}'
|
||||
out_file.write('\n'.join(
|
||||
fmt.format(**item) if item['version'] else '{name}'.format(**item)
|
||||
for item in imports) + '\n')
|
||||
|
||||
|
||||
def output_requirements(imports):
|
||||
generate_requirements_file('-', imports)
|
||||
|
||||
|
||||
def get_imports_info(
|
||||
imports, pypi_server="https://pypi.python.org/pypi/", proxy=None):
|
||||
result = []
|
||||
|
||||
for item in imports:
|
||||
try:
|
||||
response = requests.get(
|
||||
"{0}{1}/json".format(pypi_server, item), proxies=proxy)
|
||||
if response.status_code == 200:
|
||||
if hasattr(response.content, 'decode'):
|
||||
data = json2package(response.content.decode())
|
||||
else:
|
||||
data = json2package(response.content)
|
||||
elif response.status_code >= 300:
|
||||
raise HTTPError(status_code=response.status_code,
|
||||
reason=response.reason)
|
||||
except HTTPError:
|
||||
logging.debug(
|
||||
'Package %s does not exist or network problems', item)
|
||||
continue
|
||||
result.append({'name': item, 'version': data.latest_release_id})
|
||||
return result
|
||||
|
||||
|
||||
def get_locally_installed_packages(encoding=None):
|
||||
packages = {}
|
||||
ignore = ["tests", "_tests", "egg", "EGG", "info"]
|
||||
for path in sys.path:
|
||||
for root, dirs, files in os.walk(path):
|
||||
for item in files:
|
||||
if "top_level" in item:
|
||||
item = os.path.join(root, item)
|
||||
with open_func(item, "r", encoding=encoding) as f:
|
||||
package = root.split(os.sep)[-1].split("-")
|
||||
try:
|
||||
package_import = f.read().strip().split("\n")
|
||||
except: # NOQA
|
||||
# TODO: What errors do we intend to suppress here?
|
||||
continue
|
||||
for i_item in package_import:
|
||||
if ((i_item not in ignore) and
|
||||
(package[0] not in ignore)):
|
||||
version = None
|
||||
if len(package) > 1:
|
||||
version = package[1].replace(
|
||||
".dist", "").replace(".egg", "")
|
||||
|
||||
packages[i_item] = {
|
||||
'version': version,
|
||||
'name': package[0]
|
||||
}
|
||||
return packages
|
||||
|
||||
|
||||
def get_import_local(imports, encoding=None):
|
||||
local = get_locally_installed_packages()
|
||||
result = []
|
||||
for item in imports:
|
||||
if item.lower() in local:
|
||||
result.append(local[item.lower()])
|
||||
|
||||
# removing duplicates of package/version
|
||||
result_unique = [
|
||||
dict(t)
|
||||
for t in set([
|
||||
tuple(d.items()) for d in result
|
||||
])
|
||||
]
|
||||
|
||||
return result_unique
|
||||
|
||||
|
||||
def get_pkg_names(pkgs):
|
||||
"""Get PyPI package names from a list of imports.
|
||||
|
||||
Args:
|
||||
pkgs (List[str]): List of import names.
|
||||
|
||||
Returns:
|
||||
List[str]: The corresponding PyPI package names.
|
||||
|
||||
"""
|
||||
result = set()
|
||||
with open(join("mapping"), "r") as f:
|
||||
data = dict(x.strip().split(":") for x in f)
|
||||
for pkg in pkgs:
|
||||
# Look up the mapped requirement. If a mapping isn't found,
|
||||
# simply use the package name.
|
||||
result.add(data.get(pkg, pkg))
|
||||
# Return a sorted list for backward compatibility.
|
||||
return sorted(result, key=lambda s: s.lower())
|
||||
|
||||
|
||||
def get_name_without_alias(name):
|
||||
if "import " in name:
|
||||
match = REGEXP[0].match(name.strip())
|
||||
if match:
|
||||
name = match.groups(0)[0]
|
||||
return name.partition(' as ')[0].partition('.')[0].strip()
|
||||
|
||||
|
||||
def join(f):
|
||||
return os.path.join(os.path.dirname(__file__), f)
|
||||
|
||||
|
||||
def parse_requirements(file_):
|
||||
"""Parse a requirements formatted file.
|
||||
|
||||
Traverse a string until a delimiter is detected, then split at said
|
||||
delimiter, get module name by element index, create a dict consisting of
|
||||
module:version, and add dict to list of parsed modules.
|
||||
|
||||
Args:
|
||||
file_: File to parse.
|
||||
|
||||
Raises:
|
||||
OSerror: If there's any issues accessing the file.
|
||||
|
||||
Returns:
|
||||
tuple: The contents of the file, excluding comments.
|
||||
"""
|
||||
modules = []
|
||||
# For the dependency identifier specification, see
|
||||
# https://www.python.org/dev/peps/pep-0508/#complete-grammar
|
||||
delim = ["<", ">", "=", "!", "~"]
|
||||
|
||||
try:
|
||||
f = open_func(file_, "r")
|
||||
except OSError:
|
||||
logging.error("Failed on file: {}".format(file_))
|
||||
raise
|
||||
else:
|
||||
try:
|
||||
data = [x.strip() for x in f.readlines() if x != "\n"]
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
data = [x for x in data if x[0].isalpha()]
|
||||
|
||||
for x in data:
|
||||
# Check for modules w/o a specifier.
|
||||
if not any([y in x for y in delim]):
|
||||
modules.append({"name": x, "version": None})
|
||||
for y in x:
|
||||
if y in delim:
|
||||
module = x.split(y)
|
||||
module_name = module[0]
|
||||
module_version = module[-1].replace("=", "")
|
||||
module = {"name": module_name, "version": module_version}
|
||||
|
||||
if module not in modules:
|
||||
modules.append(module)
|
||||
|
||||
break
|
||||
|
||||
return modules
|
||||
|
||||
|
||||
def compare_modules(file_, imports):
|
||||
"""Compare modules in a file to imported modules in a project.
|
||||
|
||||
Args:
|
||||
file_ (str): File to parse for modules to be compared.
|
||||
imports (tuple): Modules being imported in the project.
|
||||
|
||||
Returns:
|
||||
tuple: The modules not imported in the project, but do exist in the
|
||||
specified file.
|
||||
"""
|
||||
modules = parse_requirements(file_)
|
||||
|
||||
imports = [imports[i]["name"] for i in range(len(imports))]
|
||||
modules = [modules[i]["name"] for i in range(len(modules))]
|
||||
modules_not_imported = set(modules) - set(imports)
|
||||
|
||||
return modules_not_imported
|
||||
|
||||
|
||||
def diff(file_, imports):
|
||||
"""Display the difference between modules in a file and imported modules.""" # NOQA
|
||||
modules_not_imported = compare_modules(file_, imports)
|
||||
|
||||
logging.info(
|
||||
"The following modules are in {} but do not seem to be imported: "
|
||||
"{}".format(file_, ", ".join(x for x in modules_not_imported)))
|
||||
|
||||
|
||||
def clean(file_, imports):
|
||||
"""Remove modules that aren't imported in project from file."""
|
||||
modules_not_imported = compare_modules(file_, imports)
|
||||
re_remove = re.compile("|".join(modules_not_imported))
|
||||
to_write = []
|
||||
|
||||
try:
|
||||
f = open_func(file_, "r+")
|
||||
except OSError:
|
||||
logging.error("Failed on file: {}".format(file_))
|
||||
raise
|
||||
else:
|
||||
try:
|
||||
for i in f.readlines():
|
||||
if re_remove.match(i) is None:
|
||||
to_write.append(i)
|
||||
f.seek(0)
|
||||
f.truncate()
|
||||
|
||||
for i in to_write:
|
||||
f.write(i)
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
logging.info("Successfully cleaned up requirements in " + file_)
|
||||
|
||||
|
||||
def init(args):
|
||||
encoding = args.get('--encoding')
|
||||
extra_ignore_dirs = args.get('--ignore')
|
||||
follow_links = not args.get('--no-follow-links')
|
||||
input_path = args['<path>']
|
||||
if input_path is None:
|
||||
input_path = os.path.abspath(os.curdir)
|
||||
|
||||
if extra_ignore_dirs:
|
||||
extra_ignore_dirs = extra_ignore_dirs.split(',')
|
||||
|
||||
candidates = get_all_imports(input_path,
|
||||
encoding=encoding,
|
||||
extra_ignore_dirs=extra_ignore_dirs,
|
||||
follow_links=follow_links)
|
||||
candidates = get_pkg_names(candidates)
|
||||
logging.debug("Found imports: " + ", ".join(candidates))
|
||||
pypi_server = "https://pypi.python.org/pypi/"
|
||||
proxy = None
|
||||
if args["--pypi-server"]:
|
||||
pypi_server = args["--pypi-server"]
|
||||
|
||||
if args["--proxy"]:
|
||||
proxy = {'http': args["--proxy"], 'https': args["--proxy"]}
|
||||
|
||||
if args["--use-local"]:
|
||||
logging.debug(
|
||||
"Getting package information ONLY from local installation.")
|
||||
imports = get_import_local(candidates, encoding=encoding)
|
||||
else:
|
||||
logging.debug("Getting packages information from Local/PyPI")
|
||||
local = get_import_local(candidates, encoding=encoding)
|
||||
# Get packages that were not found locally
|
||||
difference = [x for x in candidates
|
||||
if x.lower() not in [z['name'].lower() for z in local]]
|
||||
imports = local + get_imports_info(difference,
|
||||
proxy=proxy,
|
||||
pypi_server=pypi_server)
|
||||
|
||||
path = (args["--savepath"] if args["--savepath"] else
|
||||
os.path.join(input_path, "requirements.txt"))
|
||||
|
||||
if args["--diff"]:
|
||||
diff(args["--diff"], imports)
|
||||
return
|
||||
|
||||
if args["--clean"]:
|
||||
clean(args["--clean"], imports)
|
||||
return
|
||||
|
||||
if (not args["--print"]
|
||||
and not args["--savepath"]
|
||||
and not args["--force"]
|
||||
and os.path.exists(path)):
|
||||
logging.warning("Requirements.txt already exists, "
|
||||
"use --force to overwrite it")
|
||||
return
|
||||
|
||||
if args.get('--no-pin'):
|
||||
imports = [{'name': item["name"], 'version': ''} for item in imports]
|
||||
|
||||
if args["--print"]:
|
||||
output_requirements(imports)
|
||||
logging.info("Successfully output requirements")
|
||||
else:
|
||||
generate_requirements_file(path, imports)
|
||||
logging.info("Successfully saved requirements file in " + path)
|
||||
|
||||
|
||||
def main(): # pragma: no cover
|
||||
args = docopt(__doc__, version=__version__)
|
||||
log_level = logging.DEBUG if args['--debug'] else logging.INFO
|
||||
logging.basicConfig(level=log_level, format='%(levelname)s: %(message)s')
|
||||
|
||||
try:
|
||||
init(args)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main() # pragma: no cover
|
||||
Vendored
-495
@@ -1,495 +0,0 @@
|
||||
__builtin__
|
||||
__future__
|
||||
__main__
|
||||
_dummy_thread
|
||||
_thread
|
||||
_winreg
|
||||
abc
|
||||
aepack
|
||||
aetools
|
||||
aetypes
|
||||
aifc
|
||||
AL
|
||||
al
|
||||
anydbm
|
||||
applesingle
|
||||
argparse
|
||||
array
|
||||
ast
|
||||
asynchat
|
||||
asyncio
|
||||
asyncore
|
||||
atexit
|
||||
audioop
|
||||
autoGIL
|
||||
base64
|
||||
BaseHTTPServer
|
||||
Bastion
|
||||
bdb
|
||||
binascii
|
||||
binhex
|
||||
bisect
|
||||
bsddb
|
||||
buildtools
|
||||
builtins
|
||||
bz2
|
||||
calendar
|
||||
Carbon
|
||||
Carbon.AE
|
||||
Carbon.AH
|
||||
Carbon.App
|
||||
Carbon.Appearance
|
||||
Carbon.CarbonEvents
|
||||
Carbon.CarbonEvt
|
||||
Carbon.CF
|
||||
Carbon.CG
|
||||
Carbon.Cm
|
||||
Carbon.Components
|
||||
Carbon.ControlAccessor
|
||||
Carbon.Controls
|
||||
Carbon.CoreFounation
|
||||
Carbon.CoreGraphics
|
||||
Carbon.Ctl
|
||||
Carbon.Dialogs
|
||||
Carbon.Dlg
|
||||
Carbon.Drag
|
||||
Carbon.Dragconst
|
||||
Carbon.Events
|
||||
Carbon.Evt
|
||||
Carbon.File
|
||||
Carbon.Files
|
||||
Carbon.Fm
|
||||
Carbon.Folder
|
||||
Carbon.Folders
|
||||
Carbon.Fonts
|
||||
Carbon.Help
|
||||
Carbon.IBCarbon
|
||||
Carbon.IBCarbonRuntime
|
||||
Carbon.Icns
|
||||
Carbon.Icons
|
||||
Carbon.Launch
|
||||
Carbon.LaunchServices
|
||||
Carbon.List
|
||||
Carbon.Lists
|
||||
Carbon.MacHelp
|
||||
Carbon.MediaDescr
|
||||
Carbon.Menu
|
||||
Carbon.Menus
|
||||
Carbon.Mlte
|
||||
Carbon.OSA
|
||||
Carbon.OSAconst
|
||||
Carbon.Qd
|
||||
Carbon.Qdoffs
|
||||
Carbon.QDOffscreen
|
||||
Carbon.Qt
|
||||
Carbon.QuickDraw
|
||||
Carbon.QuickTime
|
||||
Carbon.Res
|
||||
Carbon.Resources
|
||||
Carbon.Scrap
|
||||
Carbon.Snd
|
||||
Carbon.Sound
|
||||
Carbon.TE
|
||||
Carbon.TextEdit
|
||||
Carbon.Win
|
||||
Carbon.Windows
|
||||
cd
|
||||
cfmfile
|
||||
cgi
|
||||
CGIHTTPServer
|
||||
cgitb
|
||||
chunk
|
||||
cmath
|
||||
cmd
|
||||
code
|
||||
codecs
|
||||
codeop
|
||||
collections
|
||||
collections.abc
|
||||
ColorPicker
|
||||
colorsys
|
||||
commands
|
||||
compileall
|
||||
compiler
|
||||
compiler.ast
|
||||
compiler.visitor
|
||||
concurrent
|
||||
concurrent.futures
|
||||
ConfigParser
|
||||
configparser
|
||||
contextlib
|
||||
Cookie
|
||||
cookielib
|
||||
copy
|
||||
copy_reg
|
||||
copyreg
|
||||
cPickle
|
||||
cProfile
|
||||
crypt
|
||||
cStringIO
|
||||
csv
|
||||
ctypes
|
||||
curses
|
||||
curses.ascii
|
||||
curses.panel
|
||||
curses.textpad
|
||||
datetime
|
||||
dbhash
|
||||
dbm
|
||||
dbm.dumb
|
||||
dbm.gnu
|
||||
dbm.ndbm
|
||||
decimal
|
||||
DEVICE
|
||||
difflib
|
||||
dircache
|
||||
dis
|
||||
distutils
|
||||
distutils.archive_util
|
||||
distutils.bcppcompiler
|
||||
distutils.ccompiler
|
||||
distutils.cmd
|
||||
distutils.command
|
||||
distutils.command.bdist
|
||||
distutils.command.bdist_dumb
|
||||
distutils.command.bdist_msi
|
||||
distutils.command.bdist_packager
|
||||
distutils.command.bdist_rpm
|
||||
distutils.command.bdist_wininst
|
||||
distutils.command.build
|
||||
distutils.command.build_clib
|
||||
distutils.command.build_ext
|
||||
distutils.command.build_py
|
||||
distutils.command.build_scripts
|
||||
distutils.command.check
|
||||
distutils.command.clean
|
||||
distutils.command.config
|
||||
distutils.command.install
|
||||
distutils.command.install_data
|
||||
distutils.command.install_headers
|
||||
distutils.command.install_lib
|
||||
distutils.command.install_scripts
|
||||
distutils.command.register
|
||||
distutils.command.sdist
|
||||
distutils.core
|
||||
distutils.cygwinccompiler
|
||||
distutils.debug
|
||||
distutils.dep_util
|
||||
distutils.dir_util
|
||||
distutils.dist
|
||||
distutils.emxccompiler
|
||||
distutils.errors
|
||||
distutils.extension
|
||||
distutils.fancy_getopt
|
||||
distutils.file_util
|
||||
distutils.filelist
|
||||
distutils.log
|
||||
distutils.msvccompiler
|
||||
distutils.spawn
|
||||
distutils.sysconfig
|
||||
distutils.text_file
|
||||
distutils.unixccompiler
|
||||
distutils.util
|
||||
distutils.version
|
||||
dl
|
||||
doctest
|
||||
DocXMLRPCServer
|
||||
dumbdbm
|
||||
dummy_thread
|
||||
dummy_threading
|
||||
EasyDialogs
|
||||
email
|
||||
email.charset
|
||||
email.contentmanager
|
||||
email.encoders
|
||||
email.errors
|
||||
email.generator
|
||||
email.header
|
||||
email.headerregistry
|
||||
email.iterators
|
||||
email.message
|
||||
email.mime
|
||||
email.parser
|
||||
email.policy
|
||||
email.utils
|
||||
encodings
|
||||
encodings.idna
|
||||
encodings.mbcs
|
||||
encodings.utf_8_sig
|
||||
ensurepip
|
||||
enum
|
||||
errno
|
||||
exceptions
|
||||
faulthandler
|
||||
fcntl
|
||||
filecmp
|
||||
fileinput
|
||||
findertools
|
||||
FL
|
||||
fl
|
||||
flp
|
||||
fm
|
||||
fnmatch
|
||||
formatter
|
||||
fpectl
|
||||
fpformat
|
||||
fractions
|
||||
FrameWork
|
||||
ftplib
|
||||
functools
|
||||
future_builtins
|
||||
gc
|
||||
gdbm
|
||||
gensuitemodule
|
||||
getopt
|
||||
getpass
|
||||
gettext
|
||||
GL
|
||||
gl
|
||||
glob
|
||||
grp
|
||||
gzip
|
||||
hashlib
|
||||
heapq
|
||||
hmac
|
||||
hotshot
|
||||
hotshot.stats
|
||||
html
|
||||
html.entities
|
||||
html.parser
|
||||
htmlentitydefs
|
||||
htmllib
|
||||
HTMLParser
|
||||
http
|
||||
http.client
|
||||
http.cookiejar
|
||||
http.cookies
|
||||
http.server
|
||||
httplib
|
||||
ic
|
||||
icopen
|
||||
imageop
|
||||
imaplib
|
||||
imgfile
|
||||
imghdr
|
||||
imp
|
||||
importlib
|
||||
importlib.abc
|
||||
importlib.machinery
|
||||
importlib.util
|
||||
imputil
|
||||
inspect
|
||||
io
|
||||
ipaddress
|
||||
itertools
|
||||
jpeg
|
||||
json
|
||||
json.tool
|
||||
keyword
|
||||
lib2to3
|
||||
linecache
|
||||
locale
|
||||
logging
|
||||
logging.config
|
||||
logging.handlers
|
||||
lzma
|
||||
macerrors
|
||||
MacOS
|
||||
macostools
|
||||
macpath
|
||||
macresource
|
||||
mailbox
|
||||
mailcap
|
||||
marshal
|
||||
math
|
||||
md5
|
||||
mhlib
|
||||
mimetools
|
||||
mimetypes
|
||||
MimeWriter
|
||||
mimify
|
||||
MiniAEFrame
|
||||
mmap
|
||||
modulefinder
|
||||
msilib
|
||||
msvcrt
|
||||
multifile
|
||||
multiprocessing
|
||||
multiprocessing.connection
|
||||
multiprocessing.dummy
|
||||
multiprocessing.managers
|
||||
multiprocessing.pool
|
||||
multiprocessing.sharedctypes
|
||||
mutex
|
||||
Nav
|
||||
netrc
|
||||
new
|
||||
nis
|
||||
nntplib
|
||||
numbers
|
||||
operator
|
||||
optparse
|
||||
os
|
||||
os.path
|
||||
ossaudiodev
|
||||
parser
|
||||
pathlib
|
||||
pdb
|
||||
pickle
|
||||
pickletools
|
||||
pipes
|
||||
PixMapWrapper
|
||||
pkg_resources
|
||||
pkgutil
|
||||
platform
|
||||
plistlib
|
||||
popen2
|
||||
poplib
|
||||
posix
|
||||
posixfile
|
||||
pprint
|
||||
profile
|
||||
pstats
|
||||
pty
|
||||
pwd
|
||||
py_compile
|
||||
pyclbr
|
||||
pydoc
|
||||
Queue
|
||||
queue
|
||||
quopri
|
||||
random
|
||||
re
|
||||
readline
|
||||
reprlib
|
||||
resource
|
||||
rexec
|
||||
rfc822
|
||||
rlcompleter
|
||||
robotparser
|
||||
runpy
|
||||
sched
|
||||
ScrolledText
|
||||
select
|
||||
selectors
|
||||
sets
|
||||
setuptools
|
||||
sgmllib
|
||||
sha
|
||||
shelve
|
||||
shlex
|
||||
shutil
|
||||
signal
|
||||
SimpleHTTPServer
|
||||
SimpleXMLRPCServer
|
||||
site
|
||||
smtpd
|
||||
smtplib
|
||||
sndhdr
|
||||
socket
|
||||
SocketServer
|
||||
socketserver
|
||||
spwd
|
||||
sqlite3
|
||||
ssl
|
||||
stat
|
||||
statistics
|
||||
statvfs
|
||||
string
|
||||
StringIO
|
||||
stringprep
|
||||
struct
|
||||
subprocess
|
||||
sunau
|
||||
SUNAUDIODEV
|
||||
sunaudiodev
|
||||
symbol
|
||||
symtable
|
||||
sys
|
||||
sysconfig
|
||||
syslog
|
||||
tabnanny
|
||||
tarfile
|
||||
telnetlib
|
||||
tempfile
|
||||
termios
|
||||
test
|
||||
test.support
|
||||
test.test_support
|
||||
textwrap
|
||||
thread
|
||||
threading
|
||||
time
|
||||
timeit
|
||||
Tix
|
||||
Tkinter
|
||||
tkinter
|
||||
tkinter.scrolledtext
|
||||
tkinter.tix
|
||||
tkinter.ttk
|
||||
token
|
||||
tokenize
|
||||
trace
|
||||
traceback
|
||||
tracemalloc
|
||||
ttk
|
||||
tty
|
||||
turtle
|
||||
turtledemo
|
||||
types
|
||||
typing
|
||||
unicodedata
|
||||
unittest
|
||||
unittest.mock
|
||||
urllib
|
||||
urllib.error
|
||||
urllib.parse
|
||||
urllib.request
|
||||
urllib.response
|
||||
urllib.robotparser
|
||||
urllib2
|
||||
urlparse
|
||||
user
|
||||
UserDict
|
||||
UserList
|
||||
UserString
|
||||
uu
|
||||
uuid
|
||||
venv
|
||||
videoreader
|
||||
W
|
||||
warnings
|
||||
wave
|
||||
weakref
|
||||
webbrowser
|
||||
whichdb
|
||||
winreg
|
||||
winsound
|
||||
wsgiref
|
||||
wsgiref.handlers
|
||||
wsgiref.headers
|
||||
wsgiref.simple_server
|
||||
wsgiref.util
|
||||
wsgiref.validate
|
||||
xdrlib
|
||||
xml
|
||||
xml.dom
|
||||
xml.dom.minidom
|
||||
xml.dom.pulldom
|
||||
xml.etree.ElementTree
|
||||
xml.parsers.expat
|
||||
xml.parsers.expat.errors
|
||||
xml.parsers.expat.model
|
||||
xml.sax
|
||||
xml.sax.handler
|
||||
xml.sax.saxutils
|
||||
xml.sax.xmlreader
|
||||
xmlrpc
|
||||
xmlrpc.client
|
||||
xmlrpc.server
|
||||
xmlrpclib
|
||||
yp
|
||||
zipapp
|
||||
zipfile
|
||||
zipimport
|
||||
zlib
|
||||
Vendored
-3
@@ -8,7 +8,6 @@ click-didyoumean==0.0.3
|
||||
click==8.0.3
|
||||
colorama==0.4.4
|
||||
distlib==0.3.2
|
||||
docopt==0.6.2
|
||||
dparse==0.5.1
|
||||
funcsigs==1.0.2
|
||||
idna==3.2
|
||||
@@ -24,7 +23,6 @@ pep517==0.11.0
|
||||
pexpect==4.8.0
|
||||
pip-shims==0.6.0
|
||||
pipdeptree==2.0.0
|
||||
pipreqs==0.4.10
|
||||
platformdirs==2.4.0
|
||||
plette[validation]==0.2.3
|
||||
ptyprocess==0.7.0
|
||||
@@ -43,6 +41,5 @@ tomlkit==0.7.2
|
||||
urllib3==1.26.6
|
||||
vistir==0.5.2
|
||||
wheel==0.36.2
|
||||
yarg==0.1.9
|
||||
yaspin==2.0.0
|
||||
zipp==3.5.0
|
||||
|
||||
Vendored
-20
@@ -1,20 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2014 Kura
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
Copyright 2014 Kenneth Reitz
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
__title__ = 'yarg'
|
||||
__version__ = '0.1.9'
|
||||
__author__ = 'Kura'
|
||||
__email__ = 'kura@kura.io'
|
||||
__url__ = 'https://yarg.readthedocs.org/'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright 2014 Kura'
|
||||
Vendored
-56
@@ -1,56 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (The MIT License)
|
||||
#
|
||||
# Copyright (c) 2014 Kura
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the 'Software'), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
"""
|
||||
yarg(1) -- A semi hard Cornish cheese, also queries PyPI
|
||||
========================================================
|
||||
|
||||
Yarg is a PyPI client.
|
||||
|
||||
>>> import yarg
|
||||
>>>
|
||||
>>> package = yarg.get("yarg")
|
||||
>>> package.name
|
||||
u'yarg'
|
||||
>>> package.author
|
||||
Author(name=u'Kura', email=u'kura@kura.io')
|
||||
>>>
|
||||
>>> yarg.newest_packages()
|
||||
[<Package yarg>, <Package gray>, <Package ragy>]
|
||||
>>>
|
||||
>>> yarg.latest_updated_packages()
|
||||
[<Package yarg>, <Package gray>, <Package ragy>]
|
||||
|
||||
Full documentation is at <https://yarg.readthedocs.org>.
|
||||
"""
|
||||
|
||||
|
||||
from .client import get
|
||||
from .exceptions import HTTPError
|
||||
from .package import json2package
|
||||
from .parse import (newest_packages, latest_updated_packages)
|
||||
|
||||
|
||||
__all__ = ['get', 'HTTPError', 'json2package', 'newest_packages',
|
||||
'latest_updated_packages', ]
|
||||
Vendored
-54
@@ -1,54 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (The MIT License)
|
||||
#
|
||||
# Copyright (c) 2014 Kura
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the 'Software'), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
import pipenv.vendor.requests as requests
|
||||
|
||||
from .exceptions import HTTPError
|
||||
from .package import json2package
|
||||
|
||||
|
||||
def get(package_name, pypi_server="https://pypi.python.org/pypi/"):
|
||||
"""
|
||||
Constructs a request to the PyPI server and returns a
|
||||
:class:`yarg.package.Package`.
|
||||
|
||||
:param package_name: case sensitive name of the package on the PyPI server.
|
||||
:param pypi_server: (option) URL to the PyPI server.
|
||||
|
||||
>>> import yarg
|
||||
>>> package = yarg.get('yarg')
|
||||
<Package yarg>
|
||||
"""
|
||||
if not pypi_server.endswith("/"):
|
||||
pypi_server = pypi_server + "/"
|
||||
response = requests.get("{0}{1}/json".format(pypi_server,
|
||||
package_name))
|
||||
if response.status_code >= 300:
|
||||
raise HTTPError(status_code=response.status_code,
|
||||
reason=response.reason)
|
||||
if hasattr(response.content, 'decode'):
|
||||
return json2package(response.content.decode())
|
||||
else:
|
||||
return json2package(response.content)
|
||||
Vendored
-58
@@ -1,58 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (The MIT License)
|
||||
#
|
||||
# Copyright (c) 2014 Kura
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the 'Software'), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from pipenv.vendor.requests.exceptions import HTTPError as RHTTPError
|
||||
|
||||
|
||||
class YargException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class HTTPError(YargException, RHTTPError):
|
||||
"""
|
||||
A catchall HTTPError exception to handle HTTP errors
|
||||
when using :meth:`yarg.get`.
|
||||
|
||||
This exception is also loaded at :class:`yarg.HTTPError`
|
||||
for ease of access.
|
||||
|
||||
:member: status_code
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
for key, val in kwargs.items():
|
||||
setattr(self, key, val)
|
||||
if hasattr(self, 'status_code'):
|
||||
setattr(self, 'errno', self.status_code)
|
||||
if hasattr(self, 'reason'):
|
||||
setattr(self, 'message', self.reason)
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def __repr__(self):
|
||||
if hasattr(self, 'status_code') and hasattr(self, 'reason'):
|
||||
return "<HTTPError {0} {1}>".format(self.status_code, self.reason)
|
||||
return "<HTTPError>"
|
||||
Vendored
-324
@@ -1,324 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (The MIT License)
|
||||
#
|
||||
# Copyright (c) 2014 Kura
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the 'Software'), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json
|
||||
from collections import namedtuple
|
||||
import re
|
||||
|
||||
from .release import Release
|
||||
|
||||
|
||||
class Package(object):
|
||||
"""
|
||||
A PyPI package.
|
||||
|
||||
:param pypi_dict: A dictionary retrieved from the PyPI server.
|
||||
"""
|
||||
|
||||
def __init__(self, pypi_dict):
|
||||
self._package = pypi_dict['info']
|
||||
self._releases = pypi_dict['releases']
|
||||
|
||||
def __repr__(self):
|
||||
return "<Package {0}>".format(self.name)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.name
|
||||
u'yarg'
|
||||
"""
|
||||
return self._package['name']
|
||||
|
||||
@property
|
||||
def pypi_url(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.url
|
||||
u'https://pypi.python.org/pypi/yarg'
|
||||
"""
|
||||
return self._package['package_url']
|
||||
|
||||
@property
|
||||
def summary(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.summary
|
||||
u'Some random summary stuff'
|
||||
"""
|
||||
return self._package['summary']
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.description
|
||||
u'A super long description, usually uploaded from the README'
|
||||
"""
|
||||
return self._package['description']
|
||||
|
||||
@property
|
||||
def homepage(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.homepage
|
||||
u'https://kura.io/yarg/'
|
||||
"""
|
||||
if ('home_page' not in self._package or
|
||||
self._package['home_page'] == ""):
|
||||
return None
|
||||
return self._package['home_page']
|
||||
|
||||
@property
|
||||
def bugtracker(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.bugtracker
|
||||
u'https://github.com/kura/yarg/issues'
|
||||
"""
|
||||
if ('bugtrack_url' not in self._package or
|
||||
self._package['bugtrack_url'] == ""):
|
||||
return None
|
||||
return self._package['bugtrack_url']
|
||||
|
||||
@property
|
||||
def docs(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.docs
|
||||
u'https://yarg.readthedocs.org/en/latest'
|
||||
"""
|
||||
if ('docs_url' not in self._package or
|
||||
self._package['docs_url'] == ""):
|
||||
return None
|
||||
return self._package['docs_url']
|
||||
|
||||
@property
|
||||
def author(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.author
|
||||
Author(name=u'Kura', email=u'kura@kura.io')
|
||||
"""
|
||||
author = namedtuple('Author', 'name email')
|
||||
return author(name=self._package['author'],
|
||||
email=self._package['author_email'])
|
||||
|
||||
@property
|
||||
def maintainer(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.maintainer
|
||||
Maintainer(name=u'Kura', email=u'kura@kura.io')
|
||||
"""
|
||||
maintainer = namedtuple('Maintainer', 'name email')
|
||||
return maintainer(name=self._package['maintainer'],
|
||||
email=self._package['maintainer_email'])
|
||||
|
||||
@property
|
||||
def license(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.license
|
||||
u'MIT'
|
||||
"""
|
||||
return self._package['license']
|
||||
|
||||
@property
|
||||
def license_from_classifiers(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.license_from_classifiers
|
||||
u'MIT License'
|
||||
"""
|
||||
if len(self.classifiers) > 0:
|
||||
for c in self.classifiers:
|
||||
if c.startswith("License"):
|
||||
return c.split(" :: ")[-1]
|
||||
|
||||
@property
|
||||
def downloads(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.downloads
|
||||
Downloads(day=50100, week=367941, month=1601938) # I wish
|
||||
"""
|
||||
_downloads = self._package['downloads']
|
||||
downloads = namedtuple('Downloads', 'day week month')
|
||||
return downloads(day=_downloads['last_day'],
|
||||
week=_downloads['last_week'],
|
||||
month=_downloads['last_month'])
|
||||
|
||||
@property
|
||||
def classifiers(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.classifiers
|
||||
[u'License :: OSI Approved :: MIT License',
|
||||
u'Programming Language :: Python :: 2.7',
|
||||
u'Programming Language :: Python :: 3.4']
|
||||
"""
|
||||
return self._package['classifiers']
|
||||
|
||||
@property
|
||||
def python_versions(self):
|
||||
"""
|
||||
Returns a list of Python version strings that
|
||||
the package has listed in :attr:`yarg.Release.classifiers`.
|
||||
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.python_versions
|
||||
[u'2.6', u'2.7', u'3.3', u'3.4']
|
||||
"""
|
||||
version_re = re.compile(r"""Programming Language \:\: """
|
||||
"""Python \:\: \d\.\d""")
|
||||
return [c.split(' :: ')[-1] for c in self.classifiers
|
||||
if version_re.match(c)]
|
||||
|
||||
@property
|
||||
def python_implementations(self):
|
||||
"""
|
||||
Returns a list of Python implementation strings that
|
||||
the package has listed in :attr:`yarg.Release.classifiers`.
|
||||
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.python_implementations
|
||||
[u'CPython', u'PyPy']
|
||||
"""
|
||||
return [c.split(' :: ')[-1] for c in self.classifiers
|
||||
if c.startswith("""Programming Language :: """
|
||||
"""Python :: Implementation""")]
|
||||
|
||||
@property
|
||||
def latest_release_id(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.latest_release_id
|
||||
u'0.1.0'
|
||||
"""
|
||||
return self._package['version']
|
||||
|
||||
@property
|
||||
def latest_release(self):
|
||||
"""
|
||||
A list of :class:`yarg.release.Release` objects for each file in the
|
||||
latest release.
|
||||
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.latest_release
|
||||
[<Release 0.1.0>, <Release 0.1.0>]
|
||||
"""
|
||||
release_id = self.latest_release_id
|
||||
return self.release(release_id)
|
||||
|
||||
@property
|
||||
def has_wheel(self):
|
||||
"""
|
||||
Returns `True` if one of the :class:`yarg.release.Release` objects
|
||||
in the latest set of release files is `wheel` format. Returns
|
||||
`False` if not.
|
||||
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.has_wheel
|
||||
True
|
||||
"""
|
||||
for release in self.latest_release:
|
||||
if release.package_type in ('wheel', 'bdist_wheel'):
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_egg(self):
|
||||
"""
|
||||
Returns `True` if one of the :class:`yarg.release.Release` objects
|
||||
in the latest set of release files is `egg` format. Returns
|
||||
`False` if not.
|
||||
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.has_egg
|
||||
False
|
||||
"""
|
||||
for release in self.latest_release:
|
||||
if release.package_type in ('egg', 'bdist_egg'):
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_source(self):
|
||||
"""
|
||||
Returns `True` if one of the :class:`yarg.release.Release` objects
|
||||
in the latest set of release files is `source` format. Returns
|
||||
`False` if not.
|
||||
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.has_source
|
||||
True
|
||||
"""
|
||||
for release in self.latest_release:
|
||||
if release.package_type in ('source', 'sdist'):
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def release_ids(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> package.release_ids
|
||||
[u'0.0.1', u'0.0.5', u'0.1.0']
|
||||
"""
|
||||
r = [(k, self._releases[k][0]['upload_time'])
|
||||
for k in self._releases.keys()
|
||||
if len(self._releases[k]) > 0]
|
||||
return [k[0] for k in sorted(r, key=lambda k: k[1])]
|
||||
|
||||
def release(self, release_id):
|
||||
"""
|
||||
A list of :class:`yarg.release.Release` objects for each file in a
|
||||
release.
|
||||
|
||||
:param release_id: A pypi release id.
|
||||
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> last_release = yarg.releases[-1]
|
||||
>>> package.release(last_release)
|
||||
[<Release 0.1.0>, <Release 0.1.0>]
|
||||
"""
|
||||
if release_id not in self.release_ids:
|
||||
return None
|
||||
return [Release(release_id, r) for r in self._releases[release_id]]
|
||||
|
||||
|
||||
def json2package(json_content):
|
||||
"""
|
||||
Returns a :class:`yarg.release.Release` object from JSON content from the
|
||||
PyPI server.
|
||||
|
||||
:param json_content: JSON encoded content from the PyPI server.
|
||||
"""
|
||||
return Package(json.loads(json_content))
|
||||
Vendored
-172
@@ -1,172 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (The MIT License)
|
||||
#
|
||||
# Copyright (c) 2014 Kura
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the 'Software'), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
from datetime import datetime
|
||||
import xml.etree.ElementTree
|
||||
|
||||
import pipenv.vendor.requests as requests
|
||||
|
||||
from .exceptions import HTTPError
|
||||
|
||||
|
||||
def _get(pypi_server):
|
||||
"""
|
||||
Query the PyPI RSS feed and return a list
|
||||
of XML items.
|
||||
"""
|
||||
response = requests.get(pypi_server)
|
||||
if response.status_code >= 300:
|
||||
raise HTTPError(status_code=response.status_code,
|
||||
reason=response.reason)
|
||||
if hasattr(response.content, 'decode'):
|
||||
tree = xml.etree.ElementTree.fromstring(response.content.decode())
|
||||
else:
|
||||
tree = xml.etree.ElementTree.fromstring(response.content)
|
||||
channel = tree.find('channel')
|
||||
return channel.findall('item')
|
||||
|
||||
|
||||
def newest_packages(
|
||||
pypi_server="https://pypi.python.org/pypi?%3Aaction=packages_rss"):
|
||||
"""
|
||||
Constructs a request to the PyPI server and returns a list of
|
||||
:class:`yarg.parse.Package`.
|
||||
|
||||
:param pypi_server: (option) URL to the PyPI server.
|
||||
|
||||
>>> import yarg
|
||||
>>> yarg.newest_packages()
|
||||
[<Package yarg>, <Package gray>, <Package ragy>]
|
||||
"""
|
||||
items = _get(pypi_server)
|
||||
i = []
|
||||
for item in items:
|
||||
i_dict = {'name': item[0].text.split()[0],
|
||||
'url': item[1].text,
|
||||
'description': item[3].text,
|
||||
'date': item[4].text}
|
||||
i.append(Package(i_dict))
|
||||
return i
|
||||
|
||||
|
||||
def latest_updated_packages(
|
||||
pypi_server="https://pypi.python.org/pypi?%3Aaction=rss"):
|
||||
"""
|
||||
Constructs a request to the PyPI server and returns a list of
|
||||
:class:`yarg.parse.Package`.
|
||||
|
||||
:param pypi_server: (option) URL to the PyPI server.
|
||||
|
||||
>>> import yarg
|
||||
>>> yarg.latest_updated_packages()
|
||||
[<Package yarg>, <Package gray>, <Package ragy>]
|
||||
"""
|
||||
items = _get(pypi_server)
|
||||
i = []
|
||||
for item in items:
|
||||
name, version = item[0].text.split()
|
||||
i_dict = {'name': name,
|
||||
'version': version,
|
||||
'url': item[1].text,
|
||||
'description': item[2].text,
|
||||
'date': item[3].text}
|
||||
i.append(Package(i_dict))
|
||||
return i
|
||||
|
||||
|
||||
class Package(object):
|
||||
"""
|
||||
A PyPI package generated from the RSS feed information.
|
||||
|
||||
:param pypi_dict: A dictionary retrieved from the PyPI server.
|
||||
"""
|
||||
|
||||
def __init__(self, pypi_dict):
|
||||
self._content = pypi_dict
|
||||
|
||||
def __repr__(self):
|
||||
return "<Package {0}>".format(self.name)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
>>> package = yarg.newest_packages()[0]
|
||||
>>> package.name
|
||||
u'yarg'
|
||||
>>> package = yarg.latest_updated_packages()[0]
|
||||
>>> package.name
|
||||
u'yarg'
|
||||
"""
|
||||
return self._content['name']
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
"""
|
||||
>>> package = yarg.newest_packages()[0]
|
||||
>>> package.name
|
||||
u'yarg'
|
||||
>>> package = yarg.latest_updated_packages()[0]
|
||||
>>> package.name
|
||||
u'yarg'
|
||||
"""
|
||||
if 'version' not in self._content:
|
||||
return None
|
||||
return self._content['version']
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
"""
|
||||
This is only available for :meth:`yarg.latest_updated_packages`, for
|
||||
:meth:`yarg.newest_packages` will return `None`
|
||||
|
||||
>>> package = yarg.latest_updated_packages()[0]
|
||||
>>> package.url
|
||||
u'http://pypi.python.org/pypi/yarg'
|
||||
"""
|
||||
return self._content['url']
|
||||
|
||||
@property
|
||||
def date(self):
|
||||
"""
|
||||
>>> package = yarg.newest_packages()[0]
|
||||
>>> package.date
|
||||
datetime.datetime(2014, 8, 9, 8, 40, 20)
|
||||
>>> package = yarg.latest_updated_packages()[0]
|
||||
>>> package.date
|
||||
datetime.datetime(2014, 8, 9, 8, 40, 20)
|
||||
"""
|
||||
return datetime.strptime(self._content['date'],
|
||||
"%d %b %Y %H:%M:%S %Z")
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
"""
|
||||
>>> package = yarg.newest_packages()[0]
|
||||
>>> package.description
|
||||
u'Some random summary stuff'
|
||||
>>> package = yarg.latest_updated_packages()[0]
|
||||
>>> package.description
|
||||
u'Some random summary stuff'
|
||||
"""
|
||||
return self._content['description']
|
||||
Vendored
-147
@@ -1,147 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (The MIT License)
|
||||
#
|
||||
# Copyright (c) 2014 Kura
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the 'Software'), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Release(object):
|
||||
"""
|
||||
A release file from PyPI.
|
||||
|
||||
:param release_id: A release id.
|
||||
:param pypi_dict: A dictionary of a release file.
|
||||
"""
|
||||
|
||||
def __init__(self, release_id, pypi_dict):
|
||||
self._release = pypi_dict
|
||||
self._release['release_id'] = release_id
|
||||
|
||||
def __repr__(self):
|
||||
return "<Release {0}>".format(self.release_id)
|
||||
|
||||
@property
|
||||
def release_id(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> v = "0.1.0"
|
||||
>>> r = package.release(v)
|
||||
>>> r[0].release_id
|
||||
u'0.1.0'
|
||||
"""
|
||||
return self._release['release_id']
|
||||
|
||||
@property
|
||||
def uploaded(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> v = "0.1.0"
|
||||
>>> r = package.release(v)
|
||||
>>> r.uploaded
|
||||
datetime.datime(2014, 8, 7, 21, 26, 19)
|
||||
"""
|
||||
return datetime.strptime(self._release['upload_time'],
|
||||
'%Y-%m-%dT%H:%M:%S')
|
||||
|
||||
@property
|
||||
def python_version(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> v = "0.1.0"
|
||||
>>> r = package.release(v)
|
||||
>>> r.python_version
|
||||
u'2.7'
|
||||
"""
|
||||
return self._release['python_version']
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> v = "0.1.0"
|
||||
>>> r = package.release(v)
|
||||
>>> r.url
|
||||
u'https://pypi.python.org/packages/2.7/y/yarg/yarg...'
|
||||
"""
|
||||
return self._release['url']
|
||||
|
||||
@property
|
||||
def md5_digest(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> v = "0.1.0"
|
||||
>>> r = package.release(v)
|
||||
>>> r.md5_digest
|
||||
u'bec88e1c1765ca6177360e8f37b44c5c'
|
||||
"""
|
||||
return self._release['md5_digest']
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> v = "0.1.0"
|
||||
>>> r = package.release(v)
|
||||
>>> r.filename
|
||||
u'yarg-0.1.0-py27-none-any.whl'
|
||||
"""
|
||||
return self._release['filename']
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> v = "0.1.0"
|
||||
>>> r = package.release(v)
|
||||
>>> r.size
|
||||
52941
|
||||
"""
|
||||
return self._release['size']
|
||||
|
||||
@property
|
||||
def package_type(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> v = "0.1.0"
|
||||
>>> r = package.release(v)
|
||||
>>> r.package_type
|
||||
u'wheel'
|
||||
"""
|
||||
mapping = {'bdist_egg': u'egg', 'bdist_wheel': u'wheel',
|
||||
'sdist': u'source'}
|
||||
ptype = self._release['packagetype']
|
||||
if ptype in mapping.keys():
|
||||
return mapping[ptype]
|
||||
return ptype
|
||||
|
||||
@property
|
||||
def has_sig(self):
|
||||
"""
|
||||
>>> package = yarg.get('yarg')
|
||||
>>> v = "0.1.0"
|
||||
>>> r = package.release(v)
|
||||
>>> r.has_sig
|
||||
True
|
||||
"""
|
||||
return self._release['has_sig']
|
||||
Reference in New Issue
Block a user