Do you have horrible convoluted things that need parsing?
Well, you're in luck because this week we're covering parsing horrible things in Python.
Obviously, you'll learn a bunch of tips and tricks from this episode,
but you'll see that advanced parsing is actually a gateway to many interesting computer science
techniques. Listen in as I speak with Eric Rose about his journey to parse weird things at Mozilla.
This is Talk Python To Me, episode 85, recorded October 27, 2016.
Welcome to Talk Python To Me, a weekly podcast on Python, the language, the libraries, the
ecosystem, and the personalities. This is your host, Michael Kennedy. Follow me on Twitter where
I'm at mkennedy. Keep up with the show and listen to past episodes at talkpython.fm and follow the
show on Twitter via at Talk Python. This episode has been sponsored by GoCD and Hired. Thank them
both for supporting the show by checking out what they have to offer during their segments.
Hey, everyone. A little bit of news for you. So first of all, I'm doing a webcast next week,
Tuesday, November 22, at 11 a.m. Pacific time. The topic is Write Pythonic Code for Better Data Science.
And I've partnered with Kevin Markham from Data School. And this is 100% free. You can drop in.
And it's kind of like a super miniature version of my Write Pythonic Code course. So if you want to come
check it out and register, just go to crowdcast.io slash e slash Pythonic or click that same link in
the show notes. I was talking to the PyCharm team this week, and they agreed to give away a free copy
of PyCharm Professional every week to one lucky listener. So all you have to do to be in the running
for this is be a friend of the show. Just visit talkpython.fm/friends, enter your email address,
and randomly I'll choose an email address out of the list, and somebody will win. And because we're
doing every week, the odds are pretty decent for you to get a copy. Let's get to this excellent
interview about parsing horrible things with Eric Rose. Eric, welcome to Talk Python.
Thanks for having me, Michael. Pleasure to be here.
Yeah, it's great to have you. I'm really looking forward to parsing horrible things and a bunch of
other stuff.
Well, nobody in their right mind really looks forward to parsing horrible things, but it's something we
have to do.
Well, when you have horrible things and you want to parse them, someone's got to do it, right?
That's right.
So I think it's, we're going to talk about some really cool techniques, some libraries,
some algorithms, and whatnot to pull that off, and some interesting work and talks that you've done.
But of course, before we get into those, let's start with your story. How do you get into
programming in Python?
Well, I mean, I used to be a Legos kid, right? You know, like snapping those things together.
And of course, the thing about being a kid is you have no economic power, so you've only got the
ones you've got in the box, and you get at birthdays, and you get at Christmas or what have you.
And so I kind of discovered programming as a way to program with, to build with Legos without ever
worrying about running out of parts. And so I became kind of an early collector of programming
languages, you know, before the internet. So you have to get these things kind of happen upon them
on floppy disks or whatever. And I did basic and I did hyper card and kind of learned programming
through mimicry like we all did in the 80s. You know, you get these magazines with program listings
in them. And you just kind of have to type them in if you want to play with them. And so you're just forced to plow
linearly through these things, making mistakes throughout. And that kind of teaches you debugging and proofreading.
And you come to all kinds of wrong conclusions. Like I remember in hyper card, there's this statement global
start flag, which of course the global variable declaration, but I thought it was this round checkerboard cursor,
which totally looked like a global start flag to me. So, you know, fast forward two dozen languages later
and I ended up working at a university over at Penn State and we had this crazy seminar registration
system called SEMREG. Maybe they're still running it. I really hope not. And it was, well, the simple thing
I could say is it was written in VBScript, but really it was written in PHP and then transliterated into
VBScript via a series of regular expressions. Wow. That's crazy. I've never heard of anything
being compiled from PHP to VBScript. Absolutely insane. And compiled is probably too kind of a word,
but, so I didn't realize this when I took the job, you know, I've become a lot smarter about
interviewing since then, I hope. And I thought I'm going to give this a chance. You know, I'm this big
Mac guy and I, it was, it was the height of the platform wars and windows was terrible, but I, you know
what? I'm going to, I'm going to not be a jerk. I'm going to give this thing a chance. I'm going to see if I
can write stuff in VBScript. And the short answer is you can't write anything in VBScript.
The thing has classes, but no inheritance. And, so, you know, with a little detour through making
my own, prototype based inheritance language out of the call statement, I thought, okay, we need to
bridge this over to something more usable. And Python was very well supported at the time on Windows
scripting host, which allowed me to do ridiculous things like share a database connection between the
legacy VBScript code and the new Python code. And that's how I got into Python, believe it or not.
Interesting. Because if you can get a drawer in the script host, you can basically get it the same
environment as this other bad thing, right? Yeah. You can kind of mash it all together. It'll bridge
strings to strings. It'll actually bridge objects to objects and methods to methods, numbers to numbers.
And if you bang on it hard enough, you can get database handles shared and share a single
transaction between the two languages. So I was very fortunate to happen upon Python that way.
Yeah, that's great. And it looks like you've been doing a bunch of Python since then, huh?
Well, Python is a really, nice little patchwork of, of, of stolen bits of language.
There's not a whole lot unique about Python, which I think is one of its strengths apart from maybe the
width statement, but it knows where to steal all the best things, the list comprehensions out of Haskell,
for example. And, you know, Hey, we're going to steal, you know, class-based object orientation
from wherever that came from small talk, I guess, but we'll also have top level functions from any
number of languages. So I've been pretty happy with it. Yeah, absolutely. And it's still,
still on its way to doing that thing with like async and await in the latest version, right? Which is
a fantastic language feature. Yeah. We'll see where that goes. I haven't played with it myself.
Yeah. I'm still looking for a good use case for that as well, but it's, it's definitely a neat
concept. So how about now? What do you work on these days?
Well, day to day, I maintain a project called DXR over at Mozilla, which doesn't really stand for
anything, but is a language analysis and navigation tool for large code bases. So
Firefox is something like 17 million lines of code. You know, if you want to make a change,
you've got to be thinking, well, what am I going to break with this change? Who am I affecting?
What functions call this function that I want to change? What, what eats the result of the
contents of this variable that I want to alter or, what invariant might I be violating here?
And DXR answers those kinds of questions through a structured query language and through both text
search and a cleverly accelerated regular expressions search. So you can get through these 17 million
lines with a regex in, you know, sub second. Wow. And how you said 17 million lines of code. That's,
that's quite impressive. That's bigger even than I thought it would be, but I knew that was huge.
How many languages are involved in that? Oh, that's a crazy question to ask. Well,
okay, I'll just go with language. So HTML is a language though, not programming language,
arguably CSS is Turing complete. Someone has proved as long as it's level three. So that's a programming
language. Now a lot of the UI is written in JavaScript. A lot of the down and dirty stuff
is written in C++. And more recently we've begun importing, Rust into the code base.
Rust is now a part of the released Firefox and, and more and more with the release of project quantum,
which was just announced last week, will be ported over to rust. So it's, so we can make more
guarantees so it can be safer and more concurrent. Nice. And what's, what is project quantum?
Project quantum. Let's see if I can get this right. Is a Mozilla project just became unsecret to import a lot of our
experimental, a Rust based rendering pipeline into Gecko, which is the current released,
Firefox pipeline. So project, that I mentioned serve already. I forget.
No, the sort of thing we're importing things from is servo an experimental web renderer written in rust,
a CSS renderer, HTML, all that jazz. And, yeah, we're, we're pulling bits of that into Gecko.
Okay. That's awesome. It's a very exciting time that'll let us be more concurrent and use all these
different cores on all these different things. You know, phones even have four cores now.
Yeah. Watches even have multi cores now.
Yeah. It's crazy. It's a crazy time to live.
It is a crazy time. You said another thing you're working on is fathom. What's fathom?
So fathom kind of, fits into all this, this parsing subject. Fathom is my new kind of toy over at
Mozilla. It's a mad scientist project to see if we can make it easier to write semantic extractors for the web.
So an example of a semantic extractor you might know is something along the lines of readability
or a browser's reader mode, where it just pulls the content text out and dispenses with headers and
footers and ads and such. But other things you might want to extract are, Hey, let's, let's teach a browser
to recognize what a previous or next button looks like. So that maybe the browser can let you assign
a keystroke to that in the general sense and not have to chase them as they bounce around as you advance
through a slideshow. Or maybe we can teach the browser at a deeper level to appreciate what an
advertisement is or what a navigation element is. So maybe we can collapse those on small screens and
hide them in a menu. There really, there's really endless potential to this. And I'm trying to
fix it. So those extractors are easier to maintain, faster to write and become less of a mess.
If you were to read the readability source code, which is kind of the thing that both Firefox's
reader mode and Safari's reader mode are based on, you get the sense that it's been written by hand,
maintained over time. There is state flying everywhere. It's hard to tell where to make tweaks.
So what Fathom does is express these extractors as lists of unordered rules in a prologue sense. If
you've ever played with prologue, it's just a whole bunch of kind of, logical statements. And then
the environment figures out how to fit those together and run them. Well, Fathom, works along those
same lines. And as a result, since order doesn't matter, third parties can tweak and, can tweak an
existing extractor just by inserting their own rules. They can say here, whenever you see a,
uh, whatever kind of element, for example, I want to boost the score by this much or lower it by that
much. Nice. So you could put like understanding of time of calendars and dates and whatnot, possibly
as another rule. Exactly. Hey, this looks like a calendar or, Hey, this looks like a payment form.
Let me help you fill it. Yeah. Okay. Yeah. That's awesome. Is that in Firefox yet? Or is this,
this is just a project so far? We hope to get it in so that, other things,
can make use of it more easily, but, it's already embeddable within Firefox add-ons and has
been embedded in, at least one add-on. It's kind of a Fathom debugging add-on.
it runs on the server side. It's all just kind of vanilla ES6. You can compile it down to ES5 for
older browsers. It kind of runs all over the place. I wrote it in JavaScript despite not liking
JavaScript myself so that we could get it, popular. Yeah. Sometimes, sometimes you got to go with
that. Well, that sounds really cool. And then another thing that you're involved in is
let's encrypt, which is very exciting. Yes. Let's encrypt has probably got the easiest
business plan I've ever heard, which is to give away a hundred dollar bills.
How's that work? How do I, how do I get my a hundred dollar bill?
Well, if you've ever bought a, well, it's very easy. So certificates,
this is all certificates have historically been fairly expensive on the order of a hundred bucks.
And there are some other ways to get cheaper ones through start SSL or Komodo or whatever is kind
of a hassle. But what we do is we have a little command line tool that you run. And if,
if you can authenticate yourself to our little, certificate creating server through a DNS record or
putting a little thing on your server temporarily, then we will give you a cert, which is recognized by
all the major browsers. So really there's no way, no reason not to use it at this point.
Yeah. So having encrypted content is obviously important if you're doing like e-commerce or something
like that, but it's also just becoming increasingly important to be a first class citizen on the web,
right?
It really is. It, I mean, it gives you the impression of trust. First of all, if people are
watching their URL bars, but also it's important for your visitors just to have the requests be private.
If I'm surfing to Wikipedia and, not doing anything particularly suspicious, but say I have a
suspect, I have a medical condition and I'm reading about all these different skin diseases or whatever
is ailing me. I don't want my ISP logging that away and selling it to their marketing partners,
which until the FCC's ruling last week was perfectly legal to do state actors. I mean,
the best defense we have against really anybody in the future coming to power and looking into our past
and seeing things they don't like, and then coming down on us is keeping things that are our business,
our business and using, SSL certificates and surfing to secure sites is the best way to do that
right now.
Yeah. And the fact that let's encrypt is, is free makes that very, very possible. And I think that's,
that's great. You know, there's a really interesting studies quoted in the original Edward Snowden book
that came out, I think, by Greenwald. I can't remember that guy's glad Greenwald, I believe.
Yes. That guy. And it was a great book. And basically, you know, a lot of people say, look,
I don't care about this privacy stuff. Like I have nothing to hide, but there've been psychological
studies and social, social studies saying people behave differently. If they know somebody's listening,
they might not break a rule in private, but they behave differently. They are slightly more private,
less willing to think, you know, sort of contrarian ideas and at least share them. And the less that
people are watching the better as far as I'm concerned for, for people in general.
Yeah. It's really the idea of chilling effects, which came out of some academic institution. It's
a wonderful phrase. And when you have chilling effects in operation, where you are afraid to do
perfectly legal things, which otherwise you might not do, democracy really cannot function.
How democracy works is by means of, well, really the Overton window, this range of things that you're
allowed to say and think that don't get you kicked out of cocktail parties.
And this window moves around over time. It's, you know, yesterday's conservative, rather yesterday's
progressive is today's conservative. And if we're not allowed to play with ideas that are just outside
the bounds of the Overton window, then the future really has nowhere to pick its new ideas from.
And we just kind of stagnate and the powers that be become the powers that always will be.
And the ideas that are, are the ideas that always will be, and we can't really go anywhere.
So, yeah, I think privacy is key to having a functioning democracy at all.
Yeah, I totally agree. And if you don't buy that, Google ranks sites higher if they have SSL.
We all want to rank higher in Google, right? So there's the Google juice.
There's the final straw to, like, start encrypting stuff. My blog's encrypted. This podcast site is encrypted and so on.
And I think it's great. Happy to do that on as much as I can.
I'm wondering, how did you become interested in parsing all these horrible things? Where did you get started with that?
Well, I guess, I guess it probably started when I was seven years old and playing around with basic and hypercard and thinking,
oh, you know, I want to write my own programming language because, of course, you're seven and no one has told you that it's hard.
And if you spend a couple of days trying to do that with just if statements, you end up in this spaghetti-fied mess and you can't get anywhere.
And you're just amazed that anyone has ever managed to write a language ever.
So, you know, then put in a little pause of about 25 years and it came up at work.
Over at Mozilla, we had a support site. We still have a support site.
Support.mozilla.org. And it's got a wiki and it's got a Stack Overflow clone and all this different stuff to help out people who are using Firefox and our other products.
And our wiki is powered by not MediaWiki itself, but the MediaWiki syntax for various hysterical purposes, as we like to say.
And not only do we want the MediaWiki syntax, but we wanted to be able to add our own little directives to the syntax.
Crazy little things that'll maybe, well, one example is we wanted to change the text that would come up according to which version of Firefox someone was using to visit the site.
It was very, very difficult to make those edits to the implementation of MediaWiki that we were using, which was a port by David Kramer, very nice little port, of the original MediaWiki machinery.
Such a direct port, in fact, that it still had dollar signs in the comments from the PHP.
Right. Yeah, it was originally PHP and you guys translated it over to Python and that helped because at least you were working in Python.
But you said the way that it worked was the parser was pretty insane.
Like it was just like a crazy bunch of regexes, right?
Yeah, there were, I think, 41 regexes.
And then there was another 2,100 lines of PHP, which just ran them over and over again against the source text, finding and replacing and finding and replacing, hopefully in the right order, interacting with each other, dropping little markers so that they didn't smash over each other when they shouldn't.
And then hopefully at the end out comes the proper rendered text.
Of course, in reality, MediaWiki language changes from release to release as they find little corner cases that this crazy slapdash loopy way didn't handle.
Yeah, you called it the Klingon MediaWiki.
Yeah, I look at these regexes and I think, well, this is the original Klingon, clearly.
Yes, obviously.
Nice.
And so you were looking for a way to escape this Klingon parser world and create something nicer.
Like one of the problems you said that was inherent in the algorithm was it would directly parse into its new representation.
Right.
There was never an intermediate representation.
So tell people what, like, is, like, why do you care?
Like, what's the intermediate representation do for you?
Well, it gives you flexibility, like any abstraction.
So let's say we have this imaginary intermediate representation for MediaWiki syntax.
We bring in the MediaWiki syntax.
We parse it into a tree because that's what all these things end up as in parsing land.
And then we have a lot of options.
We can output plain text from that, ignoring the bits of the tree that say bold or italic.
We can render out HTML from that, not ignoring those things.
We can go hunting through for just, say, date or time elements and pull out some date and timey entities.
Once you have this abstraction, you have any kind of output you like.
Or you can do any kind of analysis or transformation you like.
Nice.
So, for example, if you wanted to possibly represent stuff by a markdown output or an HTML output or plain text, those are super easy because both, like, markdown and HTML have a bold concept.
One is a bracket, you know, angle bracket strong.
One is a star.
But it's, you know, you can do that final translation pretty easily once you have the tree, right?
Exactly.
That's the trivial part, going from tree back to a linear representation.
So the hard part is getting it into a tree, huh?
Right.
Now, we're doing that as we talk, which is nice.
Now, you make a linear sequence of sounds.
And I hear them.
And I deconstruct them back into, you know, phrases and word pairs and things and idioms.
And I say, wow, that's probably what he means.
And then you do it back from my end.
Yeah, exactly.
So pretty much pulling structure out of any flat, linear stream of data is parsing, right?
Exactly.
And so the applications are as wide as you like.
I mean, anything that has any kind of structure, text, sound, you can think of musical phrases
and the sorts of, a lot of music has a theme in variations or development of a thematic statement.
On one hand, I sort of can see how you would do some of this with regular expressions.
But it's really the goal is to move it into this parse tree because then it's not just transforming
one bit of text into another text, but it's actually transforming into the structure that
we can do all kinds of interesting things, huh?
Well, right.
And more formally, regular expressions can't really support nesting.
Now, there are little corner cases that people were going to write in about where things that
are called regular expressions nowadays, like in Perl, have support for nesting bolted on,
but then they cease to become proper regular expressions.
Exactly.
Proper parsers, on the other hand, descend into the, what we call, like, Chomsky type one or
two grammar and can support nesting.
So you could say, understand sets of nested parentheses of arbitrary depth.
And that's how things like, well, HTML, for example, are.
You could have a bold tag with an italic tag in it with another bold tag in it at infinitum.
Yeah.
Div, span, A, all sorts of stuff.
Yeah.
More div.
And in addition to the nesting, a proper parser gives you the ability to read what you're doing,
essentially.
Regexes are famous for being a write-only language.
Absolutely.
I definitely think of them as write-only.
Yeah.
And you can comment them as much as you like and put white space in there, but it still
becomes, you know, at least awkward to name sub-patterns, to repeat sub-patterns, and to
maintain something where you have repeated bits of regex.
Sure.
Well, and as it gets increasingly complicated, the more you need the regular expression, the
less you can understand it, I think.
Yeah, for sure.
There seems to be a ceiling for one reason or another with straight-out regexes.
Yeah.
So you talked about there being different types of grammars that are different complexities
of grammars.
Yeah.
There's the idea of the Chomsky hierarchy of grammars.
And Chomsky is really a linguist.
And so he spoke of these grammars in terms of generative power, where, you know, I can
start from a production, a production name, something like sentence, and then descend in
one level and say, well, sentences, you know, phrase, and then maybe another phrase, and maybe
another phrase.
And what are the phrases?
Well, we have a subject, and we have verb, and we have an object.
And he's interested in creating sentences from the top level.
Now, as computer scientists, we're usually more interested in going in the opposite direction,
starting with this complete sentence, and then kind of inferring out the structure, recognizing,
as they call it in the literature.
So Chomsky came out with Chomsky hierarchy of grammar, something like that.
Anyway, levels 0, 1, 2, 3, and 4.
And type 0 is basically a free-for-all.
It kind of comes out looking like a directed graph.
And there's not really, really available kit for parsing that sort of thing, or any algorithmic
bounds to its complexity.
When we get down to a level 1, that's your context-sensitive grammars.
And Python is actually a context-sensitive grammar, I believe only for the reason that it has,
only because it has whitespace sensitivity.
So I was actually trying to parse something like Python the other day, a little side project
of mine called Turtles.
And I ran up against this.
When you indent in Python, in a normal language, in a curly brace language, when you go inward
a block, you say, curly brace.
And then when you end a block, you say, end brace.
Now, in Python, think about trying to write a tokenizer for Python, trying to find those
instances where we go in a level or out a level.
You're reading along, you're reading along.
You're at the beginning of a line, and you see eight spaces.
Did you go in a level?
I don't know.
What is the previous line?
Is it four spaces?
If so, I went in a level.
So you can see that eight space span is interpreted differently depending on our context, depending
on what the previous line had done.
So Python is a context-sensitive grammar.
Now, the rest of Python is at Chomsky level two, which is a context-free grammar.
So if you were to dig into the Python source code, one of these files there, there's a little,
let's see if I have it sitting here, a nice little sort of summary where it says, okay,
here's what a suite is, a series of statements.
A suite is a statement, statement, statement, or statement star.
But it's always that.
A suite is always this.
An if statement is always that.
You know, a function definition is always this.
It doesn't matter what came before or what comes after.
It's context-free.
Right.
Like, the if statement doesn't mean something different if it's in a while loop.
It always means the same thing.
So if you know what an if is, like, if you can define the structure of an if, you can define
its meaning.
And you don't have to do more interesting parsing.
Yep.
All the time.
All the time, if means the same thing.
There are no modes to go into or out of.
This portion of Talk Python To Me is brought to you by GoCD from ThoughtWorks.
GoCD is the on-premise, open-source, continuous delivery server.
With GoCD's comprehensive pipeline and model, you can model complex workflows for multiple
teams with ease.
And GoCD's value stream map lets you track changes from commit to deployment at a glance.
GoCD's real power is in the visibility it provides over your end-to-end workflow.
You get complete control of and visibility into your deployments across multiple teams.
Say goodbye to release day panic and hello to consistent, predictable deliveries.
Commercial support and enterprise add-ons, including disaster recovery, are available.
To learn more about GoCD, visit talkpython.fm/gocd for a free download.
That's talkpython.fm/gocd.
Check them out.
It helps support the show.
One of the things that you said, a quote from your PyCon 2012 talk, which I'll link to
the show notes, of course, was that parsing is a gateway drug to other areas of computer
science.
It's true.
I mean, once you have this tree-shaped intermediate representation, you can do anything you want.
You can get into natural language processing, which if you're doing any of this in Python,
NLTK is a not-to-be-missed library.
It, first of all, is a shining example of what all library documentation should be.
There is an NLTK book freely available and is a fantastic place to start if you want to
start understanding human language with a computer or doing sorts of data mining and machine learning.
It's also full of those sorts of algorithms.
Great piece of kit.
Yeah.
Awesome.
Also, from the intermediate representation, you can get into programming language design.
That's fun.
Make your own little toy language.
Anybody can make a lisp in a couple of days because the parsing is so darn simple.
It's just a bunch of nested parentheticals.
There's a lot of parentheses there.
Yeah.
Now I'm a lot less intimidated to reach for custom little query languages.
Like, DXR has a custom little query language, which looks a lot like Google's custom little
query language.
And it's, you know, 10 or 20 lines of grammar description that I feed into my library parsimonious.
And out comes the tree.
Yeah.
That's really cool.
I feel like when you learn these new techniques and these data structures and algorithms, like, you see problems where you just saw opaqueness before.
You're like, oh, I could actually apply this thing.
And out would pop interesting answers.
Whereas before, you're just like, there's no way I can answer that.
That's just text blobs, not structure.
Yeah, for sure.
It's just pattern recognition.
The more you've exposed yourself to, the more you'll say, hey, this is just one of those.
Let's review some of the various options for parsing text in Python today.
So there's two pretty well-known ones that have been around for a while.
There's PyParsing and there's PLY.
So David Beasley's Python Lex Yak.
Yeah, PLY is fantastic.
And anything that David Beasley does is fantastic.
You should immediately pause the podcast and go watch all of his talks.
PLY came out of when he was teaching a course on building your own little Pascal interpreter, I believe.
PLY has the advantage of being tripped over by hundreds and hundreds of students.
And they've hit every little corner case and made every possible mistake.
And so the error reporting is top notch.
And really, I would seriously recommend taking a look at PLY if the complexity of what you're parsing is amenable to it.
Now, the limit of PLY and why I couldn't use it for the MediaWiki stuff is that it implements what we call LR1 parsing, which you can look up the formalisms.
And I probably forget most of them.
But this is something we did.
I think most languages that are currently in production probably use something along the lines of LR1 just because it's very, very memory efficient and CPU efficient as well.
So it was a thing that we implemented when we had tiny little computers.
But where you run into problems is that LR1, that one means we can only look ahead one token to decide what kind of thing we're recognizing.
And in the case of MediaWiki, that wasn't actually enough.
For example, I believe it was internal links that begin with two brackets, bracket, bracket.
So it's not every time that bracket, bracket means an internal link.
It has to be followed by, oh, I'm going to get this wrong, but something along the lines of maybe a URL or page name, and then maybe a vertical bar, and then maybe a page title.
And so you might have to look ahead two or three tokens to see if your internal link is going to work out.
And if it doesn't, that bracket, bracket is just part of plain text and should be emitted verbatim.
And so we couldn't use any LR1 parser, and I put that on my shopping list and ruled out a whole lot of libraries because of it.
Right.
It just needs to keep more of it in its head, in the algorithm, all at once, right?
Pretty much, yeah.
All right.
So what's the story with py parsing?
So py parsing is what I consider or was the canonical, I reached for it first, Python parsing library before I wrote my own, of course, because I'm in that bad habit.
And py parsing is, you know, fairly Pythonic.
It mashes all the grammar definition stuff into Python objects.
So you literally say in a piece of Python, bold toggle equals literal parentheses, and then you construct an object, you say, quote, quote, quote, and say, okay, well, quote, quote, quote, is the thing that turns on bold in media wiki syntax.
And then on that object, you call methods like set name bold toggle, so that when you have this tree, you can actually tell that this thing was a bold toggle as you're walking the tree.
And kind of on you go.
Now, the disadvantage of this is it's kind of hard to read.
It's kind of wordy because, after all, we had to make this a valid Python.
And you can't do certain things like make forward references.
And oftentimes there are cyclical references in a non-trivial grammar.
In the case of py parsing, they had to put a little hack around that and say, you know, bold toggle equals forward, which is sort of a promise that I'm going to declare something later.
And then later on, you kind of jam that on.
For people who haven't seen the syntax of py parsing, it's kind of like formalized Python that acts as regular expressions.
So you'll see like Python objects, but they're clearly coming from sort of regular expression land like groups and whatnot, right?
Well, I mean, groups is a valid word to use when you're talking about parsing.
After all, we're talking about trees here, and a tree is nothing more than a nested list.
And so every sub list you can think of as a group.
So that's what py parsing is doing with the groups.
Yeah, okay.
And py parsing is of, I think, equal power with parsimonious.
They're both able to describe all the context-free grammars and probably a subset of context-sensitive ones.
And parsimonious is your library that you wrote, right?
Yes, it's my mad scientist experiment.
Though its version number starts with zero point, I have it in production all over the place.
There are lots of people using it, so.
Nice.
Do you have some examples for what it's being used for?
Yeah, well, I'm using it in DXR to parse our little query language.
What awesome people are using it for?
You know, they don't report back to me, but it gets a lot of downloads.
Yeah, excellent.
So it's out there somewhere.
Excellent.
So to me, it seems like parsimonious, it's a little simpler to define the grammar.
Is that right?
That was really my goal, both to make it simpler, to make it run fast, and to make it optimizable.
One of the goals you said was frugal RAM use, which I thought was just a great way to phrase it.
Yeah, and I haven't done a lot of RAM profiling, so I'm not ready to make any claims about that just yet.
But the formalism underneath parsimonious, which is parsing expression grammars, which come out of a 2004 paper by Brian Ford, meet that goal just fine.
I think RAM use is something along the lines of order n to the third, but n is the grammar size, so it's actually not that big an n.
And as a result of blowing that RAM, it's caches for each individual little production, each individual little context-free equals.
You get linear parse time.
Yeah, which is great.
Yeah, that's really, really nice.
So the reason people care about RAM is, I mean, if you're running this over some text and you're just going to dump it out and produce a text version, that's fine.
But if you're wanting to keep that in memory and say like a web server and continuously serve requests from it or something, then all of a sudden you care way more about RAM, right?
Well, just imagine serving up a bunch of media wiki pages and you've got to be parsing 100 of these at a time on a web server.
You know, RAM is not free.
No, it's definitely not free, especially if you've got a lot of traffic.
So one of the algorithms involved in here is you said that it uses something called the PackRat algorithm, which sounds fun.
What's that?
Yeah, I think Ryan Ford came up with that too.
It's really simple.
It's what you would come up with yourself if you're implementing one of these.
These PEG parsers, PEG parsers, they're really just recursive descent parsers.
And as you descend, you might find out, hey, now that I've looked ahead to tokens and I find out this internal link isn't going to work out for me, I need to rewind a little.
Let me take a couple steps back up the stack and let me try parsing it as plain text, for example, or maybe as an external link, for example.
And in the course of that, you may need to use a partial parse from a previous stack frame.
And rather than redoing that work, it makes sense oftentimes to cache the results of each partial parse.
And that's all the PackRat does.
Just keeps all these intermediate results around.
I see.
Basically to allow you to look ahead an arbitrary number of tokens and then adjust.
Without paying a penalty of redoing work.
Exactly.
Right.
Yeah.
Very cool.
Well, one of the things I was mostly trying to do with parsimonious, one of the things that really the thing that differentiates it so much, was that its grammars look a lot like what you'd find if you looked up the definition of the grammar in a book or in the documentation.
They're just big blobs of multi-line text in the Python quote, quote, quote, quote way.
And so it's able to do forward references because it's not bound to the idea of undefined symbols in an outer programming language.
We're able to do compile time optimizations on it really without limit because we haven't lost anything in its transformation down to a bunch of Python objects prematurely.
And it's also very easy to read as a result.
And you also keep the representation part as a separate phase so you can render to multiple formats, which is cool.
Yes, exactly.
A lot of these Python, not Python rather, but a lot of these parsing kits tend to inter-twingle output rendering with parsing.
And that way leads to pain in my experience.
Certainly rigidity.
Interesting.
It sounds like your parsimonious project is really cool.
And it's on GitHub.
People can check it out, right?
Please.
Send feedback.
Play around with it.
Send patches.
Okay, cool.
Yeah, one of the things that made me a little bit sad about PyParsing is it's on SourceForge, which I don't know.
Wow, still?
Yeah, when I see things on SourceForge, it kind of makes me feel like, oh, I'm not really sure that thing's actually still going.
Yeah, right on the homepage it says, download now from SourceForge.
It's like, oh.
Oh.
Okay, that's unfortunate.
It's still fine code.
I mean.
Yeah, of course.
It is a single 3,000 line file.
But, you know, old doesn't mean bad.
It means proven.
Yeah, absolutely.
Absolutely.
So that was a really cool talk on parsing horrible things you gave.
Do you have some other favorites?
Oh, let's see.
What else have I done?
I have a talk called Poetic APIs, where I kind of will expand on the idea that, you know, these grammars, they should be really easy to read.
In fact, all programs should be easy to read.
In fact, here are seven, you know, kind of checklist-y things you can bang against what you're writing to make sure that you set a good language for the users of your API.
Oh, interesting.
Yeah.
What we're doing when we're programming is always creating language.
Every time we name a function, name a variable, create semantics of an object, we're kind of creating the mental model in which everybody who interacts with that code in the future has to play.
So if we do that irresponsibly, we can really make people think terrible, stupid thoughts that make their jobs hard.
But if we give them really good symbols that correspond well to reality and are easily composable and flexible, like the requests package is a great example.
Like, hey, you know what?
We could just totally represent HTTP requests instead of making everyone think about raw sockets all the time, like URL lib.
Then people can have their efforts magnified.
Yeah, it really does define the way that you think about a problem, the APIs and whatnot you have to work with, and the language itself, right?
And so I think Python itself is something, an example of, like, why that's important, right?
Well, yeah, I mean, so Python is a fairly close match to what we tend to write as pseudocode.
Right, and the reason we write pseudocode is it's easy to understand and communicate, so.
Exactly.
I was just reading the topographical sort algorithms on Wikipedia, and you know what?
If you put some colons in there and take out the eaches, it's about valid Python.
That's awesome.
Yeah, I've heard that before, that people have copied algorithms out of Wikipedia, more or less, just straight up.
Turn that into Python, and it works beautifully.
That's great.
Which is also interesting verification of Wikipedia content.
Yes.
This portion of Talk Python To Me is brought to you by Hired.
Hired is the platform for top Python developer jobs.
Create your profile and instantly get access to 3,500 companies who will work to compete with you.
Take it from one of Hired's users who recently got a job and said,
I had my first offer on Thursday after going live on Monday, and I ended up getting eight offers in total.
I've worked with recruiters in the past, but they've always been pretty hit and miss.
I tried LinkedIn, but I found Hired to be the best.
I really like knowing the salary up front.
Privacy was also a huge seller for me.
Sounds awesome, doesn't it?
Well, wait until you hear about the sign-in bonus.
Everyone who accepts a job from Hired gets $1,000 signing bonus.
And as Talk Python listeners, it gets way sweeter.
Use the link Hired.com slash Talk Python To Me, and Hired will double the signing bonus to $2,000.
Opportunity's knocking.
Visit Hired.com slash Talk Python To Me and answer the door.
There's another one that you talked about called the Code Review Review.
What's the story of that?
Yeah, this is a newer talk.
So something we're trying to do at Mozilla is make sure we don't drive people away by being jerks,
doing code review or otherwise having kind of unwelcoming culture.
Mozilla is historically and today largely driven by volunteer contributions.
I mean, even the guy who owns our security sockets layer or something,
or the NSS, whatever that is, like the module owner for this, the one who has the final say,
he doesn't get paid by Mozilla.
He does something else, and he just takes it on this responsibility out of his own free time.
And so it's really important for Mozilla to keep that rolling, you know,
welcome people into the community, take in contributions,
help people level up to become better programmers and more familiar with the project.
And so the Code Review Review is a piece of our onboarding right now
that I'm turning into a more generically applicable talk where we talk about,
well, you know, how do we create that kind of welcoming atmosphere?
How do we do a proper review so that good programs come out?
And how do we do a review such that better programmers come out of it?
Yeah, that's really important that people, when they come to these new projects
or when they stick around, that they feel like it's a delightful experience
because they're doing it of their own free time and energy, right?
Yeah, for sure.
You definitely don't want it to be like slugging through a hard code.
I mean, I think an example of the opposite comes to mind is the old Python packaging,
PyPI web code.
I talked to Donald Stuffed on episode 64, and he was like,
a lot of people want to come along and help maintain and evolve this,
but it's like two files in this hugely complicated old custom web framework that they built for it.
It's just people look at it, you know, actually, thanks, but no thanks.
And finally, they're rewriting it at pypi.org, and it's in Pyramid and Bootstrap, and it's lovely.
But for a long time, I think it turned people away from pushing that project forward,
and you could tell that it kind of, it was just getting maintained, which is good,
but it's also evidence of this anti-approachability, I guess.
Yeah, it's kind of funny how all those old projects tend to be like two enormous files.
All I can think of is folders must have been expensive 20 years ago.
Yes, exactly.
Really expensive.
All right, so what else?
We've got a few moments to talk about a few other things,
and I know you've got a lot of interesting pieces out there.
What else is going on?
You're doing something with pip, right?
Oh, pip, yes.
So we deploy a lot of Python at Mozilla,
and we used to check everything into a vendor library,
you know, just to be sure no one had slipped anything under the radar,
anything malicious like that.
And vendor libraries are a pain to maintain.
You know, you have to update the versions of things,
and that creates enormous diffs in your version control,
and then checkouts take forever, and your checkouts are huge.
And so we, for a while, ran an internal PIPI mirror.
A lot of people run their own little index server,
and you kind of keep track of who's allowed to upload what to the server,
and then who did it last,
and what versions are going to work with your own projects,
and you have to keep an access control list and an audit trail.
And that was a pain, and it slowed things down.
And then I thought, well, you know,
we were actually having a beer and tell.
We have these little sessions where we have a beverage of our choice
and talk about something that we've been playing around with as a side project.
And I needed something to talk about one day,
and I thought, well,
why not just hash the results of what you download from PIPI
and make sure they match some local hash that you've pre-vetted,
and then go ahead and install it?
And so I put this thing together as this little tool called PEEP for prudently examine every package.
And we ended up moving the whole production lifecycle over to that for a number of years, year or two.
And then I thought, well, okay, this is proven out.
And PEEP called deep into pip's internal APIs, and so it would break all the time.
And it was a pain to maintain.
I thought, you know what?
I'm going to lift this up into pip, see if I can get people interested.
And long story short, I did.
People were interested, and it's in pip 8 and above.
So if you're out there deploying Python and running your own index server
or keeping up to date with a vendor library,
hey, consider just putting a bunch of SHA-256 hashes into your requirements file
with a funny little syntax and running pip 8 over it.
And it'll vet these things for you.
I mean, it won't vet them for you.
You have to make sure that there's nothing malicious in a given version of a package,
but it'll make sure that what you got that first time is the same thing you got.
Yeah, once vetted, it'll verify it can't change.
So what do you do?
You can't just say, I depend upon SQLAlchemy.
You've got to say, I depend upon SQLAlchemy 1.0.whatever, and here's its SHA.
Dash, dash, hash equals whatever it is.
Right, because obviously if the version changes,
you'd imagine the code would change and the package would change.
Absolutely.
I see.
And I try to keep the handholding in there
so that if you forget to pin the version but provide a hash,
it'll say, you know what?
You should really pin the version because you're going to have an unpleasant surprise down the line.
This is a really stable product.
You're going to find out that this is not the same.
Awesome.
And you mentioned Turtles before.
What's Turtles?
Turtles is a real mad scientist project.
So I used to do a lot of Zope and Plone consulting back in the day,
and I watched a lot of really smart people from all different walks of life.
You know, it was in higher ed, so there were professors, and there were very good writers,
and there were sys-ops, and there were chemists,
and they'd come in, and we'd have to teach them,
okay, how do I build a website,
or how do I use this content management system that has Python underlying it?
And they'd have to learn HTML, and CSS, and JavaScript, and Python,
and then ZCML as a control language,
and DTML for dynamic CSS back in the day,
and all these crazy different languages.
And it was ridiculous,
and they would get discouraged and go away, a lot of them,
or at least not work to the potential that I thought we could provide them.
And so Turtles kind of had its genesis there.
I thought, you know, if only we had a single language that we could use end-to-end,
and we didn't need to constantly reinvent, say, for loops,
or variables that allow us to not repeat ourselves,
and have a different way to do variables in Python,
and a different way in CSS, and another way in JavaScript,
wouldn't things be easier to learn, and easier to remember,
and heck, easier to read?
And wouldn't we have all of these synergies?
Turtles is one of those.
Turtles is a single-language system, or will be, I hope, for web development.
Right now, it is just a context-sensitive parser that does run,
but everything else is still up in the air.
Interesting.
So basically, instead of teaching people these three or four languages,
when they come, plus the frameworks, you're like, look, learn this one thing,
and you'll have a website, a full-on website.
That is the idea, to teach them, you know, an hour or two's worth of stuff,
and then have them be able to make real progress without an internet connection.
You know, make this thing explorable, like the old small talk environments used to be,
where you can drill into an example and take it apart and rip out pieces that you want to use,
where you can make changes to a live system and see what happens.
I mean, that's really how I learned programming, by mimicry, which we don't really do anymore.
You know, I had to type this stuff out of magazines, make mistakes,
see what the effects of the mistakes were, fix the mistakes,
and then screw around and make my own new mistakes and see what effects they had.
I think that's how we learn human language, and I think it's a powerful way to learn programming.
It is a powerful way, but we've definitely moved beyond that in lots of areas.
I mean, I try to, I think of getting started with, like, Node.js and, like, the crazy packaging and requirements and all that,
and it's like, I thought that was a simple thing to get started with, you know?
But I feel like I've done a better job of keeping it simple.
But still, how do I know where a package comes from?
If I type import requests, why doesn't that run, right?
Like, when you're new, all these challenges that we are just like, yeah, whatever, just pip install or whatever,
I just, you forgot that step.
These are all levels of friction.
Yeah, that's one of the things that I'm trying to solve in Turtles by making the answer always the same.
You ask, where does this come from?
Or where do I put this?
And the answer is always in Turtles, it goes on a page.
Your config goes on a page.
Your program goes on a page.
Everything goes on a page.
The thing that we've lost in the web, because the web is a state-free kind of environment,
is that the default behavior is for everything to go poof.
You put something in a forum, you leave the page, poof, it's gone.
Unless you're, you know, using a nice browser like Firefox where you can say, hey, reopen that tab,
and then your content comes back.
But as a developer, you have the same problem, right?
You end up writing these template languages, and you end up having to take state and shuttle it aside
into some other process, into a relational database or a document store or something,
and then reconstitute, rehydrate these pages all the time out of these databases,
where the representation may not look anything like the structure you're actually trying to pull out.
And so the idea with turtles is put everything on pages and have a single representation for everything,
which I think is going to be trees.
Because as we said with the parsing stuff, trees are a very good choice for universal representation of things.
You can do a lot with trees.
It definitely sounds like an interesting project.
So there's nothing quite yet that we can go play with, but you're working on it, huh?
Nothing but 100K of design notes and parser up on GitHub.
But yeah, not quite ready yet.
All right, cool.
I'll keep us posted on that.
That's great.
All right, so another thing that you said you're into these days is GTD or getting things done, right?
Oh, my gosh.
Changed my life.
So as a repeat offender of Python library creation, I have the open source guilt.
I put this thing out there, and people are like, oh, well, it's broken this way, and it's broken this way,
and I wish it did this, and here's a patch, and why don't you review my patch,
and shouldn't you be doing this instead of watching Netflix and spending time with your family?
I'm like, well, I guess.
And the guilt builds and builds and builds, and you're just kind of,
you know, you're just kind of shaking all the time, and you can't relax.
So GTD, I got this book at work seven years ago.
Somebody gave me a copy and it sat on the shelf for seven years, and I picked it up,
and it has all these little helpful practices for getting rid of that guilt
and making sure you're always working on the most important thing at any one given time.
And you know what?
It's really changed my life.
I no longer have the guilt to such a degree.
Hardly at all, really.
My response time has gone way down.
My email box has been at zero.
I mean, my work one and my home one were 5,000 before.
Now they've been zero for months.
And it's been easy.
It's a crazy thing.
That sounds delightful.
Yeah.
I've read that book, and I've lived the GTD lifestyle.
And I found it didn't quite work for me, but I gained a huge value from doing it.
And so if you can find a few techniques to help tame the world, whether it's so you have
better response time on your open source project, or you're not stressed all the time, or you
can go home and see the family and not have the weight of 5,000 unread emails on you, these
are all good.
The biggest thing that helps me these days is Google Inbox with its ability to snooze items
for two weeks until that item comes back right when I'm supposed to deal with it and things
like that, that's actually been sort of where I've evolved to.
But GTD is great.
Yeah.
For real.
And nobody, you know, you say you don't use GTD per se because it didn't work out for you.
Well, nobody uses vanilla GTD.
It's, you know, it's made to be customized.
It's a grab bag of tricks.
And some of them are, you know, more important than others.
Some of them are, you know, kind of vital, and some of them are optional.
Yeah, absolutely.
And you ran into something with that inbox that really rings true to me.
I had been trying for years to use my email inbox as a sort of quasi-touching.
To-do list.
I'll leave this in my box because I'm going to need it in three days.
And so for some reason I thought it's expensive to do a find.
I don't know why I thought that, but that's what I thought apparently.
Or, you know, oh, I need to respond to this mail, so it's going to stay in there.
And it ended up just being this mixture of chronologically sorted things, some of which were reference material, some of which were things to do, some of which I couldn't do for a certain period, like you said, and needed to be snoozed for two weeks.
And yet the only way it would present them to me is as this linear kind of last-touched first list of things.
It's not a useful presentation.
And I have been unable to make any email client really bend to my will as a to-do list.
And so the reason my boxes are empty these days is any time there's an actionable email item that takes me more than two minutes to do, because otherwise I would do it immediately as part of GTD, it goes into my to-do system.
And it pops up, like you say, when you're able to take action on it.
It's really a wonderful thing.
I do agree with that.
So I would be remiss not asking which to-do system you use for this.
So I went shopping.
I wanted something that – so I'm kind of weird.
I wanted something that was expressly not cross-platform, because I think that the platform-specific stuff usually ends up with a better UI, and I'm kind of a UI enthusiast.
So I looked at OmniFocus.
I love all of Omni's stuff.
I love OmniGraffle and OmniOutliner.
I read all my talks on OmniOutliner.
And I really wanted to like OmniFocus.
But there were a couple things that it was just grating against me, and it wouldn't do what I wanted.
I couldn't reorder tasks except within projects.
And I kind of like to plan my day out.
And so I ended up with something called Things by a little German company called Cultured Code.
And it's a Mac and iPhone-only gadget.
It uses their own little cloud sync service.
And the UI has been thought out in great detail.
Development goes glacially slowly.
That's the downside.
These people seem very, very intent on getting things exactly right and not releasing until then.
So that's the downside.
But Things is great.
Things lets you schedule things out ahead of time and not bother you until then.
It lets you express due dates like, well, this drop dead has to happen now.
And it does all the D2D-style contexts.
Let me know about this when I'm at home or at work or in the car or what have you.
It's nothing particularly, you know, whizzy from a technical point of view.
But it has those kind of three core features of contexts and due dates and hide until that any large-scale to-do system needs.
Oh, yeah.
It looks really, really cool.
All right.
Well, thanks for sharing your research results there.
That's cool.
Great.
Okay.
So it looks like we're just about out of time.
We've covered all the horrible things.
Now let's talk about some cool things.
How about your favorite PyPI package?
Well, I mean, there's a lot of good ones out there.
I enjoy Flask.
I've used that to power DXR.
It's a nice little lightweight web framework by Armin Roniker.
Yeah.
I can't remember exactly who it is.
Yeah.
I hit him on one of the early shows.
Yeah.
All of Armin's stuff is fantastic.
It is.
Likewise, Click is a fantastic one by Armin.
It's, I think he kind of, did he pull it out of Flask?
No, he's pulling it into Flask, in fact.
Click is a kit for making command line tools.
And I pulled it into DXR as well because it makes it so easy to do nested subcommands.
Like if you use homebrew or something, homebrew install, brew this, brew that.
It helps you brew up commands like that.
And like all of Armin's stuff, it's sort of a decorator soup that I like very much.
Absolutely.
And then one of my own things that I always pull off the shelf when I start a new project
is more iter tools.
And it is, as the name says, more iter tools.
The ones that got left behind.
Collations and such that come in handy in almost every project.
Yeah.
Okay.
Excellent.
I'll be sure to link to all of those.
That's great.
And how about the editor?
Favorite editor?
Are you going to write some Python code?
What do you pull up?
I pull up a little Mac app called BBEdit.
It's been around for, must be 40 years or something.
Yeah.
They're on BBEdit 11.
I like their little subtitle.
I don't know.
It doesn't suck.
All rights reserved.
Yeah.
Bare-bones software.
It doesn't suck.
And they typically make software that looks like nothing.
You pull it up and their mailer looks like a big empty window of white.
And their text editor looks like a big empty window full of white.
Not a lot of toolbars.
Not a lot of fluff.
But under the hood, they do a really nice job.
The text editor uses what must be ropes because I can edit very large, you know, multi-tens
of megabyte files without a lot of lag.
It's incredibly stable.
It just doesn't lose data.
On the off chance that it maybe crashes every couple of weeks, its magical little implicit
auto-save thing will bring up your windows in exactly the state that they were.
Even your untitled documents, it won't save and plow over your stuff.
It'll save it in its own little buffer and just make sure nothing is unduly lost.
Yeah.
That sounds really cool.
All right.
Awesome.
So check that out, people.
That's cool.
And final call to action.
Well, if you're parsing in Python, give parsimonies a try and send feedback and complaints and
patches my way.
Yeah, definitely.
It's on GitHub.
I'll put the links to it in the show notes so people can find it there.
Thank you.
And second, be safe out there.
If you're running a web server, get a certificate.
Use Let's Encrypt or something else.
And if you're deploying Python, again, be safe.
Use pip hashing.
I really appreciate this look inside of the whole parsing world and how we can move beyond
regular expressions to do something way cooler.
So thanks for your project and your talk and being on the show.
It was a pleasure to speak with you, Michael.
Yeah.
Bye, Eric.
This has been another episode of Talk Python To Me.
Today's guest has been Eric Rose, and this episode has been sponsored by GoCD and Hired.
Thank you both for supporting the show.
GoCD is the on-premise, open-source, continuous delivery server.
Want to improve your deployment workflow but keep your code and builds in-house?
Check out GoCD at talkpython.fm/gocd and take control over your process.
Hired wants to help you find your next big thing.
Visit hired.com slash talkpythontome to get five or more offers with salary and equity presented
right up front and a special listener signing bonus of $2,000.
Are you or a colleague trying to learn Python?
Have you tried books and videos that just left you bored by covering topics point by point?
Well, check out my online course, Python Jumpstart, by building 10 apps at talkpython.fm/course
to experience a more engaging way to learn Python.
And if you're looking for something a little more advanced, try my WritePythonic code course at talkpython.fm/pythonic.
Be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, Google Play feed at /play, and direct RSS feed at /rss on talkpython.fm.
Our theme music is Developers, Developers, Developers by Corey Smith, who goes by Smix.
Corey just recently started selling his tracks on iTunes, so I recommend you check it out at talkpython.fm/music.
You can browse his tracks he has for sale on iTunes and listen to the full-length version of the theme song.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Smix, let's get out of here.
I'll see you next time.
Don't believe.
Thank you.