Repository: pypa/pip

Issue:
Sort "pip freeze" results by name
This is a feature request. 
Unless there are good reasons not to do it, I think it makes sense to have ordered package names.



Discussion:
They are?

https://github.com/pypa/pip/blob/develop/pip/commands/freeze.py#L122-L124

Maybe that is just in the development version?

```
(httpbench)giampaolo@UX32VD:~/svn/samsung/httpbench$ pip  --version
pip 1.5.4 from /home/giampaolo/svn/samsung/httpbench/_venv/local/lib/python2.7/site-packages (python 2.7)
(httpbench)giampaolo@UX32VD:~/svn/samsung/httpbench$ pip freeze 
PyYAML==3.10
argparse==1.2.1
docopt==0.6.1
httpbench==0.1
ipdb==0.8
ipython==1.2.1
-e hg+https://code.google.com/p/psutil@f251d96aa3f99b4bfd403e2de7360af5d7566222#egg=psutil-dev
requests==2.2.1
wsgiref==0.1.2
```

No, been around for a while. If you think it should use a different key comparison, please say so so we can consider.

Are you able to reproduce the issue though?

Which issue? As in normal python string comparison, capital letters come before lowercase. e.g:

```
(cryptography)ivo@ivosung cryptography (master)$ pip freeze
Jinja2==2.7.2
MarkupSafe==0.18
Pygments==1.6
Sphinx==1.2.1
cffi==0.8.1
cov-core==1.7
coverage==3.7.1
-e git+git@github.com:Ivoz/cryptography.git@bd08799bcce99b94250ad3b3313826651c8c0181#egg=cryptography-pyca/master
docutils==0.11
enum34==0.9.23
flake8==2.1.0
mccabe==0.2.1
pep8==1.4.6
pretend==1.0.7
py==1.4.20
pycparser==2.10
pyflakes==0.7.3
pytest==2.5.2
pytest-cov==1.6
six==1.5.2
tox==1.7.0
virtualenv==1.11.4
wheel==0.22.0
wsgiref==0.1.2
```

Everything sorted alphabetically

Mmm you're right, I clearly got confused, sorry.
But yes, I'd like to propose a change in order to avoid having capital letters visually separated from others as in:

```
>>> sorted(ls, key=lambda x: x.lower()))
```

This way we'd also have "-e " lines at the top of the list instead of in the middle.
This is going to be the result which IMO is more readable:

```
-e git+git@github.com:Ivoz/cryptography.git@bd08799bcce99b94250ad3b3313826651c8c0181#egg=cryptography-pyca/master
cffi==0.8.1
cov-core==1.7
coverage==3.7.1
docutils==0.11
enum34==0.9.23
flake8==2.1.0
Jinja2==2.7.2
MarkupSafe==0.18
mccabe==0.2.1
pep8==1.4.6
pretend==1.0.7
py==1.4.20
pycparser==2.10
pyflakes==0.7.3
Pygments==1.6
pytest-cov==1.6
pytest==2.5.2
six==1.5.2
Sphinx==1.2.1
tox==1.7.0
virtualenv==1.11.4
wheel==0.22.0
wsgiref==0.1.2
```


Resolving patch:
diff --git a/pip/commands/freeze.py b/pip/commands/freeze.py
--- a/pip/commands/freeze.py
+++ b/pip/commands/freeze.py
@@ -13,7 +13,11 @@
 
 
 class FreezeCommand(Command):
-    """Output installed packages in requirements format."""
+    """
+    Output installed packages in requirements format.
+
+    packages are listed in a case-insensitive sorted order.
+    """
     name = 'freeze'
     usage = """
       %prog [options]"""
@@ -125,5 +129,5 @@ def run(self, options, args):
                 '## The following requirements were added by pip --freeze:\n'
             )
         for installation in sorted(
-                installations.values(), key=lambda x: x.name):
+                installations.values(), key=lambda x: x.name.lower()):
             f.write(str(installation))
diff --git a/pip/commands/list.py b/pip/commands/list.py
--- a/pip/commands/list.py
+++ b/pip/commands/list.py
@@ -8,7 +8,11 @@
 
 
 class ListCommand(Command):
-    """List installed packages, including editables."""
+    """
+    List installed packages, including editables.
+
+    Packages are listed in a case-insensitive sorted order.
+    """
     name = 'list'
     usage = """
       %prog [options]"""


Test patch:
diff --git a/tests/functional/test_freeze.py b/tests/functional/test_freeze.py
--- a/tests/functional/test_freeze.py
+++ b/tests/functional/test_freeze.py
@@ -30,6 +30,7 @@ def _check_output(result, expected):
 
     def banner(msg):
         return '\n========== %s ==========\n' % msg
+
     assert checker.check_output(expected, actual, ELLIPSIS), (
         banner('EXPECTED') + expected + banner('ACTUAL') + actual +
         banner(6 * '=')
@@ -50,7 +51,7 @@ def test_freeze_basic(script):
         # and something else to test out:
         simple2<=3.0
         """))
-    result = script.pip_install_local(
+    script.pip_install_local(
         '-r', script.scratch_path / 'initools-req.txt',
     )
     result = script.pip('freeze', expect_stderr=True)
@@ -70,10 +71,11 @@ def test_freeze_svn(script, tmpdir):
         'svn+http://svn.colorstudy.com/INITools/trunk',
         tmpdir.join("cache"),
     )
-    #svn internally stores windows drives as uppercase; we'll match that.
+    # svn internally stores windows drives as uppercase; we'll match that.
     checkout_path = checkout_path.replace('c:', 'C:')
 
-    result = script.run(
+    # Checkout
+    script.run(
         'svn', 'co', '-r10',
         local_repo(
             'svn+http://svn.colorstudy.com/INITools/trunk',
@@ -81,16 +83,18 @@ def test_freeze_svn(script, tmpdir):
         ),
         'initools-trunk',
     )
-    result = script.run(
+    # Install with develop
+    script.run(
         'python', 'setup.py', 'develop',
         cwd=script.scratch_path / 'initools-trunk',
         expect_stderr=True,
     )
     result = script.pip('freeze', expect_stderr=True)
+
     expected = textwrap.dedent("""\
-        Script result: ...pip freeze
+        Script result: pip freeze
         -- stdout: --------------------
-        -e %s@10#egg=INITools-0.3.1dev...-dev_r10
+        ...-e %s@10#egg=INITools-0.3.1dev...-dev_r10
         ...""" % checkout_path)
     _check_output(result, expected)