Ask HN: Good Python codebases to read?
Hi all,
I am currently going through Learn Python the Hard Way, and am on the review section where I have to read through source code.
Can anyone recommend some good open source Python software I can look at? I am specifically looking to see ones that employ idiomatic Python, and maybe see how they approach testing (I am not completely new to programming, just rusty after being out of the field for a long time)
Extra bonus points if the software is something you use regularly.
Cheers!
151 comments
[ 4.5 ms ] story [ 174 ms ] threadBut I am hoping to move into django eventually, but first I want tknow what is going on behind the curtain.
I use Django at work, and it was my first time with Python. The beauty of Django is, IT'S ALL SOURCE. When you run it locally, you have TONS of learning options:
- Get an IDE, and read the sources if you don't understand how something works. "Find-Definition" all the way down. (I heart PyCharm.)
- If something's broken, you can edit it!
- You can put in `import ipdb; ipdb.set_trace()` calls anywhere and get a debugging prompt! (If you don't have IPython, you can use `pdb` instead of `ipdb`... shudder.) Being able to print What Actually Gets Passed Around can occasionally be very helpful.
- You can put in debugging messages at multiple points in the flow!
- make a `pygrep` alias to answer "where is ..." questions:
It's a little bit meta, but I had lots of "wow" moments. Also, it's a nice example of using C to speed up certain operations.
How to make a usable api. The decisions that went into each method call were fantastic. Great test coverage as well. I use package in most python development.
Cheers!
The first thing many users will do is
Which tells them that it takes some kwargs, but doesn't tell them what those kwargs are. It's easy, especially for a newcomer, to read "optional arguments that `request` takes" and fail to understand that they should look up the docs on (not-really-encouraged-as-part-of-public-API) function `request`. That's pretty bad; those kwargs are important! (The reason is because requests.get is implemented as a call to request(method, ..., kwargs) but the user doesn't care what the implementation-level reason is.)Beyond that I did look into the codebase once to investigate a possible bug and there were a few python style things I wanted to fix, but I don't remember them so this comment probably sounds kind of annoying (it would annoy me if I were reading it not writing it...). It didn't strike me a really clean codebase. But yes the library is very useful and I'm sure it's a pretty decent python codebase.
Here are all the kwargs the user probably wanted to know but failed to find out and was forced to either browse online docs or the source code:I was using Python for 8 years and IPython for somewhat 5 years if my memory serves me right but today I have learned that you can invoke help on an object by appending '?'. I guess I might delve into IPython documentation sometime.
Thank you for lengthy and detailed explanation.
https://hg.python.org/cpython/file/3.5/Lib/collections/__ini... Knowing specialized data structure in a language is always important and this is well coded.
Well see the 2 lines I pointed in one of the standard library in python and you will understand that even in good language there will always be dust under the carpet at one point. https://hg.python.org/cpython/file/5c3812412b6f/Lib/email/_h...
But you did teach me one thing, I didn't know that the """ could be used for commenting. I thought it was only for multi-line print statements.
These are exactly the type of things I hope to learn while code-reading.
Cheers!
As ironic(?) as this sounds, where is this doc feature documented?
(Part of my learning is that I am trying hard to learn how to navigate the various Python documentation. For example, I had a hell of a time trying to find a list of format strings, as different sources refer to it as different things)
https://www.python.org/dev/peps/pep-0257/
And for people who will no doubt call me out on this, I have been working on Zed's LPtHW for about a month. I have done numerous searches regarding Python problems, and this is literally the first time I have come across a PEP reference to look at beside PEP 8.
BTW, what you call "an opinionated piece on how to write Python" was originally written by Guido van Rossum, the guy who invented Python in the first place. I think that gives him the right to say something on the topic...
(You ought to know that Python has a large following with a strong community feeling. Making negative remarks about their BDFL - benevolent dictator for life - van Rossum does not go down well ;-) )
And I hope that other people don't think I used the wording 'opinionated' in a negative way. I do know about the concept of a BDFL, and I do know that Guido was behind those comments.
But I still stand behind my assessment that the PEP 8 comments are opinionated. And maybe rightly so. ;)
Doesn't make it any less of a community. Families can disagree with each other and still love each other.
It's not code, but also see Raymond Hettinger's talk "Beyond PEP 8" on YouTube. Actually, pretty much any talk by Hettinger is worth watching:
http://pyvideo.org/speaker/138/raymond-hettinger
[0]https://www.python.org/dev/peps/
2. The Bazaar VCS is written entirely in Python, is very well documented and has a large test section. (www.launchpad.net/bzr)
Bazaar I may look into, as I know it's a very capable piece of software, and now I know it's well documented with tests makes it very relevant to my interests :)
Edit: I'm on windows, but I'm using vagrant with Ubuntu 14lts image for my development work. Specifically the data science vagrant box...
Thank you! (And I had no idea that either bazaar or mercurial were written in Python, because them being 'serious' software I automatically assumed they were written in C. Color me stupid)
But honestly, the Bazaar code base is great. Great documentation at every level, and, as far as I can judge, some pretty good code too.
Cheers!
Cheers!
Disclaimer: contributed to mercurial (and wrote some plugins), wrote few plugins for bzr (it was used in one company I worked for).
P.S. Didn't notice right away, hey, Dirkjan! :)
- https://github.com/zzzeek/sqlalchemy
- http://www.aosabook.org/en/sqlalchemy.html
- http://docs.sqlalchemy.org/en/rel_1_0/
Thanks for the recommendation.
Cheers!
Still it's a good example how to make many relatively complex parts easily composable and efficient.
- https://bitbucket.org/zzzeek/dogpile.core - https://bitbucket.org/zzzeek/dogpile.cache
Cheers!
[1]: https://github.com/openstack/openstack [2]: https://github.com/openstack/barbican
Cheers!
Seriously, I've seen "sychronization threads" that use no synchronization primitives that have a single bare exception handler trap the critical section. The handler just restarts the computation... leading to fun times.
Cinder also has an interesting problem in the explosion of ABC "mixins" used for constructing a backend driver. It went from 5 in the previous release to something like 25 presently. A patch to fix it: https://review.openstack.org/#/c/201812/
But even the process isn't perfect. I've seen patches that change a couple of log lines get dog-piled with -1 nit-picks about inconsequential wording and take months to get through.
Openstack is an interesting beast but it's not a good example if you're just learning, IMO.
That being said Barbican is quite good, which I think is due to its proof of concept being written in Go[1] before being ported.
If you want to learn decent testing Openstack is a good example, the code as a whole not so much. This also only applies if you want to use unittest or their custom test module, testtools. py.test is a much nicer way to do testing IMO
[1]: https://www.youtube.com/watch?v=245rSZBdm9s
Thank you for all the good replies peeps!
(Honestly, looking at the repo, I don't even know where to start if I wanted to do a read through. Has anyone created a map? :)
If the OP wants to grok a small, discrete codebase then I agree that Django is not what he's looking for.
He recommends the following Python projects for reading:
* Howdoi (https://github.com/gleitz/howdoi)
* Flask (https://github.com/mitsuhiko/flask)
* Werkzeug (https://github.com/mitsuhiko/werkzeug)
* Requests (https://github.com/kennethreitz/requests)
* Tablib (https://github.com/kennethreitz/tablib)
Hope that helps---good luck!
Thank you for this resource, much appreciated!
However reading the less abstract parts may help. For instance, the paginator is pretty self contained. https://github.com/django/django/blob/master/django/core/pag...
https://github.com/django/django/blob/master/django/core/man...
I prefer sklearn like https://github.com/scikit-learn/scikit-learn/blob/master/skl...
A lot of code that does a lot.
Bottle is nice on the web dev front.
https://github.com/bottlepy/bottle/blob/master/bottle.py
The "self.thing = bar" in one function that only gets used in some other function ( or even worse something only used in a companion class) pattern is super prevalent.
Might just be me but I think a lot of the older code suffers from massive locality problems that makes debugging framework bugs super tricky
I think a lot of the issues involving overuse of state, are primarily related to using OO when a pure function would suffice. It's just too tempting to dynamically assign attributes to mutable instances.
To be fair, when Django is used properly it isn't usually an issue. Besides the queryset/model API is extremely nice, and at this point very polished.
Whilst this wasn't a discussion on which framework is best (and I'm not a Web dev by trade either), I must say I turn to Flask, as I find the API more Pythonic.
I guess what I'm trying to say is that the Django source code is probably great, but the less heavyweight packages/frameworks the better. Learn Pythonic API design from somewhere else.
https://github.com/boto/boto
* https://github.com/web2py/web2py/
* https://github.com/web2py/pydal
http://norvig.com/lispy.html http://norvig.com/lispy2.html (Lisp interpreter)
http://www.norvig.com/spell-correct.html (Spelling corrector)
http://norvig.com/sudoku.html (Sudoku solver)
Also his online course Design of Computer programs includes many short, well-explained Python examples:
https://www.udacity.com/wiki/cs212
He's using overly terse, poorly descriptive variable names, not using multiline strings for docstrings, not indenting where he should, and one-lining if/elif statements and function definitions. This style does not contribute to readability.
This is not how I would want someone just learning Python to learn it.
The spellchecker still blows my mind, and I don't yet understand the Sudoku puzzle. We can always take the code and re-format / re-name variables to aid our understanding.
For example:
To me this is perfectly clearly a simple function whose only purpose is to prepend forward slashes to unix-style paths. Is the following really so much more readable? To my eyes and mind, the second example is not any more readable at the expense of several lines of code.Considering that the creator of the Python language considered getting rid of lambdas because they are essentially limited functions and thus violate Python's "one obvious way to do it" philosophy, I'd rather those learning Python to be shown the latter, rather than the former.
From a development and version control perspective, as soon as the lambda function requires more than a simple expression, i.e. a compound statement (https://docs.python.org/2/reference/compound_stmts.html), you have to trash the whole line, instead of adding perhaps a single extra line of content.
Oh, really? Let's compare:
These functions are actually not identical in their computation - only their result.> 1) the former function does not know its own name
If you think that is really important (hint: it's not [from a lisper perspective, anyway]), Python thankfully allows you to do this:
> 2) the latter function can be documented with a docstring Of course the only reason you can't put docstrings on a lambda function in python is because the forced indentation of code and implicit return with no indented block available is what Guido went with for Lambda.> Considering that the creator of the Python language considered getting rid of lambdas
Guido is not a proponent of functional programming in general and claims that map, reduce, and filter are so much harder to understand than list comprehensions (which implement some common map, reduce, and filter, operations with special optimized syntax) that he tried to get them removed from the language too. Thankfully for us users of the language, this view did not win through and we can still use map, reduce, and filter in python, if we choose.
Hey, maybe you can help me decipher this, I've always wondered exactly what's going on here: https://docs.python.org/2/faq/programming.html#is-it-possibl...
Ad hominem? I guess I win.
> List comprehensions and generator expressions have replaced all need for map, filter, and lambdas
Please explain how list comprehensions and generators have replaced the need for lambdas.
Your "distaste" of functional programming constructs is right up there with Guido's.So that's:
Do note that good code and code golf are two different things! :DThanks!
> Did you know there's an `operator.itemgetter` function that does that?
Yes, I'm quite aware! Are you aware the "useless" functional solution with lambda is two characters shorter?
Cause you're apparently not aware that I was demonstrating a use-case for lambdas as one-off functions that are passed to other functions (which is an abstract concept from the particular function used), and you didn't demonstrate how list comprehensions or generators make them not-needed. Of course, that's because it was a leading question and the answer is that the concepts are orthogonal so it cannot be demonstrated.>Ad hominem? I guess I win.
That was not ad hominem, because what you wrote is indeed half-baked hackery.
Nobody said it cannot be done the way you did it. You were just pointed at the shortcomings of your approach and that the Python community generally prefers stupidly simple, easy to understand solutions. Using magic attributes to argue against it just makes it worse - remember this is a thread about idiomatic Python code bases.
> Nobody said it cannot be done the way you did it. You were just pointed at the shortcomings of your approach
I "addressed" the shortcomings of "my approach" by showing that Python (the language, not the community) allows you to access and manipulate the data you claimed was important and missing.
I don't believe it is necessary for most simple functions to know what their name is. I do believe the demonstrated code is self documenting enough to not require a documentation string. You made those "requirements". I never claimed that every function must be a lambda - you seem to be implying I am, so I am explicitly stating that I do not.
Here's a place where you really do need a named function (due to deficiencies in Python's lambda implementation):
Of course, that's completely silly... since the point of a lambda function generally is that the function is generally small enough and short-lived enough that it does not need a name or documentation.> the Python community generally prefers stupidly simple, easy to understand solutions.
Which, despite your protests, includes using lambdas!
> Using magic attributes to argue against it just makes it worse - remember this is a thread about idiomatic Python code bases.
How else does a function "know its own name" unless it uses the "magic" attribute "__name__"? Oh, you prefer "func_name"? That's cute:
So in this comment I am replying to, it is a bad thing that I made use of "__name__", but in the comment THAT was replying to, it was a bad thing that I did NOT use "__name__" or its linked "func_name". That's how you move goal posts!>>> [(b, a) for a, b in sorted(((-(x2), x) for x in xrange(10) if 0 == x % 2))]
[(8, -64), (6, -36), (4, -16), (2, -4), (0, 0)]
However, ocasionally you still need a more complex sorting function. So lambdas are still handy, IMO.
I would say that is debatable. Coming from an FP background, I use map, filter and lambdas nearly all of the time because I find it more readable and can easily reason about the code. I have seen some two line list comprehensions and they are far harder for me to read and understand.
Lambda functions are most useful for very small, straightforward functions that return a value - especially in cases where you don't necessarily need to name or document them deeply, such as for passing as arguments to other functions (for example, sort/sorted).
So if you want terse code that only does what it needs to do and nothing more, pepper with lambdas as needed.
If you want to invent names for things just cause you like inventing them or need to document every single function you write (even if the code is simple enough to document itself), feel free to make all one-line returning functions in the fully named and documented format.
Reminds me of that blog thread where this design pattern guru hemmed and hawed from his high horse over several posts about how to write constrained based solvers and still did not get to a piece of code that actually solved the problem, whereas Norvig just posted a simple solution. A few non-idiomatic indents here and there (although his style has never been a problem for me) are nothing really.
Right.
>Reminds me of that blog thread where this design pattern guru hemmed and hawed from his high horse
I read a similar story a while ago. Two programmers are given the task of writing a program for some non-trivial problem.
One of them, Hoity Toity Harry, tries to apply many of the latest and greatest algorithms, techniques, paradigms, etc., to impress people (of course).
The other, Down To Earth Dan, just strives for a good implementation, with reasonably good algorithms, etc. After a while, Dan finishes his program and does a test run. It works well enough for the task. Meanwhile, Harry is not even near to finishing his code, due to struggling with complexities of the techniques he has tried to use.
The boss comes in, sees the results, and congratulates Down To Earth Dan.
Hoity Toity Harry, of course, has to protest, trying to put down Down To Earth Dan's implementation, saying that it uses simple algorithms, etc., while his own code uses sophisticated, state of the art techniques. Dan replies: "Yes, I could also have used those things. But my program runs, and yours doesn't."
Okay, I changed the programmers' names for fun and effect, but I really did read the story, in some good (and pragmatic) software book, a while ago.
For instance, I find this unnecessarily difficult to read.
>>> 0 if True else 1 if True else 2
0
But breaking it up like this keeps it reasonably concise, while retaining readability.
They can also be combined with comprehensions, which can be useful.>>> import random
>>> ['a' if random.choice((True, False)) else 'b' for _ in range(6)]
['a', 'a', 'a', 'a', 'a', 'b']
Adherence to Python's best practices / pep-8 are not one of them
I'd rather have Norvig's code solving some IA problem than some perfectly compliant PEP-8 code solving an issue in a naive way
It's a nice, small, fast web framework. Great for building APIs. Also, it's one ~3k loc, readable file.[1]
[1] https://github.com/bottlepy/bottle/blob/master/bottle.py
Rather than seeing the code of great libraries, I sometimes want to see how people use them in the real world.
The functions in PyToolz are short, well tested and idiomatic Python (thought the functional programming paradigm they support is not quite so idiomatic). I recommend starting with the excellent documentation: http://toolz.readthedocs.org/en/latest/
In particular, the API docs have links to the source code for each function: http://toolz.readthedocs.org/en/latest/api.html
It is a minimal web framework like Sinatra or Flask. The beautiful thing about CherryPy is you write code for it the same way you would write general Python code. I enjoy using it for small projects from time to time.
edit:
Bickbucket Repository: https://bitbucket.org/cherrypy/cherrypy/overview
Lots of examples of SQLAlchemy, Flask, gevent, and pytest in action to build a REST API and sync platform for email/calendar/contacts data!
On the testing side, I was chatting to a fellow Pyladies attendee about how we do test fixture setup and teardown (especially around databases) -- you might find that interesting to look at too.
(Might not be totally obvious, because the package namespace is called `inbox/` for legacy reasons.)
If a beginner wants to see real production code, rather than toy examples, I think it's inevitable that there will be some points of confusion. Part of the learning process is diving in and exploring and being okay with not totally understanding everything that's going on. :)
By design, Mercurial has almost no dependencies, so it's very self-contained. I find this makes it a particularly easy codebase to get into.
If you're interested, I would love to walk you (or anyone else!) trough it.
https://www.python.org/dev/peps/pep-0008/
I was more defending being a pedant about whatever coding standards your team agrees upon rather than any specific PEP-8 standard.
It is no problem to increase PyLint's line length limit if your team wants to use something other than the PEP-8 79 character limit.
I referred to it when adding tests for tokenizers in a common lisp NLP application: https://github.com/vseloved/cl-nlp/.
NLTK's value is that it shows you how to write NLP algorithms, and gives you an understandable starting point when you need to do something that nobody has implemented yet.