How to deal with poor code analysis support - Vladimir Losev

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] today i'll be talking about the approach we have taken to deal with sport code analysis support in our generator meta classes and uh code generation heavy project uh so we have open sourced uh a library that's called local kit uh it's a python library used to interact with our platform and at some point it uh we started using some advanced features of python some dynamic features like again generators meta classes and code generation and we encountered some problems with ide support so i will try and explain the problem one a simple example so say we want to create a module that's called sleepy and it's uh and we want it to contain a single function sleep for so the difference uh in sleep for uh the difference between sleep four and start and the standard function sleep is that sleep work accepts two arguments the amounts and time units so we can say sleep for please one minute half a day or two weeks um and as we can see if we uh are trying to use the function in some other module we can see that our ide by the way for the purpose of this talk i'll be demonstrating everything on my pycharm ide but effectively this should be the same in all other ids so in my pie chart id we can see the signature we can see the um name suggestion for our arguments and if we uh pass an unexpected argument or a wrong argument that does not fit our signature we see that id id highlights the wrong argument but let's add a simple decorator so let's add a decorator that locks function call typically you would write the decorator like this so this is a simple decorator that logs some string when the function is called and locks some other string band uh the function is uh finished so we configure the logging we run the codes we see that everything works but let's have a look at the ide support after we have applied such decorator to our function we can no longer see syntax file signature we can no longer access the argument suggestion and we can pass an unexpected argument and this will not be provided by our ide all gone but signature is actually still there so if we import an inspect module and we print the signature of the sleep for function we can see that the signature is still there so why the ide does not show us any suggestions what went wrong well uh the thing is that ide uses static code analysis for its humans it is afraid to run our code because um it may have side effects or because it may be badly written and raise an exception or it might be a code in the middle in in the process of um right being being written so it might be might not be syntactically correct and id still has useful outputs so the ide tries to get as much to know as much as it can about your code without without actually running it and this is a tremendously hard job some ideas might do better some might do more poorly but what can we do with this particularly in this case we can well generally it's a good idea to provide your ide and the static analysis tools with as much information as you can and in this particular case you could add an additional type hints that would uh tell our ide that the decorator pre returns the same type as it accepts and at least for my uh pycharm version this does not uh fix the issue with signature but we can see that if we try to uh write an argument we have the suggestion and somehow the signature is in a pop-up window right above um again somehow it does not highlight the unexpected arguments but technically we can see that my it might be some minor bug still all the information is picked by the ide but not all cases are as easy as this one as we can see even a simple decorator can confuse the ide but there are harder ones so let us say that at some point our users that used our sleeping module uh returned to us with the feedback that they no longer want to use the time unit minutes or time the time units because they do not want to write an extra import and time unit dot minutes or time unit dot hour is a long string to write so they want to write units as strings so what we can do we can write an additional decorator that would take any function and try to cast all the past arguments to enamels if need be so we would add an authentim uh decorator and the autumn decorator would look something like this let's quickly go through the definition so first of all we take the original signature of our function then we create a wrapper function that accepts arcs quarks and in order to map the original arguments past arguments to the original ones we bind the arguments to the signature then we go through all the arguments and if we see that in the original signature the argument was annotated as in and the past argument is not an imam we try to convert the past value to the enum type and then we have quite a lot of code that preserves the original signature so we take the original annotations and if we see an announcement where we replace this with a union of a union and a literal that contains all the possible enum values finally we assign the signature to the wrapper function and return the wrapper function so as we can see the ide does not pick the updated signature it highlights our units passed as a string but both functions work and if we output the signature that we obtain in runtime with an inspect module we can see that the signature is correct and is present uh so uh as we can intuitively understand um the static tool static code analysis tools would not be able to recreate the signature just by looking the code without without running it because uh if i go back a few slides we can see that this is pretty much an arbitrary code and being able to understand the output signature of this function would effectively equivalent to actually running the code and ide and static to code analysis tools do not want to do that they are afraid to do that so how can we fix the situation we can fix this with stop files stop files is a language feature that was introduced in uh 484 and long story short it's um a substitute for your original files so for code analysis tools you can say that uh for this tools please instead of the original file take all the information necessary for static analysis from a substitute file that is called a stop file so um what should you put in a stop file you should put the all the public uh member definitions that were in original files annotations dot strings uh final function signatures without decorators uh constants where possible if it's too complicated or impossible you can use three dots instead and all necessary inputs for the code to be a valid python what can be omitted private members decorators and function implementations so for our uh you need that pi we would create a stop file that would look something like this so we had a sleep for function and we replaced this with the definition of sleep for function with the final signature we omit all the implementation and we keep all the uh classes and inputs that are required in order for this to be a valid python so we imported an enum in order to be able to define a time unit as an intimum and uh literal and unions from typing module in order for our annotation to be valid uh the convention says that stop files are the files that have the extension pyi and they should be called the same as the original original files uh in path 561 there was an addition that requires us to add a marker pi that typed file to the module if it supports uh typing from typekins so we do this and this fixes the uh fixes the issue so we can see the signature again we can see the auto suggestion and we can see that id highlights unexpected arguments uh and also it does not highlight uh our minute string so everything is okay but now we runs but now we have a problem and the problem is that we actually uh have to maintain all the pyi files manually and this is quite a burden so what so the approach we took at loca is automatic stop generation uh the idea is uh default is the following um so static analysis tools are afraid to run the code but if we know that our code is pretty much runnable it does not have side effects during import time has does not raise exceptions we can do the running part ourselves so we can import the module we can get the runtime module object and from this runtime object we can recreate this generate create the stop files so this would look something like this this is a simple example that does not produce uh working output just in order to understand how this approach works in practice um so we would write um a file that would go like this we would define a function uh that can create a module object from a given path um in the function that generates stop content we would go through the module object and we would traverse all the attributes and pick only for this example functions that are defined in this module we would write a definition that would have a name signature and an empty body and we would run this on module so if we run this we get something like this if we refactor the code we it would look something like this so the problems that occur during the stop generation process are that um we have to import everything that is referenced by uh the functions or the classes or whatever we are generating in this case we have to import unions we would have to create the time unit we would also have to manage the default values representation uh this is manageable and but um takes a bit more lines of code and we uh implemented this implemented our internal tool for exactly this purpose and if we run our internal internal tool uh on this code it produces the following results it generates all the necessary stop files it generates uh the docs string four time unit because actually when you create uh an alarm class it automatically contains uh an enumeration.string so th this is taken from everything is taken from runtime and generator automatically for the autonom and log function call we also produced valid stop files but they are not pretty very interesting so we are intending on open sourcing this tool uh later this this month um this point if you are interesting interested in having a look at the original project where we used this approach to generate stop files you can follow the link and thank you for your intention [Music] [Music] you
Info
Channel: SF Python
Views: 116
Rating: 5 out of 5
Keywords: SF Python, Vladimir Losev
Id: ejCoT4WWdKQ
Channel Id: undefined
Length: 16min 25sec (985 seconds)
Published: Tue Sep 14 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.