Monday, July 8, 2019

What is pylint and how is it useful (or useless) for your project

Wikipedia tells me : Pylint is a source-code, bug and quality checker for the Python programming language.  That seems to be way too heavy, isn't it?  Well, to put simply, I'd say pylint is a source code analysis tool for the Python programming language.  And why do we need a source code analysis tool?  In other words, do I really need to use pylint in my project?  This was my thought when I first came to know about pylint, and had to use it.  I had written my first python code in a new project.  Then I was told to run pylint, and get a score of 10.  The score with my code turned out to be somewhere around 2 or 3.  With some effort, I could get the score of 10.  But I was still wondering, is this all really necessary?  And now when I look back after walking all this pythonic path, I realize wasn't completely wrong.

Okay, Pylint is useful for the project, but only when used in the right way.  To mold pylint to meet the exact requirement of the project, some customization is necessary.  The plain bare pylint, without any customization, creates a lot of noise.  Sometimes so much noise that the real usefulness of pylint gets lost in the noise it creates.  This must be a reason why pylint appears to be a not-so-useful tool, like how it appeared to me when I first used it.

What is this "noise" we are talking about?  Pylint usually creates a very long output, containing a lot of warning, errors, and information.  Not all of this would be important for you.  From the long list, only a handful of messages could be important.  In this useless way, pylint seems like a jailor who believes that the pythonic aphorisms such as "readability counts" are the rules that everyone must strictly follow, and enforces these rules on whoever it meets.  That's not what we want, right?  And for someone like me who has long lived in the other part of the world, where "there are more than one ways to do it", this systematic effort of making all the code in the world look similar is pathetic.

Then what's the trick to get the usefulness of pylint, and leave behind the unwanted noise?  You need to prepare a magic wand, which forces pylint to do only what you want.  The magic wand is a pylintrc file.  And you must prepare it yourself, after figuring out exactly what you want.  The pylintrc file in my project may not be useful for your project.  Because what I want get out of using pylint in my project would be different than what you want to get out of using pylint in your project.  But here's a sample pylintrc file which you could take, to begin with.  You may start with this pylintrc file, and then add more checks to it, as per your requirements.

[MESSAGES CONTROL]

disable=all
# Disable all checks
# and enable only these :
enable=syntax-error,
    import-error,
    unused-import,
    unused-variable,
    reimported,
    used-before-assignment,
    undefined-variable,

[VARIABLES]

init-import=no
# Do not check for unused import in __init__ files.

[BASIC]

bad-functions=map,filter,input
# List of builtins function names that should not be used, separated by a comma

include-naming-hint=no
# Do not include any hint for the naming formats


Here I have disabled all checks, except the seven checks that I have explicitly mentioned.  So all the unwanted noise is gone.  And we get only what is useful for us.  A good start, right?
If you are looking for a list of all pylint features, here it is.  From this list, you could choose what you want, and update your pylintrc file accordingly.  This pylint check could be executed during build process of the project.  And build process could be made to halt upon finding a non-zero exit status from pylint.  So that the errors must be fixed first, and only then build could be created.  In this way, we used pylint to implement a quality check for our project.

Friday, July 5, 2019

How to get the find command to exclude a directory

A friend of mine wanted to use the find command to search certain files in his home directory, but excluding one particular sub-directory.  I thought I could do that in a minute.  But that turned out to be more than a one minute challenge.  Redirecting stderr to /dev/null and thus avoiding to look at the errors was not what he wanted.  He wanted the find command to not step into the particular directory.  Because that directory contained way too many files and so find command was taking too long to finish.

Google told us, -prune could get us to exclude a directory.

When not knowing exactly how to do something with the find command, consulting the manual page is a good place to start.

       -prune True;  if  the  file  is  a  directory,  do not descend into it. If -depth is given, false; no effect.  Because -delete implies -depth, you cannot usefully use -prune and -delete together.

Well, this did not provide clarity to me.  So I explored further.

-prune stops the find command from entering the mentioned directory.  But only -prune is not sufficient to get us what we want.  -prune is an action (like -exec), and not a test (like -type).  -prune alters the list on which further operation is done.  -prune returns true when the file or directory is skipped, and returns false when the file or directory is not skipped.

$ find .  -path ./perl_modules -prune

In the above command, -prune stops the find command from entering the ./perl_modules directory.  After this, we need to use the remaining list and do with it whatever we wanted to.  For this the -o (logical OR) is useful.  The -o (logical OR) provides the list wherever action resulted in false.   This is our intended list (after eliminating what we wanted to exclude).

My friend wanted to list all the files that have aa in their names. 

$ find . -path ./perl_modules -prune -o  -name '*aa*'  -print

In this output, we found that some errors were also printed, as listed below.

find: `./SoNASInstall': Permission denied
find: `./.jazz5': Permission denied
find: `./.metadata': Permission denied


Earlier, I used redirect stderr to /dev/null and thus avoid looking at the errors.

$ find . -path ./perl_modules -prune -o  -name '*aa*'  -print 2>/dev/null

But even better is to eliminate the unwanted files in the list that is provided to further parts of the find command.  We could do this, using the new -prune trick we have learned.

$ find . -path ./perl_modules -prune -o  -name '.?*' -prune -o  -name '*aa*' -print

I chose to go down the rabbit hole some 20 years ago, when I learned SCO Unix system 5.  And I am still discovering how deep it is.  Oh wait, did I choose to go down the rabbit hole, or did it simply happened to me.  That got me thinking, what is choice?  Is it an illusion?  The Merovingian.  Hell ya.  Where are my stud shoes.  Let me get my gear ready for the football game tomorrow morning.  And escape from the rabbit hole, even for a few hours.