 We're going to start with our next talk. We have Gintari Urbán talking about a strongly typed Python. So let's give her applause please. Okay, hi, hi everyone. I hope you can hear me all right. So for the start I just wanted to introduce myself quickly. So I'm Gintari as mentioned. I'm coding in Python for about six, seven years. I started from OpenStack and infrastructure engineering. Now I'm more in a fintech. So I work for a company called Thought Machine. I'm a software backend engineer there. This is why this is important I will mention in a couple of slides later. Okay, so in this talk, spoiler alert. Quick one. Today this morning in a keynote we heard about MyPyC, which is a strong typed Python compiler and some ideas in this area. So this talk, I'm not going to talk about any alternative version of Python compiler, but this is more like using vanilla Python that we all are comfortable with and trying to do it yourself, strong, sorry, type checking and validations in runtime. And I will give you some ideas why we found this is important and useful for us. So let's start from answering this question. Okay, so to give you a background why it was important for us in Thought Machine. So we're creating a core banking platform and to configure this core banking platform we use a concept called smart contracts. This is not a blockchain smart contract, but this is a blob of Python code that we trigger at events at specific times. Some events are very hard to test manually. So, for example, an event can happen in 10 years or once a year. So you would need a very robust, very good testing framework for that. So like simulation that runs. Okay. And another thing someone told me, oh, you're so brave, you guys writing smart contracts in Python. That's a great thing to do. And the reasons why it's brave and the reasons why it could be error prone is actually type checking and type validations. And we try to solve this problem, not problem, but challenge by introducing a runtime type checking and validations for the smart contract code. And we have very sophisticated framework for testing this that allows you to use the same library objects, classes, functions in your unit test code, do whatever you want with them, but that will be protected and ensure that all the monkey patching will also be type validated. So let's answer again the question why. For the wider audience, not only for our use case, but basically we learned and like I personally learned, I think I can sum it to the three things. So why does a need for strong typing sometimes? So checking the types or sorry, failing, it's not always an option when it happens. Sometimes you want to prevent. Very popular kind of use case. I think it's a for middleware type of locations. What I mean by middleware, it's like application or library between a main system, core system, and a user input. So I think it's the middlewares applications are like a almost the most important purpose is to get the input manipulated somehow and pass it forward. So majority of bugs could be prevented with the type checking. And the last thing that I already a bit mentioned, it's in unit test, dependencies are mocked. So basically, if we don't have a type enforcing, so you know, like by mocking dependencies, that we can have false positive assertions. And basically, this is worth to put in a meme. Having a unit test passing, you know, doesn't ensure that your code wouldn't fail in production in 10 years time or something. Okay, so quick disclaimer before we show the code. All the code I will show today was inspired by my work in foot machine. But it was all it is all my home project, which I kind of created in a bit different way, a new way to what I did in foot machine. But basically, yeah, I needed to put this here. Okay. By the way, all examples, I will, you know, show the GitHub link later. All examples are in GitHub. So don't worry, you don't need to, you know, remember or note any code. So okay, let's start from examples. Probably you all know, you know, what is typing, but about that in next slide. Before we go into that, let's look at example function that could be used in the smart contract or, you know, in similar applications. So we have a submit payment function. It takes amount account ID reference. Yeah. And it prints out the types and returns. Before returning, by the way, it actually submits the same payment in some kind of a sync queue or something. We don't have any feedback from it, for example. We just, you know, we can't do anything about it after we submit. Okay. So let's run this once with float and once with a string value of a amount. As we all know, what will happen is we'll just get both run successful and, you know, Biden is forgiving here, which is great for some use cases, but not for every. So as I mentioned, we want spam specific types because we later propagate those types into our async queue hidden away system to submit the same payment and, you know, that runs probably on, I don't know, go or something that doesn't allow invalid types. Okay. Let's do the same with annotating all the types at the top. This is now possible using Python typing module, which is now part of core. And all those links up there, you know, quotes, steps that were recently introduced. And we also, to quickly mention, we also have in this typing module, very useful method called get type hints. And that's an example at the very end of this. So I will show you what that type hints function provides us. I will show you in the output in a second. So let's call the same submit payment within valid type here after declaring the types. All right. So again, nothing did, nothing bad did happen. Although we have this additional information that's useful, we have all those mentioned type hints called type annotations. So we see that amount should be float account ID should be string. While we see that after run, our account ID is integer, but nothing failed. Okay. So we had the type hints. We said that we wanted those specific types, but no type errors were raised. It's fine until it's not. So basically, just to give you a again, like a reason for doing us static or runtime validations here. Okay. So basically, static runtime validations would be like a linter. And there are quite many popular ones. I would say most popular is my pie. And today we heard about my pie C, which is, I guess, runtime allotted. So what these type checkers could do is they could look at your code, like linter validate at all, and raise any type errors. Also, we see the plugins in PyCharm and so on. So there are plenty of these available in open source community. Also, there's this enforce module. It does the runtime validations. And there's already plenty useful stuff out there that's ready to be used. Okay. So one against another. As I mentioned, if you want to use the same objects in the tests, I want to ensure that they're not, you know, monkey patch with wrong attributes, wrong type attributes. So it's very important then to use the runtime validation against the static. So we chose and I found it very useful to use the runtime validation. And I will show you today how to do one yourself without using any dependencies in your code, like enforce library or any other. And the reason why we created ourselves and like why I did work on this myself is that I found that sometimes using dependencies are, you know, not enough and could be, you know, creating some incompatible versions later, could be incompatible new versions later. And also they were missing some functionality that I added here in my examples. And I will show you. Okay. So let's look at the code finally. Yeah, okay. So as I mentioned, it's all in a good hub. So don't worry. Okay. So we have the same function, right? And now the same function will be enforcing times in runtime. So what we do, we declare the function, we have the same type annotations and at the top we add the decorator and we run it with incorrect types. Yay, finally. Basically, this is what we wanted for our use case, you know, if the function is run in like tests or in the simulation or any other process, you will write away before calling the core system and failing then you will write away stop and say, okay, you can't go further. The types are not correct. Okay. Another example how this could be used, the same validator. By the way, I don't know if you noted, but the return type is also declared with this arrow saying none. So basically we assume that our function returns none. But here let's add the one instead of none. Okay. We have the return type. The return value was not correct type. How I actually did it? So the only thing that was required here, actually two. So one was type annotations. We needed to declare for all arguments of a function and the return time. And this decorator. So how this decorator is implemented. So we just intercept the function call. And before returning a value, we validate all its arguments. And after returning a value, let's validate the return. That's very good. So how it actually is implemented. So if you remember at the very beginning, I showed you the very useful typing function called get type hints. And in the common string at the top, we see what it outputs just to remind there. So we have the all attributes and also namespace called return. That's just saying what is the return type. So all the attributes and their types as a Python object. And we basically get the type information with this helper function. And we iterate over these and assert that in arcs and keywords, we have all those there and all the correct types. And the return is just almost the same. Valid return is almost the same. Just there, we only care about one thing, the return. Okay. The last thing to show here is how to actually validate type. And I will not show the code for underscore validate type, which is actually although I have it in Appendix, if you want to see a lot of lines of code, we'll go into there. But the reason why is just it's big. And I think in the future, I already raised this question, we should introduce and add it to the Python core typing module. Because this underscore validate type is general enough for the typing module, I think. What it does, it actually takes this expected type in a Python format. Basically, it could be nested. It could be huge. It could be, let's say, dictionary of where the key is, I don't know, like a sequence. And then in the sequence, we have a number nested structure. It could be huge. And we would give it the expected type and the value, which we could recursively iterate and check whether it's a correct type. So I think in the future, we might want to have this somewhere implemented once and available and not to do the boilerplate code for any sort of use cases. Okay. So sorry for the bunch of code, but hopefully you didn't lose the attention. Let's look at more code examples. Okay. So now on, I would like to show you guys a class. Let's see a payment class and how to do the attribute validations. So here we'll have two attributes that we want to eventually validate. Class level attributes, account ID and amount. And this is how we would declare the types at the top of these functions, sorry, of these attributes. And then look, note that we inherit from a meta class called strong typing. And I will show you how it's implemented in the next slide. Okay. So what we're doing here at the end on the runtime, we like to instantiate the method with, sorry, class of correct types. But later on, let's change the type. Let's change the attribute to be the incorrect type. Okay. We have the failure, which is very useful. And that actually is like an example of what could be done in a test as you test along. You might want to change the values and you obviously want to ensure that always the object is a correct type. Okay. So we have this error, which we wanted, how it's actually implemented. The meta class, I heard in a couple of talks that this is a, you know, no-no zone. But let's see. Maybe it's not so dangerous. So the meta class allows you to, before initializing a class, it allows you to add some attributes onto the class. And we'll use this information to add each attribute onto the class, each attribute set attribute and get attribute methods. And in the set attribute, we add intercept one tiny bit, which is validate type. So at any point anyone wants to set attribute on that class, we will set it before, so validate it, validating before setting every time. Okay. Let's see how else we can use this meta class by adding a bit more code to it to do the method arguments validation. So we have here the get status method, which should get the timestamp as an argument of a daytime. Let's try running once with correct daytime, with correct value, and another time with incorrect type. And what we get here, okay, this is what we wanted. So we get the error saying that it was incorrect type. How we achieved it? Again, by adding a bit more code to the same strong typing meta class. So what I did here, if you remember this decorator that we had for the submit payment function, so we just looked through all the class attributes, figured out which of these are methods, they have call attribute, and decorated those. So this decorator, I wouldn't show it because it's like almost the same as the validate function decorator. It's just for methods with self. Okay. So probably you go all like that, but I promise you a price. Is it visible? Okay. So here's the price, sorry, as in price as a present. So we added a bunch of code and have the meta classes. Maybe we can get out of this some extra thing that will come for free. So yes, indeed we can. Let's use the type annotations that we already set as something that could generate automatically our doc strings for us with all that information that's already there in the type annotations. So here we have the payment and all the methods and calling the doc strings on those. They don't show any information about the type annotations. And the example at the bottom is what I actually wanted. So we already have all those annotations. Maybe we can automatically get the doc string like that out of them. So how could it be achieved? We need to attach somewhere the description of each attribute or argument. So Python is so forgiving. It allows us to do something like this. We have this new class that we declared which stores two things. It stores both type and a description. So this is literally the same code just everywhere. Instead of assigning a attribute or argument to type, we assign it to two things like type and description. Okay, the result. This is what we wanted. So now the doc strings are actually not detached from the real code that validates stuff. So it actually is accurate and all the time consistent with your implementation of a function. And, you know, you can't really use it if you set wrong types. So therefore, it should be consistent all the way through the lifecycle of your code. So how it's actually achieved? It's achieved by, as I said, Python is forgiving. Let's just have this class called type and we set the description and type there. And before exiting the method decorator, we'll add the function docs. And in the add a function docs, we just inflate the doc string with type annotations, the type annotations in string format. And this is how it's done. So basically, loop through the type annotations, extract all the information from there, which is already there, and just put it in a string. And one last example, promise, is that if anyone's interested and found it useful, you can also do it yourself, data structures. And we found the use for it, like type tuple, type list type dictionary. This is type tuple example. You would just literally use the same class, sorry, meta class, and have a strong type data structures. And the prints over there at the end, they go like this. So it only allows to instantiate this tuple with correct data types. And if we try to use the incorrect ones, we get the type error. Yay. So thank you for listening. Let's look at the summing up and basically conclusions. So I think typing module in Python is a really good addition to allow, if someone wants, have a strong type version of your code. And we just saw that it's not so difficult to do it yourself a validation runtime. There are plenty of other libraries. My code will be there out. And there's growing fuzz in Python community to maybe introduce like we heard today, like a compiler or some additions in that field. So validate type, I think, as mentioned before, I think it should be a part of the typing module because it's just the implementation is just boilerplate that could be done, like that has to be done in any project. And the last thing to say that, yeah, in some projects is the runtime validations is very good thing to have to ensure that the code is less error problem. Thank you so much. Fortunately, I don't think we have much time, except you have a really quick, quick, quick question because we need to get ready for the next one. Really quick, please. I actually had two questions, but I'll ask one. Okay. So since this type annotation is littered across the code, and the examples you have shown were for the primitive data lives, but if we want... Sorry? The examples that you used were for primitive data types, but if you want to use for complex data types, do you think it will create problem while unit testing in which you want to use things like mock where you replace the object with a mocked object? Yeah. So you said primitive types, right? Or no? I'm saying the examples for a primitive type, but if you want to use Yeah. So, but this is the main reason why I suggest that this underscore validate type function should be part of typing module and, you know, should be getting the... Basically, by getting any type declaration could be complex, rich, nested, big. It would implement all this validation recursively. And, you know, I could show my implementation of it. And I think, you know, it captures most of the cases, but of course, you know, like this actual validation of a type, especially for new declared types or more sophisticated cases, you know, it's a whole new problem. Yeah. Okay. Thank you very much. I think I'm sure she's going to be around today. So if you want to ask your second question, for example, or any more questions, she will be here. So thank you very much for your talk.