If you aren’t happy with Flake8, Pylint, and isort (or maybe if you are!), I recommend checking out Ruff:<p><a href="https://github.com/charliermarsh/ruff">https://github.com/charliermarsh/ruff</a><p>It’s literally 100 times faster, with comparable coverage to Flake8 plus dozens of plugins, automatic fixes, and very active development.
> If your project builds a Docker container, also create a .dockerignore file to specify files and directories that should be excluded from the container.<p>I would nitpick this. You build images not containers and since files are not copied by default there is more nuance here that the .dockerignore file makes builds faster by not including them in the build context.<p>That does ultimately prevent COPY directives from using them but it is these sorts of brief, slightly inaccurate summaries that mislead folks as they build understanding.
Not sure if I like the recommendation to not let Black change your code and just give out errors.<p>I absolutely let Black change code and see the value in Black that it does that so the devs do not have to spend time on manually formatting code.<p>Black shouldn't break anything (and hasn't broken anything for me in the years I used it) but in the unlikely case it does it, there's still pytests/unittests after that that should catch problems...
Even since the start of python typing, it was recommended to use a more generic type like Iterable instead of List. The author claims that List is too specific -- this seems like a straw man argument against typing that doesn't acknowledge python's own advice.<p>Also, mypy has gotten really good in recent years and I can vouch that on projects that have typing I catch bugs much much sooner. Previously I would only catch bugs when unit testing, now they are much more commonly type errors.<p>The other thing typing does is allow for refactoring code. If anything, high code quality relates to the ability to refactor code confidently and typing helps this. Therefore I would put it at the top of the list above all the tooling presented (exception I agree with ci/cd)
> For example, you basically never care whether something is exactly of type list, you care about things like whether you can iterate over it or index into it.<p>This is an odd complaint. typing.Sequence[T] has been there since the first iteration of typing (3.5), for exactly that use case, along with many related collection types.<p><a href="https://docs.python.org/3/library/typing.html" rel="nofollow">https://docs.python.org/3/library/typing.html</a><p>mypy isn’t perfect, but it’s sure better than making things up without any checks; you’re going to want it for all but the smallest projects.
> Coverage measurements are too easy to “game” — you can get to 100% coverage without meaningfully testing all or even most of your code<p>Still it's a good low bar for testing. It's easy and rises code quality. I have very good results with coverage driving colleagues to write tests. And on code review we can discuss how to make tests more useful and robust and how to decrease number of mocks, etc.
I don't understand. The title of the post is: "Boring Python: code quality". Further down: "Today I want to talk about what's generally called "code quality" - tools to help...". I'm sorry but "code quality" is not "tooling". The post should be titled: "Python tooling". Code quality: What abstractions are you using in your code?, How easy is to make a change?, How easy is to understand your code base?, What patterns are you using and why?, Are you abusing class inheritance?, How many side effects are present out there and how does that affect your program?, Are you taking advantage of the Python language facilities and idioms?, Is it easy to write unit tests for?, etc. To sum up: "tooling" != "code quality".
> For example, you basically never care whether something is exactly of type list, you care about things like whether you can iterate over it or index into it.<p>Terrible advice not to use type hints and this reason makes no sense. There's already pretty good support for Sequence and Iterable and so on, and if you run into a place where you really can't write down the types (e.g. kwargs, which a lot of Python programmers abuse), then you can use Any.<p>Blows my mind how allergic Python programmers are to static typing despite the huge and obvious benefits.<p>It's true that Python's static typing does suck balls compared to most languages, but they're still a gazillion times better than <i>nothing</i>, and most of the reason they suck so much is that so many Python developers don't use them!
> I recommend using two tools together: Black and isort.<p>Black formats things differently depending on the version. So a project with 2 developers, one running arch and one running ubuntu, will get formatted back and forth.<p>isort's completely random… For example the latest version I tried decided to alphabetically sort all the imports, regardless if they are part of standard library or 3rd party. This is a big change of behaviour from what it was doing before.<p>All those big changes introduce commits that make git bisect generally slower. Which might be awful if you also have some C code to recompile at every step of bisecting.
There is also a 'hypermodern' cookie cutter template for python projects - I've used it several times now and it works mostly out of the box:<p><a href="https://github.com/cjolowicz/cookiecutter-hypermodern-python">https://github.com/cjolowicz/cookiecutter-hypermodern-python</a>
I don't work on large python projects, mostly just small scripts that need to work well (integrating with a 3rd party rest api is a good example). I don't do CI or unittests but I use git. This is because it takes time and honestly no one outside of myself would care for small stuff like that. But I do run autopep8 and pylint it (I ignore stuff like line being too long,broad exception handling or lack of docs).<p>My concern is a) It needs to be reliable (don't wanna spend a ton of time chasing bugs later on) b) How can I write the actual code better? I see what pro devs write and they use smarter language features or better organization of the code itself that makes it faster and reliable, I wish I could learn that explicitly somewhere.<p>I mean, just the 2.7->3.0 jump was big for me because since I don't code regularly that meant googling errors a lot basically. Even now, I dread new python versions because some dependency would start using those features and that means I have to use venv to get that small script to work and then figure out how to troubleshoot bugs in that other lib's code with the new feature so I can do a PR for them.<p>I love python but this is exactly why I prioritize languages that don't churn out new drastic features quickly. Those are just not suitable for people whose day job is not coding and migrating to new versions, supporting code bases, messing with build systems, unit tests, qa,ci,etc... coding is a tool for me, not the centerpiece of all I do. But python is still great despite all that.
Not agreeing/disagreeing with the message, but the style of writing here is quite nice. It's focused, reasoned, and doesn't make too many assumptions about your tools and environment--and I appreciate that acknowledgment.
One thing that is underestimated is keep the tools version in sync between your app dev dependencies and pre-commit. This also includes plugins for specific tools (for instance flake8). A solution would be to define the hooks in pre-commit to run the tools inside your venv.<p>About typings: I agree the eco-system is not mature enough, especially for some frameworks such as Django, but the effort is still valuable and in many cases the static analysis provided by mypy is more useful than not using it at all. So I would suggest to try do your best to make it work.
I disagree with this assessment on running a static type checker, although I will admit, every update of python over the past 3 years seems to add more and more typing changes which tends to force global typing updates (looking at you Numpy for python 3.12!)<p>When python converges on consistent typing across its extended numpy and pandas ecosystem, I believe we will be able to move towards a fully JIT'd language.
What's the current state of the art of managing multiple virtual environments, running tests and running your application?<p>On Ubuntu and Windows I use Poetry [0], and it works, although it has (had?) some quirks during the installation on Windows.
I liked its portability and lockfile format though.<p>A few years ago I used conda [1], which was nice because it came batteries included especially for Deep Learning stuff.
I switched because it felt way to heavy for porting scripts and small applications to constrained devices like a Raspberry Pi.<p>And then there are also Docker Images, which I use if I want to give an application to somebody that "just works".<p>What's your method of choice?<p>[0] <a href="https://python-poetry.org/" rel="nofollow">https://python-poetry.org/</a><p>[1] <a href="https://www.anaconda.com/" rel="nofollow">https://www.anaconda.com/</a>
I wish VSCode would figure out that ExampleModel.objects.first() returns ExampleModel or None or ExampleModel.objects.filter() returns an iterable of ExampleModel. Has anybody gotten this working, automatically or manually annotating?