 So, for those who were at the Pycon Singapore, I talked about one of my projects they're called Warped Drive. This time I'm going to talk about another. I've got the wrong slider. That's bad, isn't it? This is the one I did at Pycon Singapore. I need to bring the right ones. This will teach me. Here, that's better. Now, I've probably lost this connection. So, yes, as you were saying, I'm the author of Model Whiskey, so I've been doing Python since I don't know when to come out. I dragged down version 0.9 off the... It wasn't internet back then, it was like usernet news groups. So, I've been playing around with Python quite a lot of time. And I have a history of being really silly and putting out open source projects. And I don't know if anyone else has their own little open source projects. They can be a lot of work, and I'm silly and keep doing it. So, I have three main open source projects I've known for. ModWiskey, Wrapped, and... What was the other one? There's another one which died actually, a long time ago. There's a C++, we won't go into that. So now, I'm going to talk about Wrapped today. Let's see if it gets going. Good, that works. Okay, so Wrapped. So, I'll start rather than go and talk to me about monkey patching. But I'm not going to go there quite first, I'm going to talk about decorators first. Now, we all know what decorators are in Python. Yes, they're useful. Yes, they're easy to implement. Who's implemented a decorator themselves? Everyone's used them. Okay, so you've used them. So for those who have implemented them, are they actually easy to implement? You think so? You sure? Okay, so here's a typical decorator. One area of a decorator is you're putting a wrapper around another function. And there is a syntax in Python where you use this app symbol to make use of your decorator. And there's a bit of magic going on here to essentially put this function around this other one so that when this one is called, it'll actually call this one, do this work, and return that result. So you essentially intersect that call and put this wrapper around it. And that is the basic pattern for implementing a decorator that you've probably used. The problem is, if you implement a decorator like that as written, it will break things. It doesn't actually, it will work most of the time. Most people wouldn't even know there was a problem. But one of the things that breaks is introspection. And if you're familiar with Python, one of the great things about the language is that you can actually go in there and look at the objects in your application. So you fire up the interpreter and you can start playing with objects. And you can work out the type of the objects. You can ask their names. You can look at help strings and so on and so forth. They're looking at the name, they're looking at the help strings, looking at the arguments that a function accepts. That's what we regard as being introspection. It's pulling out that information to learn about it. Decorators, if you use that basic pattern, as people use, breaks it. As the name, done is called name, done is called doc. That is the name and the help string that you'll get. Those things are not preserved when you wrap things with a decorator. Now, you may be familiar if you've done implementation of decorators in a package called, or module in the standard library called functools. Now, it has the thing in there called wrappes. Now, it itself is a decorator. It's a bit of magic which you can supposedly use to make this decorator work properly, to fix those problems of introspection. The problem is it doesn't solve all the problems. It doesn't always work. It sort of fixes the basic things like done is called name and done is called help, doc. But there's other things that doesn't quite get right. Now, the things it doesn't fix is, there are other ask the issues with introspection which it doesn't fix. Things like, if you want to get the arguments of the function which the decorator is applied to, they don't work. You can't get them back properly. You're going to get back the arguments that the wrapper itself is applied. And there's other problems where if you try and use a wrapper using that basic pattern of a decorator, it won't work when implementing it around certain types of other decorators which you implement using a thing called descriptors. Now, descriptors is a real bit of magic in there. And some examples of something that uses a descriptor is class method in Python, which is another decorator. We use decorators. If you put one of your decorators around a class method, things start to not quite work right. So, there's a lot of complicated details and I'm not going to go into it. I've done talks about this in the past and if you really want to know about all these issues that can occur with decorators and what can go wrong and how you should do them properly, if you go to my blog, it's the best place. You look on the right-hand side, there's a quick link section and it has decorators monkey patching. There's about a dozen or so blog posts there where I've talked about and gone through the basics of decorators and how they're implemented, why they're implemented wrong, how they should be implemented and so on and so on. So, you want to know more about that than go there. So, much as you might think decorators simply, if you're going to implement, this is my advice. Don't try and do them yourself. Okay? Don't follow that pattern that I showed up there earlier. But what is the solution? The solution is a project I wrote called RAT. What it does is it embodies all that proper way of doing things. So, it deals with all those things about introspection. It deals with the things of how to create a decorator which when applied around another sort of decorator, whether it's a normal decorator or one implementer using a scripter, it handles all that magic and does everything correctly. All the introspection things are fixed. You can query your decorator function and you'll get back the correct name, the correct doc string, the correct arguments and a whole host of other things. In terms of using RAT to create your own decorator, then it's a bit simpler than we had before. Before, we were implementing the decorator by using a function closure. Essentially, one function is nested inside of another. Using this decorator from RAT to be clear, you get rid of one level there, which makes it all look a bit simpler. You're going to just declare your wrapper function like that and you'll get a few arguments coming. RAT, which is a function you decorate with, and then at the end you've got ARGS and KWIRGS. There's other things in here called instance. Now, what's interesting about instance, if I go the right way, is that when you use the original decorator pattern, one of the bits of information and knowledge that you lose that you don't know about is whether you've applied a decorator to a normal function or an instance method of a class or a class method, or even to a class, that information is very hard to get out and use that basic decorator pattern. In RAT, it allows you to get that out such that when your wrapper function is called, it will can tell you effectively why this instance argument, how your decorator was being used. So we can see whether the decorator is being applied to a class, to a functional static method, to a class method, or an instance method. Now that's very important because if you want to write a decorator which can be used in different scenarios like that and is able to dynamically adjust, you need something like that. And who uses Django? There are decorators in Django which there are two versions of them. One you can apply to a normal function and then the same type of decorator, but you have to use a different one of applying it to an instance method because they haven't got that smarts in there to allow their decorator implementation to pick up in what context it's used in. RAT handles that. That's a good thing I say you if you're able to create these things called universal decorators. Now imagine a time that you might not need this but it's a cute feature. Now, if you don't trust me and believe me and say you should use RAT and it's wonderful and all that, I had multiple people from the core developers of Python come up to me, can you please get RAT inside of the Python standard library? I mean the last one was... I forgot this first name, someone Hastings. Anyway, very, very important person to see Python world and I've told you we've got this name. Whether we'll get into the standard library I don't know. I've missed the cutoff for Python 2.6. I've got a year and a half I think for Python 2.7 maybe I'll get enthusiastic and look at it. Now, I've talked about RAT and decorators but and it's really good for that. That's actually wasn't what RAT was created for. The reason that RAT was created was for something called monkey patching. I used to work at a company called New Relic. Anyone heard of New Relic? They do application performance monitoring for web applications. They... what they do is they provide an agent library if you like or an agent package which integrates into a web application to put in instrumentation which allows you then to monitor that web application. So number of requests coming in, how long the requests take but a lot, lot deeper than that. If you are using Django for example, it will associate a particular request with the particular view handler in Django which was invoked to handle that request. So it will associate that data for that request with that view handler and we can get a breakdown of not my web apps getting all these requests but my web apps getting all these requests and I know that 50% of them went to this particular view handler and 25% to this handler. And it can dig down into extracting data out about database performance. How many calls you doing to your database SQL database? How long each of those queries took? What were the details of the queries? Now to do all that if you are going to instrument your own code you may well go off and use your own decorator. You've got the ability to modify your code put those decorators in there where you need them to extract information out and then report it into a monitoring system such as DataDoc, StatsD a couple others as well there's a lot of open source on this one. So you can do it all manually but when you talk about a product like New Relic they don't really want you to expect you to go and put all of this instrumentation in your own code yourself to do all of that. So what New Relic does is it goes in a monkey patch just to help out of the code base. It knows about Django or Pyramid or whatever all these frameworks it will detect when you have imported those modules and put Django great, you're using Django I'm going to go in and put all this monkey patching in there to instrument so I know when this view handler is called, when this template rendering is happening and it does all that dynamically without you even knowing and if you're using New Relic and you thought hey this is a lot of magic if you had no idea how about works you should be really scared so when I was at New Relic I wrote that I had a lot of information for them and yeah, it monkey patched the hell out of everything and in doing that I don't know that monkey patch coding for them but I sort of fought one holiday I was actually up in KL I've just come back from a holiday from KL I was actually in KL one holiday before a number of years ago it might have been a five or six week holiday I don't remember and I thought okay let's talk about how to do monkey patching because of New Relic and I thought it's time to sit down and do it properly now and I did it as a separate library which is what wrapped us and so that's what all came up from that work from there so why then is wrap got decorators in there but also monkey patching and that is because decorators rely on a lot of the similar principles to monkey patching so I actually did the monkey patching support and side effect of that was this great way of implementing decorator really easy as well so that's how it came about now the reason for that who has used Python 2.3 or earlier anyone use Python from that by back wow so Python 2.3 earlier did not have decorator syntax this didn't exist okay you could still do the same thing but the way you would write it in your code you just have to remember that we had that function wrapper implementation before so if you use it 2.4 plus you could just go add name of decorator and apply it to function in Python 2.3 you get your function and you're going to go function equals so we've got to actually replace this with a function wrapper passing it to function and so if you remember the notation the nested function so you've called that outer function which has passed in the function as an argument and the body of that has then returned the inner function it's a closure function closure and that's what actually gets assigned back into that so this is what generally we refer to as being monkey patching and that's how decorator spectrally are implemented under the hood the difference is decorator applied when your code is defined so if you've written your own code be it a function at a module scope what you're doing you go in there you put your code and then you put at function wrapper or if you define your class it's at function wrapper on the instance method and that decorator is applied when that Python code is being read in by the interpreter and converted from code to byte code so it is done when the code is defined the difference with monkey patching is it's performed after the fact and as a result it can't use the decorator syntax now when I mean by after the fact it's literally going to be after that whole module has been imported some time later why would you want a monkey patch you may want a monkey patch you may want a monkey patch if you need to fix bugs in code you cannot modify so imagine Django had a bug in it and they know about it they've fixed it it's not going to be available until Python 1.10 which is just going through pre release calendar but imagine you were on version 1.8 of Django and you couldn't move up for various reasons but you still need that fix now you've got the choice of fork Django make your own modified version of it and then maintain that alternatively you can use your existing Django 1.8 and use monkey patching to go and apply a fix to that code after the fact so that's one reason you might use it but another reason you might use it and probably the use case which most people would encounter it is for doing testing now who here has used the Mock package anyone heard of Mock one again same person but if you're using Python 3 I can't remember what it's called there is a version of Mock now one of the more recent Python 3 versions what Mock is is if you're writing unit tests for Python code it's a way of when you're writing those unit tests you want to isolate bits of the code you're testing so that you can test just those bits a bit at a time and when you've got a large application which may be doing things like calling out to some back end service and you want to just test the function which is doing that call and it's in the result you don't want it to be talking to that back end service because that back end service may not exist so this is a library out here called Mock and this again shows how bad my memory is I forgot the name of the guy who writes it he's a UK person he's got a big beard I haven't met him in New Zealand and he wrote this thing called Mock and it's a way of doing monkey patching so you write your unit test and you apply decorators to your unit test and with a description of what I need the monkey patch for that unit test and so when that unit test runs you've got to apply all these monkey patches to change the code so it might stub out some code so rather than actually making a call to request library and then doing a call to back end service you'll mock out parts of the request library so that the call will actually go to your Mock code so instead of calling back it it'll call you a little test function or Mock function which returns a faked up result so that's another useful and finally I mentioned the case of Neuralit before you might want to do it to go into code and add instrumentation to be able to do performance monitoring as well so monkey patching with RAPT give you an example so you remember this function we had before the wrapper previously I was having RAPT.decorator I'm dropping that decorator at the moment so imagine I've got this bit of code here in this example.py and I want to apply a wrapper around this name method in there because I need to change the implementation slightly to do something that's expired or might be mocking it out to do testing what you can do with RAPT is essentially you've got this patches modeling import RAPT define the wrapper and the class from that code folder I want to actually apply this wrapper RAPT.rap function name of class we're actually going to give it a class object the name of the method and the wrapper and RAPT is going to go in there and put a wrapper around that method and it's going to do that if you then go and create an instance of that example class now and call name on that method which then allows you to do something and in this case I'm just calling the original but I could change arguments as they go in I could get the result as it comes out and change the result or I could just not even call just stub it out with a mock value for testing and that's all it does but you'll see the separation here which I mentioned before about decorators do it with the defined monkey patches after the fact I've already imported this this module in so I'm going and doing evil things afterwards now when I showed how things were done in 2.3 you might remember I had an example here function equals wrapper function you shouldn't do that actually that itself can cause various strange corner case problems with classes class instance methods in particular so I could do that so I've got my wrap decorator example again so that's my decorator version you can do this and it'll work 99% of the time but there's some corner cases that it won't work in so that's where when you're using wrap you'll use my function trust that wrap will go in and do the things that it needs to do properly and I don't know how familiar you are with how the python object model works I can tell you of how in the python module in a python class there is a dict, underscore dict that's where all the attributes the methods from that type are in there if we do this we're getting that function out of there but this magic thing happens with python called binding usually it's used to take the normal function and associate it with an instance of a class that's where things start to fall apart if you try and do this yourself because we've got this off the class type itself, binding has occurred it's actually bound that function to a none whereas normally when you're using an instance it'll be bound to an instance anyway I'll just confuse everyone and myself if I go into that just trust me, don't do that that's why I've got the other function so direct patching of methods breaks in certain cases basically if you're going to use wrapped you'd let wrapped do it for you now you'll remember there when we had the example .py and we had my patches file and I had to actually import that example class from the example.py we can actually clean that up a bit in this case I've got my wrapper function and I've got this other decorator inside of wrapped which is patch function wrapper so in this case rather than going import from example import example from import example from example I should have used different names anyway instead of importing the module and getting the class out of it we can just say patch this function wrapper in module and the method example.name okay when I import patches.py it'll zip through this, it'll see this it'll apply that wrapper and it's all done okay we can clean that up a bit now I mentioned testing before so what about testing where we do not want permanent patches because that previous example patch function wrapper, it's a permanent once you do that it's applied forever for the life of that process so wrapped has this other one then it's a transient function wrapper it's very very similar to that patch function wrapper but what we can do in this case is when this file gets pulled in it's not actually going to do anything at this point it's actually going to create a new decorator and we're going to create use that new decorator down here so what and it's applied it to this test method here what's going to happen in this case is that when we call test method what will happen is that this is when this kicks in it will apply that wrapper to that method look up method on that class and then it will call test method actually the body of it so when it calls this method here that wrapper will be exist do whatever we need to do and when it pops out of this function it's going to remove that wrapper and the reason for this is if you've got a whole bunch of test methods and mock library mock package works the same way you can't have the patches be permanent because you may want different patches applied for different tests so you run one test with one particular monkey patches applied when that test is finished you take them all out then you run the next test with a different set of monkey patches applied and that way you keep all the things separate when you're running a different test anyway there's a way in wrapper doing that also wrap has another case of what if we need to intercept access to a single instance of an object okay so let's give an example of that imagine that we have just ignored this so imagine our test method is going storage equals instance of storage class and then it calls storage look up key so normally what we have to do is we create our instance until we go and do that now in this particular case we've created that storage instance within the scope of this method so it doesn't matter it's a local copy but you can imagine that when we monkey patch something we're actually monkey patching a method on the type of the class so every single instance we create of that class that we've monkey patched has that monkey patched code applied to it so we only want to have a monkey patch applied to one instance because we might be doing this in instrumentation in a real life application and it might be a multi threaded application and so there's always different threads running all over the place and we only want to patch one instance of a class in one thread we don't want that same monkey patch to be affecting everything else now what wrap test for that is this thing called object proxy it's the thing that actually underlies everything in wrap everything is built around this wrap object proxy all the monkey patching function wrappers are built on object proxy decorator mutation built on this object proxy what it is it's a way of just essentially giving it any python object you wrap this object proxy around it and if I now call the proxy what will actually happen is it will just forward on that call to the original method on the original storage class the original lookup method but if I go put my wrapper around it my proxy wrapper it allows me to intercept that one method call and so when I call this case storage lookup of this file it's actually going to call my method here and I can do what it's over and call the original one this is the original object I wrapped here but if I call storage.clear if I clear in here it will still call the original straight so essentially what's called transport object proxy it works not just on method calls if you access an attribute via the proxy it will give you back the one that's in the original one if you've ever used from the python standard library from weakref module there is a type in there called ref the form of object proxy if there is not transparent in the sense that when you want to access it you actually have to use ref and like a call to get back to original this one just does all transparent so there are the different ways you can use wrap to do this and that monkey patchy if you need to now very important thing you mentioned before about how decorators are applied when the code is being read in monkey patchy is done after the fact one thing you have to be very very careful of is ordering problems when you apply monkey patches and here's an example I have a function and an example and I want to monkey patch that so that gets imported by module somewhere else in the application code and it might go from example import function I laid out when I try and patch this function and I go oh great I have my wrap patch function and I'll apply a wrapper around it there's a problem anyone see what the problem is so in what you're going to apply it's still not attached in what you're going to apply it's still not attached so I'm going to apply this to here but this because it went from example import function has copied a reference of function into the global namespace of module so when I patch this it's not patching this function so that's what I mean by ordering problems if other things get in there before you do and import that module and do things like this and then your monkey patch doesn't apply to their copies of it and if you have ever used a ventlet or g-event if you they the purpose of ventlet and g-event are packages in python which not in the core but third party which rather than using multifredding to implement concurrency they use a thing called greenlets essentially it's co-operative multi-tasking it relies on something that is running to say I'm going to block here I'm going to voluntarily give up control so that something else can run to do that though so it's transparent those packages go into monkey patch the python standard library they go into monkey patch into the socket code multifredding code a whole bunch of other places the way that they work is this naive approach of you in your application there's a particular function of g-event where you have to go g-event.monkeypatch all that has to eventually get done it goes to all these all these monkey patches get applied but if the application code is already imported some of the stuff that it needs to monkey patch you'll end up with a copy and your copy won't be imported g-event and the cells have got tripped up by this because in the python standard library itself a lot of code around there which goes from time import sleep and things will get copies of sleep when you use these packages there'll be some sleep call out that doesn't work and it blocks your whole function because it hasn't got this little wrapper around it which says no I'm going to give up control so that something else can run while I sleep I don't like g-event and eventlet if you ever think you have a need for them probably you don't don't use them unless you really really understand how they work and you think you have a need for them because they don't do monkey patch important another problem I want to concur is the fact that in that previous code I've got this patches module so you might have in your application code okay I want to do all this different monkey patching but imagine if you've got different ways of running your application in some cases it may not only exercise certain functionality so you only may import certain code but if I have a whole bunch of these patches of being implied in one big patches file and it's going to import all of this code that it wants to monkey patch upfront if you ever use that code later on you've imported it for no reason all you've done is increased the amount of memory your application is using so that's another danger thing you have to be careful of so what can we do about it everyone with me what peps are so pep is what's got a python enhancement proposal if you're familiar with the internet they have rfcs request the comments pep is like a python equivalent of that it's where someone can write up a proposal about how something should be implemented and down the track if it's accepted it may be implemented into the core python library or the language and so on now there's this pep created called pep.prc.com which is post importals it never got implemented never got accepted so it doesn't exist it never got done but wrapped has implemented a part of that actually it hasn't implemented at all now maybe for my patches module was going to actually cause examples to be imported straight away using concepts from this post importals I'm going to go in here I've got my wrapper and I've got my function applied patches which is seen as actually going to apply the patch but I've put it around at the decorator which is wrapped when imported so example so all it is is a definition and what happens is that you import that and it hasn't caused example to be imported that point but if example is imported later on by something I've installed this thing called post importals so when that module is imported later it'll go great I've seen that that module has been imported now I'm going to call this function and allow you to apply that patch only at the point that the module was actually imported very very importantly it is applied before anything else gets to do anything with the module so if the first user of that module was from example import function or example plus this gets in before that happens so I can actually apply my patch before anything else very important now that is better but it still requires that patches module to be imported for anything else in your main application script so you still have to go in to modify your application and we've got it down now to a little bit of code modification but it's still going to modify your application code what would be great is if you didn't have to modify anything your application code and there's a way of doing that so we need a way to trigger monkey patches without modifying the application code and I have another package for that it's called autorept so people use autorept as well now for this to work what we need to do though is we need to separate each of your sets of monkey patches into their own separate modules now I'm going to use an example here in the python standard library this is a module called whizgy ref so whizgy is the python's standard for when facing with web applications between servers and applications and there's this simple whizgy server in there now I want to instrument that whizgy server so that when I get a htdb request for my application I want to dump out how long that web request took so I'm going to go and create this separate module now which packages up my monkey patches so I've got to set up the py file here which is what you use if you want to create your own installable python module which you want to put up on pypy and let people install this on I'm going to call my module name whizgy ref to plug in very important here I've got this thing in here called entry point this is something which is a part of this package called set up tools originally when python came around there was a thing called distutils it was the basic library package which you used when implementing these setup.pys to create installable modules someone created something a bit more complicated called set up tools and one of these things they had with this thing called entry point it's just a way of when you install a module it can register these things called entry points it just creates a file in your python installation associated with that package so here's this extra bit of information this module provides this service or this functionality or something like that and you can go and look up those entry points later and we're going to make use of that so this may look it's going to be the actual punky patch module similar to before actually I should point out something about my entry point so this is the details of my entry point what I'm saying is when whizgy ref got simple server module is imported I want you to call rack whizgy ref to plug in which is name of module apply patches and here's that apply patches is here I'm going to say patching module and a wrap function wrap with that using that function from wrap what it's going to do is it's going to take whizgy request handle which is the actual handle function inside the whizgy service implementation which handles one request and I'm going to wrap it with this function called timed function so timed function then following the wrap way of the evaporator is going to start a timer we started it call the original function and when it's done we're just going to print out a speech so we're applying a monkey patch now here's the magic with auto wrapped I'm going to go pip install all the wrapped I've gone pip install my monkey patch module and I have an app.py which is my application and that's importing that simple server from whizgy ref and giving it a whizgy application to run that's your original code I am not touching that at all we're not going to modify it all we need to do because I've installed order wrap is set this environment variable this is the name of my module which cleared the monkey patch exporting it so the application is here I don't have to run python just python nothing else python app.py and my code got patched in automatically I haven't finished it I haven't modified one line of code in the application and I wouldn't have changed all very magic and I don't actually do how that works is very evil the order wrap module has been around over a year this is the first time I've ever told anyone about it even though it's been up on actually I did do a blog post about it it's not something to say much about I'm not sure what the reaction will be with people this is a really weird concept in python packages when you install a python package into your python distribution one of the things that it can install into the python installation into the site packages directory which is where all your modules are installed along with the package you can install this file I call it .pth it's like the original purpose of it was that you can almost view it like a sim link or an alias if you like it would normally have in it a directory so what would happen is when python starts up and trying to work out your sys.path where it's going to get all your modules from it goes through the directories and looks for these .pth files it will open it up and stick that in sys.path so it was a way of having packages installed elsewhere rather than just the site packages directory and python would know where to get packages from those the main use of it is not actually to have packages installed somewhere else it was so that when you install a package you can have a version number and the directory that would be actually in a sub directory of the site packages so you might have Django-1.10 in a sub directory but there will also be a Django.pth file which says Django-1.10 so that way it knows when it goes through sys.pth it will put site packages Django 1.10 in sys.path so it knows where to find that actual version of Django that's where it came from somewhere along the line and I believe it had something to do with codecs for language locales someone had this really weird idea that hey let's allow executable code inside of that .pth file and there's this bit of magic in there python when going through looking at all those .pth files if it starts with import space it's going to go oh this is code I'm actually going to read in that line of code and execute it when python is being initialised so autorept is doing this horrible magic which puts code in one of these .pth files when python starts up that bit of code is going to is that environment variable set for autorept bootstrap if it is I'm going to import autorept I'm going to call this bootstrap function which then goes and hooks into the python import machinery for modules and that gives me on my way hooking into the import mechanism so that we have told it this is this monkey patch module over here I've been able to use those entry points to get the information about where that monkey patch function is and that all gets registered and later on when your code imports that whizgy breath simple server module my code will go oh good I'm going to monkey patch for you before anyone even gets to it it's really, really horrible nasty and the interesting thing I find about this is that it's maybe a weird concept for many I think is that it means that technically because of the way all this works I've had to package up my monkey patch as a module you can start to distribute monkey patches as packages on pypo and the use case for this for me is instrumentation for monitoring now back in New Relic when I did that that was obviously a reply to a bit of software and all of the monkey patch required for all the different frameworks that existed the database modules and all this sort of thing we at New Relic had to implement all those and they were part of the New Relic package and it's not really extensible by anyone else because it's all New Relic stuff but technically if one wanted one could go and write a replacement for New Relic if you like which has a basic bit of functionality in there for handling the reporting of metrics pipeline into some back end and through just using this ability to package up monkey patches people could come along and start package up instrumentation for all these different frameworks themselves and just put them on pipeline and if someone knew about it they could say great I'll bring in my base monitoring package and I need this bit of monkey patch Django and this bit of monkey patch and just list them in that environment they just patch and they don't modify their code at all and they can get a whole ecosystem of all these horrible monkey patches it's a scary idea but I don't know I'll get people interested in that last thing about wraps so head decorator sport had all this stuff with monkey patching it has one bonus feature if you're doing multi-frame programming I've thrown in an example of your life an example of a decorator in there actually I wanted to use it myself if you've done multi-frame programming you would know that you have to be careful about doing friend synchronization and you know you need to make sure if you've got shared data that you don't have multiple things accessing the same data at the same time and normally you would use the lock object in the threading module yourself to do that and that gets a bit complicated and things like that there's a much simpler way if one can actually incorporate that manipulation of the lock the acquire of the lock and the release of the lock around the function which is modifying the data you can make it really simple you can have that synchronized so in this particular case it means that if multiple threads call this function at the same time only one can execute the code at the same time and this one is separated so it's got its own synchronization lock on it and who has used Java anyway okay you're familiar with the synchronized what are they called decorators annotation is it you're familiar with the synchronized annotation in Java? Keyword oh yeah so Java has this idea of synchronized keyword and it's very similar to decorators in the way we use them right but it's a very very important thing when you use synchronized keyword on a method of a class in Java it's effectively locking that whole instance of that class okay or if the synchronized decorator does Java have static methods now I think if you apply this synchronized to the static function it's locking the whole class I don't know about the instance anyway if you remember back to my description of the wrap decorator before we talked about the universal decorator the fact that the decorator could tell you applying it to normal function instance method or class or class method we can make use of that inside of this synchronized decorator implementation so in this particular case we have synchronized on the function before and all it's doing is controlling access to that one function, global function people are synchronized on a method now because I know that I'm being using it on an instance method of class hey I can lock the instance of the class or if I apply it to a class method class method normally I can apply it to a class I can lock the class if I apply it to a static method static methods aren't really bound they're like a global function then I'm just locking that one function but also in Java I can't remember how to synchronize for this for works, there's some syntax for this in decorator in Java as well if you want to be able to synchronize on a block of code my synchronized decorator even though it's a decorator I've made it a bit more magic as well and if you don't know what context managers are they are the things that you use with this with syntax you might be familiar with if you've gone with open file now that gives back a file object but that with statement ensures that that is closed when that with statement exits and that's the fact because this file object is what's called a context manager so I've made my decorator even more fancy I've made it bold and purpose it's not just a decorator it's also context manager so as well as using it as decorator we can actually use it in this so the decorator it can also at the same time do this and it's smart enough that in this case it's an instance method so we're synchronizing on the instance and here obviously we've synchronized itself and so I can say or if it's a another instance method for some reason needed to synchronize on the class so similar to a class method I can actually give it the object and I'll synchronize on that instead so that's my extra bonus thing in wrapped so why might you use wrapped in for creating better decorators I don't say I've got a hundred percent right but I'm a lot, lot closer than using functools.wrappers a lot, lot closer and there's a lot of code in there there is a pure python version there's also C implementations for the performance so I'll use this implementation and make it nice and performant and it will fall back to pure python for some reason you're going to follow I've got safety mechanisms for monkey patching and you get this brilliant little synchronization decorator and that's it, that's my talk so what docs there is, wrap.read.docs.io but better still go to my blog go look on the right hand side and there's that quick link for monkey patching now decorators monkey patching over a dozen blog posts on the topic actually I think they're linked off so that's one of my little open source projects that's it so any questions? the sample code that you went through is that available on the site or is this presentation available? I'll be putting it up it'll end up on was it slideshow probably we don't even meet up but yeah I usually push stuff off I think it's up on slideshow there's two slide slides I can't remember which one I used but the blog posts that over a dozen blog posts go into a lot more detail there's got all these examples in there any more how long have you been using Python? as I said I downloaded version .9 I looked at it and went oh crap tab spaces as indenting as like you gotta be joking I sort of played around a little bit but obviously it was very early then and I think I next dealt with it when it was about version 1.2 1.2 maybe 1.3 and I started playing with it more than and I wrote all these big Python wrappers around my C++ library which I had out then and that C++ library that started in about 1990 before Python C++ standard template library existed so it had string classes it had collection classes it had an old template file it was a logging system it was an event system it was a distributed messaging system in there and I created Python wrappers for the distributed messaging system a whole way of doing distributed applications using a published private request for Python module and that was used in some telco software where I was working and a later job where I was writing software to drive card printers to print driver's licenses that software is still used it's still running even though I haven't played with that C++ library for many years any other questions? yeah, any other questions? one last slide after this for those who weren't at Python Singapore I did a talk on a thing called warp drive and that is to do with web application deployment and Docker trying to make web applications much much easier to deploy it's not just local warp drive is designed to do stuff it's very easy on your local development system but also inside of Docker but also in hosting services such as OpenShift which is where I work which I'm an advocate for but I'm now an author I've got my name on a book now this book is free if you're interested in platform as a service if you need to host a web application then you can go and download this book for free and it will tell you about how OpenShift works our latest version which is using Docker for container runtime Kubernetes for orchestration and scheduling because Docker alone it's great on your own machine but if you need to start going beyond one machine until many many machines Docker alone is not there and this company is trying to fill in all the holes to make their Docker cloud or what are they called Docker data center they are still on way behind things like Kubernetes Mesos and all these other ones but we are thinking of Kubernetes so if you're interested in web application hosting or Python web apps that book mentions Java though unfortunately only mentions Python once in the whole but you can download it for free it'll explain how you can actually download it on your own laptop and cloud it I do actually have in that VM you download there are actually some templates in there for deploying Python web apps using my warp drive software which is what my other talk was about and obviously there's a video from the Python Singapore that talk if you just can go back and look at it although I should come to Python Australia in a few weeks time and see it there because I'm going to give a talk again okay? Thank you