Python Standard Library, The Hidden Gems
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Molina, Alessandro
The Python Standard Library is a very rich toolset, which is the reason why Python is stated to come with ""batteries included"". In such an amount of features and tools it's easy to get lost and miss some of the less unknown modules or gems hidden within the whole load of functions and classes. This talk aims at showcasing some recipes, snippets and usages of standard library modules and functions that are less known or that are not covered in the most common books and tutorials available for Python. The talk will try to showcase a bunch of short examples in the hope to foster the ""oh, wow! I didn't think about that"" reaction at least once in the audience. We will see how frequently for tasks where you used third party libraries or frameworks a solution bultin into the standard library is already available, and such solution is guaranteed to be maintained and well working for the years to come thanks to the standard library reliability and stability. The showcased examples are took from the “Modern Python Standard Library Cookbook” book that I authored.
 You already said everything, but let me have a quick introduction of what I'm doing in my life right now. I'm the maintainer of the 2.0.0.2 web framework, which is one of the top ten web frameworks in Python currently, and maintain of the bigger project for caching and session, which is widely used by many web frameworks, contributed to Ming, Tosca widgets, Webop, Kajiki, as you can see, all web-related projects. So most of my time is spent in the web world with Python. And from their work point of view, I'm one of the founders of a company in Italy, technical advisor of three startups in Italy, and one of the engineers behind the Crunch.io project, which is a great project. If you don't know it, let's have a look. And the reason why I decided to speak about this topic is because I recently published the book, which is named Modern Python Standard Library Cookbook. As you can guess, it talks about the Python Standard Library. Why I decided to write such a book when Python is full of great documentation, great books, and things like that? The reason is that most of the cookbooks that are available for Python are actually about the language, the core features of the language. Some of them showcase some features that are available to the standard library, but most of the focus is about the language itself. And we have some great sources for documentation about the standard library, like the documentation itself, the Python module of the WIC project, and things like that. But they try to focus on how you can use those models, how they work. They act more like a reference when you already know that they exist. They are not a very convenient way to discover new models or corner cases or ways you can use those models. And the Python Standard Library, it's really huge. I still discover new features, new models, and functions every day, and I've been using it for like 15 years or something like that. And this is actually a very interesting topic because recently there was a proposal to reduce the amount of models included in the standard library because it's so big that the burden over the maintainer is not manageable anymore. Some models are unmaintained for years because no one has knowledge about them. There are not enough people willing to maintain the standard library to maintain it at its current site. So sadly in the next years it's going to shrink, but still it has some very cool hidden gems that I want to share with you. The first one that I want to show you is how to report crashes from your production applications or like any kind of application action. This is something that I consider very important for any kind of application. You want to know that there is an issue because you get notified by your monitoring system, not because your user come and complain to you. So you want to be aware of any kind of issue before it can impact any user or before it impacts them enough that they start complaining. And being reported of crashes, it's one of the best way that you cannot read a bug in your code because as much as you could test your application, as much as you could have a quality assurance process, the users will always discover bugs because the complexity of the word out there is much bigger than anything we can replicate in a constrained environment like our testing systems and things like that. So this is an example of what I want to achieve, which is every time the application crashes, it sends me an email with the trace back and the error. And this can be achieved actually in a very simple manner through the logging model in Python. I guess that most of you have used the logging module at least once in your life, but I think that not many people know that the logging model is actually very flexible. It can be configured in many ways. The logging model is structured in a way that you have what's called end loss, which are in charge of doing something when you submit a message to the logging system. And one of the things that they can do is actually send for what that message to you through an SMTP server. So you can get your log by email whenever the logging system outputs a new log entry. That's of course not very convenient for logging itself. You don't want to reach thousands of emails every time you write something on the logging. But if you use properly, it can be a very good way to provide hints about some specific messages. And in this case, what I'm going to do is decorate a function, usually the main of your software or the main of your WISC application in case of web applications. We've decorated that every time there is an exception, it calls the exception logging helper on the logger that we just configured. If you notice in the previous page, the crash logger is configured to send every entry by email. And here we tell the logger to a record a new exception. The convenience is that the exception helper actually does not only record the message, which is going to be used as the subject of the email, but it also records the traceback and line where it crashed and things like that. So if this is used properly, you are going to receive my mail every single ever that your application faces so that you know before your users start to complain. And this requires like two lines of code. You just decorate the entry point of your application or the most important functions and you get notified. It works explicitly well in the context of web development because you have a single entry point in the whole application that it's called by the WISC server every time it has to serve a request. So every time the request crashes, you get notified for that specific request. Another cool feature that's available in the Python Slotna library very few people know about is that you have a way to implement literal objects. If you have a word with other dynamic languages, like probably JavaScript because it's the most widespread one, you probably got used to having literal objects and be able to just throw around objects are located at any point in your code with any kind of properties and not having to declare classes or proper structures and things like that. That's not the best way to organize your code but it can be very convenient when experimenting or when writing tests that have to simulate the behavior of other objects and you don't want to end up using real logs or things like that. When hacking around in general, it can be convenient to be able to declare objects that don't require proper class hierarchy to be created. And usually in Python, you frequently end up using dictionaries for this purpose because you can put anything you want in the dictionary. But if you have to code called third parties code, it's going probably to accept some kind of dictionary, some kind of object and not a plain dictionary as the argument. So the problem with dictionaries is that they do not support the dot notation for the access to their content. And that's the reason why in the standard library, we have something like the namespaces where you can actually set any property you like. They act like a dictionary, nothing different. But the major difference from dictionaries is that you can assess all the properties that are inside the namespace with the dot and notation. So in practice, you can create namespace everywhere and pass them around. And as we are talking about a fully dynamic language, that will be accepted by all the function that you need to call as far as they have the properties that they expect. So you reach nearly the same level of literal objects that you can achieve in other languages like JavaScript and so on. And another very cool feature I want to talk to you about is that the fact that Python provides the spools temporary files. This is a kind of temporary file that not frequently I see used in code, but it can be very convenient for some reasons. I think that all of you, at least once in their life, they need to store some data in memory in the form of a file or read it or something like that. And frequently we end up using the bytes.io as the way to store this data, to keep this data around. The problem with bytes.io is that it grows as far as your memory allows it. So in some context where you have constant resources or where you have multiple processes running for the same resources, this can be a problem because, like, let's say that you are storing in a bytes.io a file that was uploaded by a user to your web application. If the user uploads a 20 gigabytes file and it's able to actually send it to you, you're going to consume 20 gigabytes of memory. And that's going to be a problem if your system doesn't have 20 gigabytes of memory or if your system has other processes that compete for the same memory. And the solution to this problem is usually to rely on disk files, like temporary files. Most web frameworks end up storing when you submit a file, they actually store it as a temporary file on disk somewhere, and they return you an access to that temporary file. And this is cool because it solves the memory consumption problem, the disk is far bigger than the memory you have available, so it shouldn't be a major problem, but has the problem that it has a major performance impact. The disk is far slower than your memory. And in some cases, you can be also trotted by the maximum number of IE operation every second you can do and things like that, like especially if you are on a shelf file system like elastic file system or things like that, they have a maximum number of IE operations that you can do across the world cluster. So if you have many nodes that are writing and reading on the same file system, you're probably going to read the IE limit before you read the bandwidth limit. The solution to this problem is actually available in the standard library and prevents you from facing these kind of problems, that this is actually a real logs from an application that has been continuously killed, a web application, you see Apache is usually the process that got picked by the womb killer, just because the user was uploading very big files in the intent to bring down the system on purpose. And it was such a thing doing that. But if you use the spool temporary file, you're going to get the best of the both worlds. What's going to happen is that as far as the file is smaller than the specified max site, Python is going to work on it in memory. So it's going to practice to use something like bytes.io. Everything happens in memory, it's very fast, you can work it on nearly real time and things like that. But if your files grows far too far from the site, it gets swapped to the disk. So you don't have to care about your users' exhausting or your memory or things like that. And this is probably the best solution to that kind of problem because for realistic sites, for those that will be 90% of your request, you are going to process them quickly in memory and for big requests that might be malicious or might be an exception, you're going just to be a bit slower because you'll flood them to the disk but you're not going to crash anymore. Another interesting problem that is frequently in some kind of application is proper output alignment and display. If you ever wrote a terminal application, you probably face the case where it takes you a few hours to provide the output that you want to provide, a proof of concept of your application, and you spend the rest of the day trying to format it in a way that works in a reasonable way on all sites and kinds of terminals. However, your users might have decided to resize their window and things like that. That's a very hard problem that not frequently many software out there that has been around for years are not very good at solving. And to show you this case, I picked a very common example which is a progress bar. Progress bars are very widespread. They are very recognized and known way to show to your users the progress of some kind of operation. But they are also very good examples for this case because if you don't format properly a progress bar, your user is not going to understand anything. It would be just a huge mess of things on its screen and we'll lose any ability to provide the information that you want. For example, this is the progress bar from a real software existing out there. And you can see that at a certain point, it just gets a huge mess of truncated data and one point it goes on a new line. It's really hard to understand what's going on. Is it progressing at all? At which progress am I right now and things like that? So this is why you want to make sure that your software is properly able to adapt to the screen size of your users. And the standard library actually has a way to do that. And I use that utility to implement the progress bar that adapts properly to the size of the screen. And here you can see the example. It's very simple to use. You just decorate the function that has to report the progress and yield any progress advancement from that function. So that function can compute whatever it has to compute, write the result whenever it has to write it. Meanwhile, it can report progress by yielding values back to the decorator. And the output, the result is, as you can see, nicely formatted progress bar. The implementation is pretty straightforward. It's just a function that loops and continuously consumes data from your decorated function. Your decorated function there is the, it's called to retrieve the generator. You see gen equal funk. And then it just goes on calling forever next over your generator. So the implementation is not the interesting part here. The interesting part here is that in the SHUTL method, in this huge module, sorry, you have a way to grab the, where is it? I can't find it anymore. Here, sorry, at the top. You have a way to grab the current terminal site. So you are able to adapt the output of your function to the current sites of the terminal window. And this will take care for you of most of the complexity because it's not something very simple. It depends on the terminal configuration, kind of system you are on, or Windows is different than on Unix systems and things like that. So it's not a very straightforward information to achieve, but the standard library takes care of making sure you get back something meaningful for you. And even better, if I move this information within the Y loop, it will also adapt if the user recites it on real time the Windows. So I don't have to care about it. Let's see the next feature available in the standard library. How to survive an atomic fallout. Not really. It's how to survive atomic rides. So in many web applications, there is a need to replace the content of, say, file of some data that you are storing on the disk, suppose like an uploaded image or something like that. Only if you successfully wrote it for real, if you completed writing it. If your process gets killed in the middle of the ride, if your process crashes in the middle of the ride or things like that, we should not have corrupted the file we were replacing. This is actually a very common problem for nearly all applications that have to store data. Think of your database system. Would you be happy if you were inserting data and if it crashes in the middle of insertion, you corrupted the whole content of the database? That's probably not something that's going to make you very happy. But most of the application I saw around, from this bug, from this issue, if you interrupt the ride, they will have corrupted the data. Because the way the system writes the data is by writing in chunks of bytes. So if you interrupt in the middle of two chunks, you only wrote the first part of the data and probably you end up with a file that has half of the previous content and half of the new content and makes no sense at all. Or it might have only half of the new content, so it's still truncated invalid data. And we can implement, using the standard library, a utility that makes you safe from this kind of issue. And it will also allow us to retain the same exact behavior. We are used to working with the plain open function. We are just going to use safe open instead of open, and then we can write and read from that file without caring about the fact that it will guarantee for us the atomic right to the file. So if we use the safe open in case our codes crash in the middle of writing, it will roll back to the previous state of the file. And the implementation is very straightforward. We are going again to rely on a very convenient model of the standard library, which is the temporary file module. The temporary file module is a kind of temporary file, which is the name of the temporary file. It means that you don't only get back the handle that gives you access to that temporary file, but gives you back an actual file name on disk. So something on which we can call more functions based on the file name itself. And why is that important? Because by virtue of the fact that we are within the context manager, when you open a file, we actually don't open the file, but we open a temporary file. So we are going to write to a new file and not to the one you were targeting to. So in this example, you see that I opened TMP my file. And what I'm going to do is that instead of opening TMP my file, I'm actually going to open a temporary file somewhere on the disk. Then my code works on that temporary file. And only if it's a seed, sorry, only if it's a seed, the temporary file is closed and then the file is renamed. So it's moved to the place that was previously used by the file we wanted to open. And this works because as far as you are on the same file system, so you're not moving across to different disks or remote files, things like that, as far as you are on the same file system, the rename operation will be atomic. There is no way to interrupt half way every name. It's all I've named it or not. So at the end, I wrote the whole content on my file or not because I was able to end the whole function and rename my temporary file to the target file. And so I replaced the target file with the data that I wrote on the temporary file. Or I failed doing that, and so I didn't rename anything. My temporary file is left there. And my target file is still there as it was before. It doesn't even know that something was written somewhere. And if I get an exception, I just throw away the temporary file. And nothing was ever written. My target file is still in the same exact state it was before. And we can see how this works with this simple example. You see that in the first case, I obviously just open the file and write the content. And if I read it back, I will see hello world. Because I wrote everything and close my context manager. While in the second example, I open my file, I write some content, and I throw an exception which will cause my code to exit from the context manager. Now if I print back the content of my file, what do you expect to see? It's important to notice that in this example, I used the standard open. So I didn't use my safe open. And for this reason, what I'm going to see is only the first line of the content. My previously written hello world is thrown away and gets replaced with my replace the hello world. But I never add the second part of the text written on this, which is what you expect. It's straightforward to understand its content. The problem is that I thrown away the previous content of the file. It's lost forever. But I didn't finish writing the new content that I wanted to write. And instead, if we use the safe open for the same example, if I read back the content of the file after the crash of my code base, I won't replace the hello world, but I will actually read hello world. Nothing was ever written to my file by virtue of how the safe open context manager works. So I didn't corrupt my previous data in any way. I didn't write anything, and everything is as it was before. It's like having a transaction system for files. If you fail, you can roll back the content of the file to the previous state and be happy. One more feature that's available in the standard library and very few people know about is the multiprocessing manager. Some people probably used it in the past, too, and then they're relying on it to share data across multiple processes. It's very common. It's the reason why it was born. It's a way to share data across processes. You can store any value inside the manager, and that value will be available to all the processors that share the same manager. So you can write multiprocessing software without having to manually share the data across the processes. Any data that you store in the manager will be available, readable from all the processors that are children of the process that fork the manager, and they can replace the data and things like that. It's like having a database where you can store the data you want to share across all your systems. The interesting feature is that very few people know how the manager actually works. The way it works is that it actually forks a sub-process of your process, and this sub-process is a fully functional memory database system. The list ends for a request through TCP. The point is that from any process on any machine, you would be able to connect to that process to the manager and store data there. As far as you know which part and address is listening, you can write and read data to that manager. So what we actually have is a fully functional database system without having to start or manage any database system. For very simple projects, this can become a convenient way to store the data and permit access across different processes from different machines. It's easy to see that if you pair the manager with the shelf module, you actually implement the fully functional database system because you can shelf on disk all the data that it's in the manager, and you can restore it from disk the next time the manager starts. So let's see how it works. In this case, I'm going for convenience to just rely on the fact that I forked the manager so that I don't have to show you all the machinery involved into connecting to a remote manager because the example is already pretty long like this, and it didn't fit in a single slide. So let's suppose we have a first process that writes the set 42 as a value in the manager, and the second process that sets a date as the manager, and the last process that sets a date time as the value in the manager. Those three variables, first, second, and last, will be available to a fourth process that is able to read their content and print them. As far as this process knows about the manager, so as far as they were fourth, all from the same parent, they can read and write to the same manager, and the data is available to all the processes that are sharing the same manager. The only thing you need to make sure is that you don't fork the manager in the middle of your code because the way it works is as I told you, it makes a fork of your project. So you don't want your code dynamically forking processes, copying the whole memory of your process including all the data that you did storing that process because you probably know that forking relies on the copy and write property, but you probably don't remember that Python has built-in reference counting. So anytime you assess an object, you are actually going to break the copy and write because you have to increment the reference counting in the object. So forking and copy and write in Python are not very efficient as you would expect. And here there is the example that I told you where you can actually assess the namespace from any machine on any system as far as they are connected to a network. You can see that I can create a manager and tell the manager that it's going to listen to the part 50,000. I specify it just because that way I know which part is listening to otherwise it's something dynamic that I will never know. And then I tell to the manager to serve connections forever. So I just start the process that stays there, blocks, and listens for requests and goes on and on serving any request that he receives. And from a second process, I make another manager that instead of listening for requests, connects to the other manager. So I can tell to the second manager to connect to the other manager. And then the rest in part is that if I set a value in the first manager, like in this case I set five in value, the other process is perfectly able to print that value. Even though that value was stored on a different machine, doesn't even have to be on the same machine because we are relying on a network connection. You just need to pay attention to the fact that the models, if you start complex objects like classes or things like that, those models need to be available on both systems because otherwise you will face peaking issues, of course. But that's the only real thing you need to care about. As far as you have the same environment on both machines, you are able to send values back and forth across the whole network without having to care too much. One more really convenient feature that I find, I think that many of you have faced at least once in your life is that if you have to write an HTML output, maybe a web page, maybe send an email, you know that you need to escape anything that you place in that email and that the user provided to you because otherwise if the user provided malicious content like JavaScript or similar, you are going to send to the browser of your users that JavaScript is and it will be executed and it can be a very powerful vector of attacks. This is still a very common issue in web applications, like 90% of the security reports that you can find for web sites out there are usually through this vector, which means that this is something we developers are not very good at handling. And the most common way to handle this problem is by doing manual escapes on every single page where you inject the value in the output. And that's not something that works because it gets boring and tedious and humans are not very good at doing boring things. They start to skip them saying, oh, no, here we will never happen anything and things like that or they forget and so on. So the best approach to this problem is actually having escaping by default. Have the software escape everything unless you explicitly don't want to escape it. So you don't have to remember to escape things and in worst case, you wish or something that is broken to the user but it's not malicious in any way. And the way we can achieve this is through the standard library formatter. If you know the way you have the format strings in Python as being based on the string formatter, actually it's not really implemented on top of the string formatter but they provide the same exact feature. But the string formatter is something that we can customize. So it provides a string formatting feature through a class that we can customize. And this example I made in HTML formatter that allows me to format HTML and why is that important? Because every time I replace a value in my target string, it actually gets escaped for me. So if you see in the output, the strong name was escaped so I didn't put HTML in the result. I probably escaped that. But the title where I explicitly stated that it's markup so I want to have it as markup was not escaped. Was formatted as ease. There are very cool libraries out there that take off these. The most famous one I think it's markup safe from the flask guys. But it's something that you can easily achieve without the need of any external dependency or anywhere framework at all. It's available on the standard library itself just by subclassing the string formatter. And the way the string formatter works is that every time it has to replace a value, every time it has to format a value, it's going to call the get field method. It's going to tell the get field method. I need the value of this variable. Like in this case, we have the name and title. So every time the format has to resolve name and every time it has to resolve title, it's going to call the get field method. And what we can do is that after we actually retrieved that value from the class, from the parent class, we can check if that value is a markup value and the protocol on which the markup class is based is that it has an underscore, underscore HTML method. So if our class, if our value is a markup based class, respects the markup protocol, we are going to put it as ease or more than as ease formatted as a HTML. So call the protocol. While instead if our value is not markup, we are going to escape it. If it's a string, let's escape it. That way every time we format the value, it gets escaped automatically and we don't have to remember to escape it. And here you can see a very simple implementation of the markup protocol. It just relies on having a HTML method that returns the HTML representation of that object, which in case of a string, it's the string itself. So it's very simple. It's just a way to tag a string as something that has to be formatted as ease instead of being escaped. So you can see that in five lines of code, you actually end up having the same exact feature that you will have by installing the external dependency. And it's a feature that can save your life in many contexts. I think that most of you already know this comic stripe, but this is very fun. One last thing I want to show you, actually two last things I want to show you, but this is one of my favorites. As I told you, I'm involved in web development and I'm maintaining web framework, so it's very fun for me to talk about how to write a web framework. And it's something that we can do in five minutes through the standard library because if you look very well into the standard library, you will see that you have all the pieces that you need to write a fully functional web application that take care of the most complex part of handling web requests for you. So this is the web framework that I wrote, only relying on the standard library, and it might look like something that you already use in your life. It's very similar. We just declare a whiskey application and then attach all the functions that we want to routes that get served for us. And the routes can be even complex, like having regular special arguments and things like that. So anytime I assess the route, I will see a lower than anytime I assess link, you click link, try this other link, and then it gets me to an end point that accepts some arguments and I can print back the arguments and things like that. So it's particularly fun for a web framework for most basic needs. And at the end, I just have my web application, so it will list on HTTP for me. The two route concepts that I use as a convenience, you don't really need to do that, but it can be convenient to represent the incoming data and the outgoing data to response and request classes. That's what you're probably used to in other web frameworks. And the response class only has to take care of remembering what's the status that you want to send back and what's the others that you want to send back. And then provide a simple method to send back that response. Why the request is going to keep in memory all the information that got sent to us by the browser and allow us to read what was the requested path, what was the requested arguments and things like that. The web framework itself, it's just this code, nothing more, nothing less. So it's very simple. The route decorator, which is the one we used here to register the various end points, just saves the end points you wanted to register into a list of available end points. So it keeps somewhere recorded that for this URL, we want to call this method, nothing else. Of course, as the endpoint can be a regular expression, we compile this regular expression. The seven method, it's even simpler because it relies on something that it's really made in the standard library, the WISG reference server. So we create a web server, a WISG server, that we list them on part 8,000. And every single request that gets received on that part is forwarded to self, so to yourself, to your web application. And it's forwarded by calling the provided callable object, so in this case, by calling our dunder call method. So every time we receive a request, we get the dunder call method call. And what we do is that we create the request representation, we check if any of the registered routes matches with the request path that we got, and then we call it. So we just call the register endpoint, we get back the response that they at point provided us, and we send back the response to the browser. That's all. So it's very straightforward. If there is any registered callback for the endpoint, call the callback, get the result from the callback, and send back the result to the browser. That's all you need to implement a fully functional web framework, I would say. What's true that I lied, you will notice that probably if you start doing these in two weeks, you're still writing a web framework. And in three months, it will be two mini lines of code and things like that. And in three years, you will be the maintainer of one more web framework in Python. So don't do that. Use Django, Flask or whatever you want. But it can be convenient if you only want to expose two free endpoints in a web application that maybe has to run in constrained environment where you don't have enough memory space or a properly functional package manager to install dependencies or things like that. Or you just don't want to bother maintaining dependencies and things like that. Five lines of code and you are happy with your own web support. The last recipe I want to show you is based on code tracing. This is not something that you are going to use in your code itself, but it's something that can be convenient to understand other people's code. So whenever you use a new library or whenever you have to approach a new code base, it can be very hard to understand what's going on. You know nothing about the library of that code base. So it takes time before you start understanding how it works at the general level, a vision of how the library works. And in my experience, the best way to start understanding that, start having that vision, it's by following what goes on when you run the library. So look at which lines of code get executed. Look at which arguments get passed around. Also the execution of the library or of the application you are trying to understand. The problem is that when you try to do this with the bugger, they focus on the specific line you are executing. And after a while, you lose the global vision of what's going on. After the term time, you end up deep into the stack of function codes. You don't even remember anymore where you came from. You have all the information you care about, about the single current line of code. You have the context of the code surrounding the line of code where you are, but you probably forgot where you came from. So it's not very good to have a global vision of what's going on into the application as a wall. And the very good way to have that global vision is to rely on tracing of the wall code. So this is a very simple example that I did. And I asked the tracer to trace the execution of function. And what's function? Function is a very simple function. And just, like, does the sum of two numbers. And as you can see, I get back the printed code and I get a little plus near to all the lines that were executed. So you can see that in this execution, I didn't enter this if and so I didn't print these message. I just got a 1, b2, and returned a plus b. And so I understood what's going on. Why didn't I print that message? Because it never passed the if and things like that. Of course, in this very simple example, it's obvious to understand, but it's already a good way to understand what your codebate contains. And it can surprise you, like, these food that contains human flesh. I'm not sure I'm going to try it. How is that all implemented? It's based on the trace model. So inside Python itself, inside the Stutter library itself, you have the trace model which allows you to trace the execution of codebase. And what we do is just every time the tracer provides us information, we record that information somewhere, and then to the print trace execution, we print the codebase with the information of which lines got executed. So it's very straightforward to understand you just record which line were traced and then print those lines back. So you can see all modules that got executed in which order, which lines were executed, and try to understand which is the full flow of a function code that you did. That was the last recipe that I wanted to share with you. If you want to see more recipes, of course, go and read the book. And thank you for your attention.
 You already said everything, but let me have a quick introduction of what I'm doing in  my life right now.  I'm the maintainer of the 2.0.0.2 web framework, which is one of the top ten web frameworks  in Python currently, and maintain of the bigger project for caching and session, which is widely  used by many web frameworks, contributed to Ming, Tosca widgets, Webop, Kajiki, as you  can see, all web-related projects.  So most of my time is spent in the web world with Python.  And from their work point of view, I'm one of the founders of a company in Italy, technical  advisor of three startups in Italy, and one of the engineers behind the Crunch.io project,  which is a great project.  If you don't know it, let's have a look.  And the reason why I decided to speak about this topic is because I recently published  the book, which is named Modern Python Standard Library Cookbook.  As you can guess, it talks about the Python Standard Library.  Why I decided to write such a book when Python is full of great documentation, great books,  and things like that?  The reason is that most of the cookbooks that are available for Python are actually about  the language, the core features of the language.  Some of them showcase some features that are available to the standard library, but most  of the focus is about the language itself.  And we have some great sources for documentation about the standard library, like the documentation  itself, the Python module of the WIC project, and things like that.  But they try to focus on how you can use those models, how they work.  They act more like a reference when you already know that they exist.  They are not a very convenient way to discover new models or corner cases or ways you can  use those models.  And the Python Standard Library, it's really huge.  I still discover new features, new models, and functions every day, and I've been using  it for like 15 years or something like that.  And this is actually a very interesting topic because recently there was a proposal to reduce  the amount of models included in the standard library because it's so big that the burden  over the maintainer is not manageable anymore.  Some models are unmaintained for years because no one has knowledge about them.  There are not enough people willing to maintain the standard library to maintain it at its  current site.  So sadly in the next years it's going to shrink, but still it has some very cool hidden gems  that I want to share with you.  The first one that I want to show you is how to report crashes from your production applications  or like any kind of application action.  This is something that I consider very important for any kind of application.  You want to know that there is an issue because you get notified by your monitoring system,  not because your user come and complain to you.  So you want to be aware of any kind of issue before it can impact any user or before it  impacts them enough that they start complaining.  And being reported of crashes, it's one of the best way that you cannot read a bug in  your code because as much as you could test your application, as much as you could have  a quality assurance process, the users will always discover bugs because the complexity  of the word out there is much bigger than anything we can replicate in a constrained  environment like our testing systems and things like that.  So this is an example of what I want to achieve, which is every time the application crashes,  it sends me an email with the trace back and the error.  And this can be achieved actually in a very simple manner through the logging model in  Python.  I guess that most of you have used the logging module at least once in your life, but I think  that not many people know that the logging model is actually very flexible.  It can be configured in many ways.  The logging model is structured in a way that you have what's called end loss, which are  in charge of doing something when you submit a message to the logging system.  And one of the things that they can do is actually send for what that message to you  through an SMTP server.  So you can get your log by email whenever the logging system outputs a new log entry.  That's of course not very convenient for logging itself.  You don't want to reach thousands of emails every time you write something on the logging.  But if you use properly, it can be a very good way to provide hints about some specific  messages.  And in this case, what I'm going to do is decorate a function, usually the main of your  software or the main of your WISC application in case of web applications.  We've decorated that every time there is an exception, it calls the exception logging  helper on the logger that we just configured.  If you notice in the previous page, the crash logger is configured to send every entry  by email.  And here we tell the logger to a record a new exception.  The convenience is that the exception helper actually does not only record the message,  which is going to be used as the subject of the email, but it also records the traceback  and line where it crashed and things like that.  So if this is used properly, you are going to receive my mail every single ever that  your application faces so that you know before your users start to complain.  And this requires like two lines of code.  You just decorate the entry point of your application or the most important functions  and you get notified.  It works explicitly well in the context of web development because you have a single  entry point in the whole application that it's called by the WISC server every time  it has to serve a request.  So every time the request crashes, you get notified for that specific request.  Another cool feature that's available in the Python Slotna library very few people know  about is that you have a way to implement literal objects.  If you have a word with other dynamic languages, like probably JavaScript because it's the  most widespread one, you probably got used to having literal objects and be able to just  throw around objects are located at any point in your code with any kind of properties and  not having to declare classes or proper structures and things like that.  That's not the best way to organize your code but it can be very convenient when experimenting  or when writing tests that have to simulate the behavior of other objects and you don't  want to end up using real logs or things like that.  When hacking around in general, it can be convenient to be able to declare objects that  don't require proper class hierarchy to be created.  And usually in Python, you frequently end up using dictionaries for this purpose because  you can put anything you want in the dictionary.  But if you have to code called third parties code, it's going probably to accept some kind  of dictionary, some kind of object and not a plain dictionary as the argument.  So the problem with dictionaries is that they do not support the dot notation for the access  to their content.  And that's the reason why in the standard library, we have something like the namespaces  where you can actually set any property you like.  They act like a dictionary, nothing different.  But the major difference from dictionaries is that you can assess all the properties  that are inside the namespace with the dot and notation.  So in practice, you can create namespace everywhere and pass them around.  And as we are talking about a fully dynamic language, that will be accepted by all the  function that you need to call as far as they have the properties that they expect.  So you reach nearly the same level of literal objects that you can achieve in other languages  like JavaScript and so on.  And another very cool feature I want to talk to you about is that the fact that Python provides  the spools temporary files.  This is a kind of temporary file that not frequently I see used in code, but it can  be very convenient for some reasons.  I think that all of you, at least once in their life, they need to store some data in  memory in the form of a file or read it or something like that.  And frequently we end up using the bytes.io as the way to store this data, to keep this  data around.  The problem with bytes.io is that it grows as far as your memory allows it.  So in some context where you have constant resources or where you have multiple processes  running for the same resources, this can be a problem because, like, let's say that you  are storing in a bytes.io a file that was uploaded by a user to your web application.  If the user uploads a 20 gigabytes file and it's able to actually send it to you, you're  going to consume 20 gigabytes of memory.  And that's going to be a problem if your system doesn't have 20 gigabytes of memory or if  your system has other processes that compete for the same memory.  And the solution to this problem is usually to rely on disk files, like temporary files.  Most web frameworks end up storing when you submit a file, they actually store it as a  temporary file on disk somewhere, and they return you an access to that temporary file.  And this is cool because it solves the memory consumption problem, the disk is far bigger  than the memory you have available, so it shouldn't be a major problem, but has the problem  that it has a major performance impact.  The disk is far slower than your memory.  And in some cases, you can be also trotted by the maximum number of IE operation every  second you can do and things like that, like especially if you are on a shelf file system  like elastic file system or things like that, they have a maximum number of IE operations  that you can do across the world cluster.  So if you have many nodes that are writing and reading on the same file system, you're  probably going to read the IE limit before you read the bandwidth limit.  The solution to this problem is actually available in the standard library and prevents you from  facing these kind of problems, that this is actually a real logs from an application that  has been continuously killed, a web application, you see Apache is usually the process that  got picked by the womb killer, just because the user was uploading very big files in the  intent to bring down the system on purpose.  And it was such a thing doing that.  But if you use the spool temporary file, you're going to get the best of the both worlds.  What's going to happen is that as far as the file is smaller than the specified max site,  Python is going to work on it in memory.  So it's going to practice to use something like bytes.io.  Everything happens in memory, it's very fast, you can work it on nearly real time and things  like that.  But if your files grows far too far from the site, it gets swapped to the disk.  So you don't have to care about your users' exhausting or your memory or things like that.  And this is probably the best solution to that kind of problem because for realistic  sites, for those that will be 90% of your request, you are going to process them quickly  in memory and for big requests that might be malicious or might be an exception, you're  going just to be a bit slower because you'll flood them to the disk but you're not going  to crash anymore.  Another interesting problem that is frequently in some kind of application is proper output  alignment and display.  If you ever wrote a terminal application, you probably face the case where it takes you  a few hours to provide the output that you want to provide, a proof of concept of your  application, and you spend the rest of the day trying to format it in a way that works  in a reasonable way on all sites and kinds of terminals.  However, your users might have decided to resize their window and things like that.  That's a very hard problem that not frequently many software out there that has been around  for years are not very good at solving.  And to show you this case, I picked a very common example which is a progress bar.  Progress bars are very widespread.  They are very recognized and known way to show to your users the progress of some kind  of operation.  But they are also very good examples for this case because if you don't format properly  a progress bar, your user is not going to understand anything.  It would be just a huge mess of things on its screen and we'll lose any ability to provide  the information that you want.  For example, this is the progress bar from a real software existing out there.  And you can see that at a certain point, it just gets a huge mess of truncated data and  one point it goes on a new line.  It's really hard to understand what's going on.  Is it progressing at all?  At which progress am I right now and things like that?  So this is why you want to make sure that your software is properly able to adapt to  the screen size of your users.  And the standard library actually has a way to do that.  And I use that utility to implement the progress bar that adapts properly to the size of the  screen.  And here you can see the example.  It's very simple to use.  You just decorate the function that has to report the progress and yield any progress  advancement from that function.  So that function can compute whatever it has to compute, write the result whenever it has  to write it.  Meanwhile, it can report progress by yielding values back to the decorator.  And the output, the result is, as you can see, nicely formatted progress bar.  The implementation is pretty straightforward.  It's just a function that loops and continuously consumes data from your decorated function.  Your decorated function there is the, it's called to retrieve the generator.  You see gen equal funk.  And then it just goes on calling forever next over your generator.  So the implementation is not the interesting part here.  The interesting part here is that in the SHUTL method, in this huge module, sorry, you have  a way to grab the, where is it?  I can't find it anymore.  Here, sorry, at the top.  You have a way to grab the current terminal site.  So you are able to adapt the output of your function to the current sites of the terminal  window.  And this will take care for you of most of the complexity because it's not something  very simple.  It depends on the terminal configuration, kind of system you are on, or Windows is different  than on Unix systems and things like that.  So it's not a very straightforward information to achieve, but the standard library takes  care of making sure you get back something meaningful for you.  And even better, if I move this information within the Y loop, it will also adapt if the  user recites it on real time the Windows.  So I don't have to care about it.  Let's see the next feature available in the standard library.  How to survive an atomic fallout.  Not really.  It's how to survive atomic rides.  So in many web applications, there is a need to replace the content of, say, file of some  data that you are storing on the disk, suppose like an uploaded image or something like that.  Only if you successfully wrote it for real, if you completed writing it.  If your process gets killed in the middle of the ride, if your process crashes in the  middle of the ride or things like that, we should not have corrupted the file we were  replacing.  This is actually a very common problem for nearly all applications that have to store  data.  Think of your database system.  Would you be happy if you were inserting data and if it crashes in the middle of insertion,  you corrupted the whole content of the database?  That's probably not something that's going to make you very happy.  But most of the application I saw around, from this bug, from this issue, if you interrupt  the ride, they will have corrupted the data.  Because the way the system writes the data is by writing in chunks of bytes.  So if you interrupt in the middle of two chunks, you only wrote the first part of the data  and probably you end up with a file that has half of the previous content and half of the  new content and makes no sense at all.  Or it might have only half of the new content, so it's still truncated invalid data.  And we can implement, using the standard library, a utility that makes you safe from this kind  of issue.  And it will also allow us to retain the same exact behavior.  We are used to working with the plain open function.  We are just going to use safe open instead of open, and then we can write and read from  that file without caring about the fact that it will guarantee for us the atomic right  to the file.  So if we use the safe open in case our codes crash in the middle of writing, it will roll  back to the previous state of the file.  And the implementation is very straightforward.  We are going again to rely on a very convenient model of the standard library, which is the  temporary file module.  The temporary file module is a kind of temporary file, which is the name of the temporary file.  It means that you don't only get back the handle that gives you access to that temporary  file, but gives you back an actual file name on disk.  So something on which we can call more functions based on the file name itself.  And why is that important?  Because by virtue of the fact that we are within the context manager, when you open  a file, we actually don't open the file, but we open a temporary file.  So we are going to write to a new file and not to the one you were targeting to.  So in this example, you see that I opened TMP my file.  And what I'm going to do is that instead of opening TMP my file, I'm actually going to  open a temporary file somewhere on the disk.  Then my code works on that temporary file.  And only if it's a seed, sorry, only if it's a seed, the temporary file is closed and then  the file is renamed.  So it's moved to the place that was previously used by the file we wanted to open.  And this works because as far as you are on the same file system, so you're not moving  across to different disks or remote files, things like that, as far as you are on the  same file system, the rename operation will be atomic.  There is no way to interrupt half way every name.  It's all I've named it or not.  So at the end, I wrote the whole content on my file or not because I was able to end  the whole function and rename my temporary file to the target file.  And so I replaced the target file with the data that I wrote on the temporary file.  Or I failed doing that, and so I didn't rename anything.  My temporary file is left there.  And my target file is still there as it was before.  It doesn't even know that something was written somewhere.  And if I get an exception, I just throw away the temporary file.  And nothing was ever written.  My target file is still in the same exact state it was before.  And we can see how this works with this simple example.  You see that in the first case, I obviously just open the file and write the content.  And if I read it back, I will see hello world.  Because I wrote everything and close my context manager.  While in the second example, I open my file, I write some content, and I throw an exception  which will cause my code to exit from the context manager.  Now if I print back the content of my file, what do you expect to see?  It's important to notice that in this example, I used the standard open.  So I didn't use my safe open.  And for this reason, what I'm going to see is only the first line of the content.  My previously written hello world is thrown away and gets replaced with my replace the  hello world.  But I never add the second part of the text written on this, which is what you expect.  It's straightforward to understand its content.  The problem is that I thrown away the previous content of the file.  It's lost forever.  But I didn't finish writing the new content that I wanted to write.  And instead, if we use the safe open for the same example, if I read back the content of  the file after the crash of my code base, I won't replace the hello world, but I will  actually read hello world.  Nothing was ever written to my file by virtue of how the safe open context manager works.  So I didn't corrupt my previous data in any way.  I didn't write anything, and everything is as it was before.  It's like having a transaction system for files.  If you fail, you can roll back the content of the file to the previous state and be happy.  One more feature that's available in the standard library and very few people know about is  the multiprocessing manager.  Some people probably used it in the past, too, and then they're relying on it to share  data across multiple processes.  It's very common.  It's the reason why it was born.  It's a way to share data across processes.  You can store any value inside the manager, and that value will be available to all the  processors that share the same manager.  So you can write multiprocessing software without having to manually share the data across the  processes.  Any data that you store in the manager will be available, readable from all the processors  that are children of the process that fork the manager, and they can replace the data  and things like that.  It's like having a database where you can store the data you want to share across all  your systems.  The interesting feature is that very few people know how the manager actually works.  The way it works is that it actually forks a sub-process of your process, and this sub-process  is a fully functional memory database system.  The list ends for a request through TCP.  The point is that from any process on any machine, you would be able to connect to that  process to the manager and store data there.  As far as you know which part and address is listening, you can write and read data  to that manager.  So what we actually have is a fully functional database system without having to start or  manage any database system.  For very simple projects, this can become a convenient way to store the data and permit  access across different processes from different machines.  It's easy to see that if you pair the manager with the shelf module, you actually implement  the fully functional database system because you can shelf on disk all the data that it's  in the manager, and you can restore it from disk the next time the manager starts.  So let's see how it works.  In this case, I'm going for convenience to just rely on the fact that I forked the manager  so that I don't have to show you all the machinery involved into connecting to a remote manager  because the example is already pretty long like this, and it didn't fit in a single slide.  So let's suppose we have a first process that writes the set 42 as a value in the manager,  and the second process that sets a date as the manager, and the last process that sets  a date time as the value in the manager.  Those three variables, first, second, and last, will be available to a fourth process  that is able to read their content and print them.  As far as this process knows about the manager, so as far as they were fourth, all from the  same parent, they can read and write to the same manager, and the data is available to  all the processes that are sharing the same manager.  The only thing you need to make sure is that you don't fork the manager in the middle of  your code because the way it works is as I told you, it makes a fork of your project.  So you don't want your code dynamically forking processes, copying the whole memory of your  process including all the data that you did storing that process because you probably  know that forking relies on the copy and write property, but you probably don't remember  that Python has built-in reference counting.  So anytime you assess an object, you are actually going to break the copy and write  because you have to increment the reference counting in the object.  So forking and copy and write in Python are not very efficient as you would expect.  And here there is the example that I told you where you can actually assess the namespace  from any machine on any system as far as they are connected to a network.  You can see that I can create a manager and tell the manager that it's going to listen  to the part 50,000.  I specify it just because that way I know which part is listening to otherwise it's  something dynamic that I will never know.  And then I tell to the manager to serve connections forever.  So I just start the process that stays there, blocks, and listens for requests and goes  on and on serving any request that he receives.  And from a second process, I make another manager that instead of listening for requests,  connects to the other manager.  So I can tell to the second manager to connect to the other manager.  And then the rest in part is that if I set a value in the first manager, like in this  case I set five in value, the other process is perfectly able to print that value.  Even though that value was stored on a different machine, doesn't even have to be on the same  machine because we are relying on a network connection.  You just need to pay attention to the fact that the models, if you start complex objects  like classes or things like that, those models need to be available on both systems because  otherwise you will face peaking issues, of course.  But that's the only real thing you need to care about.  As far as you have the same environment on both machines, you are able to send values  back and forth across the whole network without having to care too much.  One more really convenient feature that I find, I think that many of you have faced at least  once in your life is that if you have to write an HTML output, maybe a web page, maybe send  an email, you know that you need to escape anything that you place in that email and  that the user provided to you because otherwise if the user provided malicious content like  JavaScript or similar, you are going to send to the browser of your users that JavaScript  is and it will be executed and it can be a very powerful vector of attacks.  This is still a very common issue in web applications, like 90% of the security reports  that you can find for web sites out there are usually through this vector, which means  that this is something we developers are not very good at handling.  And the most common way to handle this problem is by doing manual escapes on every single  page where you inject the value in the output.  And that's not something that works because it gets boring and tedious and humans are  not very good at doing boring things.  They start to skip them saying, oh, no, here we will never happen anything and things like  that or they forget and so on.  So the best approach to this problem is actually having escaping by default.  Have the software escape everything unless you explicitly don't want to escape it.  So you don't have to remember to escape things and in worst case, you wish or something that  is broken to the user but it's not malicious in any way.  And the way we can achieve this is through the standard library formatter.  If you know the way you have the format strings in Python as being based on the string formatter,  actually it's not really implemented on top of the string formatter but they provide the  same exact feature.  But the string formatter is something that we can customize.  So it provides a string formatting feature through a class that we can customize.  And this example I made in HTML formatter that allows me to format HTML and why is that  important?  Because every time I replace a value in my target string, it actually gets escaped for  me.  So if you see in the output, the strong name was escaped so I didn't put HTML in the result.  I probably escaped that.  But the title where I explicitly stated that it's markup so I want to have it as markup  was not escaped.  Was formatted as ease.  There are very cool libraries out there that take off these.  The most famous one I think it's markup safe from the flask guys.  But it's something that you can easily achieve without the need of any external dependency  or anywhere framework at all.  It's available on the standard library itself just by subclassing the string formatter.  And the way the string formatter works is that every time it has to replace a value,  every time it has to format a value, it's going to call the get field method.  It's going to tell the get field method.  I need the value of this variable.  Like in this case, we have the name and title.  So every time the format has to resolve name and every time it has to resolve title, it's  going to call the get field method.  And what we can do is that after we actually retrieved that value from the class, from  the parent class, we can check if that value is a markup value and the protocol on which  the markup class is based is that it has an underscore, underscore HTML method.  So if our class, if our value is a markup based class, respects the markup protocol,  we are going to put it as ease or more than as ease formatted as a HTML.  So call the protocol.  While instead if our value is not markup, we are going to escape it.  If it's a string, let's escape it.  That way every time we format the value, it gets escaped automatically and we don't have  to remember to escape it.  And here you can see a very simple implementation of the markup protocol.  It just relies on having a HTML method that returns the HTML representation of that object,  which in case of a string, it's the string itself.  So it's very simple.  It's just a way to tag a string as something that has to be formatted as ease instead of  being escaped.  So you can see that in five lines of code, you actually end up having the same exact  feature that you will have by installing the external dependency.  And it's a feature that can save your life in many contexts.  I think that most of you already know this comic stripe, but this is very fun.  One last thing I want to show you, actually two last things I want to show you, but this  is one of my favorites.  As I told you, I'm involved in web development and I'm maintaining web framework, so it's  very fun for me to talk about how to write a web framework.  And it's something that we can do in five minutes through the standard library because  if you look very well into the standard library, you will see that you have all the pieces that  you need to write a fully functional web application that take care of the most complex part of  handling web requests for you.  So this is the web framework that I wrote, only relying on the standard library, and  it might look like something that you already use in your life.  It's very similar.  We just declare a whiskey application and then attach all the functions that we want  to routes that get served for us.  And the routes can be even complex, like having regular special arguments and things  like that.  So anytime I assess the route, I will see a lower than anytime I assess link, you click  link, try this other link, and then it gets me to an end point that accepts some arguments  and I can print back the arguments and things like that.  So it's particularly fun for a web framework for most basic needs.  And at the end, I just have my web application, so it will list on HTTP for me.  The two route concepts that I use as a convenience, you don't really need to do that, but it can  be convenient to represent the incoming data and the outgoing data to response and request  classes.  That's what you're probably used to in other web frameworks.  And the response class only has to take care of remembering what's the status that you  want to send back and what's the others that you want to send back.  And then provide a simple method to send back that response.  Why the request is going to keep in memory all the information that got sent to us by  the browser and allow us to read what was the requested path, what was the requested arguments  and things like that.  The web framework itself, it's just this code, nothing more, nothing less.  So it's very simple.  The route decorator, which is the one we used here to register the various end points, just  saves the end points you wanted to register into a list of available end points.  So it keeps somewhere recorded that for this URL, we want to call this method, nothing  else.  Of course, as the endpoint can be a regular expression, we compile this regular expression.  The seven method, it's even simpler because it relies on something that it's really made  in the standard library, the WISG reference server.  So we create a web server, a WISG server, that we list them on part 8,000.  And every single request that gets received on that part is forwarded to self, so to yourself,  to your web application.  And it's forwarded by calling the provided callable object, so in this case, by calling  our dunder call method.  So every time we receive a request, we get the dunder call method call.  And what we do is that we create the request representation, we check if any of the registered  routes matches with the request path that we got, and then we call it.  So we just call the register endpoint, we get back the response that they at point provided  us, and we send back the response to the browser.  That's all.  So it's very straightforward.  If there is any registered callback for the endpoint, call the callback, get the result  from the callback, and send back the result to the browser.  That's all you need to implement a fully functional web framework, I would say.  What's true that I lied, you will notice that probably if you start doing these in two weeks,  you're still writing a web framework.  And in three months, it will be two mini lines of code and things like that.  And in three years, you will be the maintainer of one more web framework in Python.  So don't do that.  Use Django, Flask or whatever you want.  But it can be convenient if you only want to expose two free endpoints in a web application  that maybe has to run in constrained environment where you don't have enough memory space or  a properly functional package manager to install dependencies or things like that.  Or you just don't want to bother maintaining dependencies and things like that.  Five lines of code and you are happy with your own web support.  The last recipe I want to show you is based on code tracing.  This is not something that you are going to use in your code itself, but it's something  that can be convenient to understand other people's code.  So whenever you use a new library or whenever you have to approach a new code base, it can  be very hard to understand what's going on.  You know nothing about the library of that code base.  So it takes time before you start understanding how it works at the general level, a vision  of how the library works.  And in my experience, the best way to start understanding that, start having that vision,  it's by following what goes on when you run the library.  So look at which lines of code get executed.  Look at which arguments get passed around.  Also the execution of the library or of the application you are trying to understand.  The problem is that when you try to do this with the bugger, they focus on the specific  line you are executing.  And after a while, you lose the global vision of what's going on.  After the term time, you end up deep into the stack of function codes.  You don't even remember anymore where you came from.  You have all the information you care about, about the single current line of code.  You have the context of the code surrounding the line of code where you are, but you probably  forgot where you came from.  So it's not very good to have a global vision of what's going on into the application as  a wall.  And the very good way to have that global vision is to rely on tracing of the wall code.  So this is a very simple example that I did.  And I asked the tracer to trace the execution of function.  And what's function?  Function is a very simple function.  And just, like, does the sum of two numbers.  And as you can see, I get back the printed code and I get a little plus near to all the  lines that were executed.  So you can see that in this execution, I didn't enter this if and so I didn't print  these message.  I just got a 1, b2, and returned a plus b.  And so I understood what's going on.  Why didn't I print that message?  Because it never passed the if and things like that.  Of course, in this very simple example, it's obvious to understand, but it's already a  good way to understand what your codebate contains.  And it can surprise you, like, these food that contains human flesh.  I'm not sure I'm going to try it.  How is that all implemented?  It's based on the trace model.  So inside Python itself, inside the Stutter library itself, you have the trace model which  allows you to trace the execution of codebase.  And what we do is just every time the tracer provides us information, we record that information  somewhere, and then to the print trace execution, we print the codebase with the information  of which lines got executed.  So it's very straightforward to understand you just record which line were traced and  then print those lines back.  So you can see all modules that got executed in which order, which lines were executed,  and try to understand which is the full flow of a function code that you did.  That was the last recipe that I wanted to share with you.  If you want to see more recipes, of course, go and read the book.  And thank you for your attention.
Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_0_491.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_492_4199.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_4200_6047.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_6048_6467.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_6468_7631.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_7632_8195.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_8196_8351.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_8352_8879.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_8880_8963.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_8964_9791.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_9792_12359.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_12360_12899.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_12900_16895.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_16896_17027.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_17028_17627.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_17628_18083.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_18084_18599.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_18600_19259.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_19260_20135.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_20136_21311.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_21312_22211.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_22212_22295.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_22296_23255.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_23256_25535.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_25536_25643.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_25644_25883.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_25884_26519.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_26520_27251.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_27252_29807.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_29808_30347.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_30348_30575.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_30576_32903.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_32904_34091.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_34092_34703.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_34704_36143.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_36144_36299.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_36300_40199.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_40200_42659.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_42660_43151.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_43152_43403.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_43404_45395.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_45396_45587.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_45588_48095.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_48096_49727.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_49728_50327.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_50328_50663.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_50664_50747.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_50748_52691.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_52692_52823.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_52824_52895.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_52896_53099.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_53100_53255.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_53256_53483.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_53484_54359.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_54360_54431.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_54432_55631.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_55632_56747.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_56748_57059.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_57060_57143.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_57144_59387.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_59388_63395.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_63396_64679.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_64680_65015.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_65016_65315.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_65316_66143.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_66144_66239.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_66240_66383.png Alessandro_Molina_-_Python_Standard_Library__The_Hidden_Gems_fhn0p8uS788_66384_66600.png