5
\$\begingroup\$

I looked at the pypi classifiers and some guide to help me write the following script, and here's me wondering if it can be improved:

import xmlrpc.client

# pypi language version classifiers
PY3 =  ["Programming Language :: Python :: 3"]
PY2 =  ["Programming Language :: Python :: 2"]
PY27 = ["Programming Language :: Python :: 2.7"]
PY26 = ["Programming Language :: Python :: 2.6"]
PY25 = ["Programming Language :: Python :: 2.5"]
PY24 = ["Programming Language :: Python :: 2.4"]
PY23 = ["Programming Language :: Python :: 2.3"]

def main():
    client = xmlrpc.client.ServerProxy('http://pypi.python.org/pypi')

    # get module metadata
    py3names = [name[0] for name in client.browse(PY3)]
    py2names = [name[0] for name in client.browse(PY2)]
    py27names = [name[0] for name in client.browse(PY27)]
    py26names = [name[0] for name in client.browse(PY26)]
    py25names = [name[0] for name in client.browse(PY25)]
    py24names = [name[0] for name in client.browse(PY24)]
    py23names = [name[0] for name in client.browse(PY23)]

    cnt = 0
    for py3name in py3names:
        if py3name not in py27names \
           and py3name not in py26names \
           and py3name not in py25names \
           and py3name not in py24names \
           and py3name not in py23names \
           and py3name not in py2names:
            cnt += 1

    print("Python3-only packages: {}".format(cnt))

main()

Sidenote:

$ time python3 py3k-only.py 
Python3-only packages: 259

real    0m17.312s
user    0m0.324s
sys 0m0.012s

In addition, can you spot any functionality bugs in there? Will it give accurate results, assuming that pypi has correct info?

\$\endgroup\$
8
  • \$\begingroup\$ a more complete script \$\endgroup\$
    – tshepang
    Commented Jan 26, 2012 at 8:03
  • \$\begingroup\$ @jamal you killed the evolution of the Question, and now the Answer looks odd \$\endgroup\$
    – tshepang
    Commented Sep 24, 2014 at 18:57
  • \$\begingroup\$ The answer was never edited, though. It had to correspond to just the original code. \$\endgroup\$
    – Jamal
    Commented Sep 24, 2014 at 18:57
  • \$\begingroup\$ Yeah, but look at Why do you have a single string in a list? for example. You got rid of that part of the original Question. \$\endgroup\$
    – tshepang
    Commented Sep 24, 2014 at 18:59
  • \$\begingroup\$ I still see that in this code. \$\endgroup\$
    – Jamal
    Commented Sep 24, 2014 at 19:00

1 Answer 1

3
\$\begingroup\$
import xmlrpc.client

# pypi language version classifiers
PY3 =  ["Programming Language :: Python :: 3"]

Why do you have a single string in a list?

PY2 =  ["Programming Language :: Python :: 2"]
PY27 = ["Programming Language :: Python :: 2.7"]
PY26 = ["Programming Language :: Python :: 2.6"]
PY25 = ["Programming Language :: Python :: 2.5"]
PY24 = ["Programming Language :: Python :: 2.4"]
PY23 = ["Programming Language :: Python :: 2.3"]

You should put all these strings in one list.

def main():
    client = xmlrpc.client.ServerProxy('http://pypi.python.org/pypi')

    # get module metadata
    py3names = [name[0] for name in client.browse(PY3)]
    py2names = [name[0] for name in client.browse(PY2)]
    py27names = [name[0] for name in client.browse(PY27)]
    py26names = [name[0] for name in client.browse(PY26)]
    py25names = [name[0] for name in client.browse(PY25)]
    py24names = [name[0] for name in client.browse(PY24)]
    py23names = [name[0] for name in client.browse(PY23)]

If you put the python 2.x versions in a one list, you should be able to fetch all this data into one big list rather then all of these lists.

    cnt = 0

Don't uselessly abbreviate, spell out counter

    for py3name in py3names:
        if py3name not in py27names \
           and py3name not in py26names \
           and py3name not in py25names \
           and py3name not in py24names \
           and py3name not in py23names \
           and py3name not in py2names:
            cnt += 1

I'd do something like: python3_only = [name for name in py3name if py3name not in py2names]. Then I'd get the number of packages as a len of that.

    print("Python3-only packages: {}".format(cnt))

main()

Usually practice is to the call to main inside if __name__ == '__main__': so that it only gets run if this script is the main script.

\$\endgroup\$
5
  • \$\begingroup\$ I think you meant py3only = [name for name in py3names if name not in py2names]? \$\endgroup\$
    – tshepang
    Commented Jan 25, 2012 at 11:17
  • \$\begingroup\$ BTW, with your suggested change to put all Python 2 classifiers in one list, the only modules that get excluded are those which match all the Python 2 classifiers. That is, my output includes a lot of packages that also have Python 2 versions. \$\endgroup\$
    – tshepang
    Commented Jan 25, 2012 at 11:20
  • 1
    \$\begingroup\$ @Tshepang, yes on the first comment, not if you do it properly on the second comment. I didn't expressly state how to do it, but you can go through the list, pass each element to the client.browse() one at a time, and then combine the lists. \$\endgroup\$ Commented Jan 25, 2012 at 14:59
  • \$\begingroup\$ @Tshepang, yes that's the idea. But you'd be better off to use a list literal instead of the append lines to build PY2 you might also consider using a nested list comprehension in the fetch. \$\endgroup\$ Commented Jan 25, 2012 at 22:07
  • 1
    \$\begingroup\$ @Tshepang, ` py2names = [name[0] for classifier in PY2 for name in client.browse([classifier])]` \$\endgroup\$ Commented Jan 26, 2012 at 0:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.