Repository: jazzband/pip-tools

Issue:
pip-compile fails with a local editable
I have a project which is packaged, and I would like to take a list of dependencies from inside of the `setup.py` for that project, and compile it down to a list with `pip-compile`. Since it only supports `requirements.in` I went ahead and created one that looked like:

```
-e .
```

This resulted in an exception like:

```
Traceback (most recent call last):
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/bin/pip-compile", line 9, in <module>
    load_entry_point('pip-tools==1.0.dev1', 'console_scripts', 'pip-compile')()
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/lib/python3.4/site-packages/click/core.py", line 664, in __call__
    return self.main(*args, **kwargs)
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/lib/python3.4/site-packages/click/core.py", line 644, in main
    rv = self.invoke(ctx)
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/lib/python3.4/site-packages/click/core.py", line 837, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/lib/python3.4/site-packages/click/core.py", line 464, in invoke
    return callback(*args, **kwargs)
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/lib/python3.4/site-packages/piptools/scripts/compile.py", line 81, in cli
    results = resolver.resolve()
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/lib/python3.4/site-packages/piptools/resolver.py", line 71, in resolve
    has_changed, best_matches = self._resolve_one_round()
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/lib/python3.4/site-packages/piptools/resolver.py", line 142, in _resolve_one_round
    constraints = sorted(self.constraints, key=lambda ireq: ireq.req.key)
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/lib/python3.4/site-packages/piptools/resolver.py", line 42, in constraints
    self.their_constraints)))
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/lib/python3.4/site-packages/piptools/resolver.py", line 115, in _group_constraints
    for _, ireqs in full_groupby(constraints, key=lambda ireq: ireq.req.key):
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/lib/python3.4/site-packages/piptools/utils.py", line 79, in full_groupby
    return groupby(sorted(iterable, key=key), key=key)
  File "/Users/dstufft/.virtualenvs/tmp-63439e9bc9e5262/lib/python3.4/site-packages/piptools/resolver.py", line 115, in <lambda>
    for _, ireqs in full_groupby(constraints, key=lambda ireq: ireq.req.key):
AttributeError: 'NoneType' object has no attribute 'key'
```

What I'd really like, is a way to do something like `pip-compile .` without having to write a .in file, and have it resolve the dependencies of the package in the current directory, but at the very least, `-e .` should work.



Discussion:

Resolving patch:
diff --git a/piptools/resolver.py b/piptools/resolver.py
--- a/piptools/resolver.py
+++ b/piptools/resolver.py
@@ -20,6 +20,13 @@
 magenta = partial(click.style, fg='magenta')
 
 
+def _dep_key(ireq):
+    if ireq.req is None and ireq.link is not None:
+        return str(ireq.link)
+    else:
+        return ireq.req.key
+
+
 class Resolver(object):
     def __init__(self, constraints, repository, cache=None, prereleases=False, clear_caches=False):
         """
@@ -112,7 +119,7 @@ def _group_constraints(self, constraints):
             flask~=0.7
 
         """
-        for _, ireqs in full_groupby(constraints, key=lambda ireq: ireq.req.key):
+        for _, ireqs in full_groupby(constraints, key=_dep_key):
             ireqs = list(ireqs)
             editable_ireq = first(ireqs, key=lambda ireq: ireq.editable)
             if editable_ireq:
@@ -139,7 +146,7 @@ def _resolve_one_round(self):
         configuration.
         """
         # Sort this list for readability of terminal output
-        constraints = sorted(self.constraints, key=lambda ireq: ireq.req.key)
+        constraints = sorted(self.constraints, key=_dep_key)
         log.debug('Current constraints:')
         for constraint in constraints:
             log.debug('  {}'.format(constraint))
diff --git a/piptools/utils.py b/piptools/utils.py
--- a/piptools/utils.py
+++ b/piptools/utils.py
@@ -30,7 +30,8 @@ def format_specifier(ireq):
     InstallRequirements to the terminal.
     """
     # TODO: Ideally, this is carried over to the pip library itself
-    specs = sorted(ireq.specifier._specs, key=lambda x: x._spec[1])
+    specs = ireq.specifier._specs if ireq.req is not None else []
+    specs = sorted(specs, key=lambda x: x._spec[1])
     return ','.join(str(s) for s in specs) or '<any>'
 
 


Test patch: