How to set up a perfect Python project
sourcery.ai
sourcery.ai
For me pipenvs only selling point is that some people don’t know about python -m venv.
But I hate pipenv, so much.
The basic idea of pipenv, being able to resolve the dependency graph more cleanly and precisely, is far far far better - but there are still some usability improvements that leave something to be desired.
I only use pipenv on a work project with a hundred dependencies, and venv on one other large side project. Everything else is installed with --user, especially dev tools like black and pyflakes. The user folder gets cleaned up every few years when you upgrade to a new version of python (rm ~/.local/lib/python3.5).
Has worked fine for a decade or two, no conflicts. I think some folks get spooked at python packaging and overcompensate in response, but it's pretty easy to troubleshoot when you've learned how it works.
Quickly noticing my mistake in being driven to play with shiny, new toys, I went back to my old tried-and-true pip + virtualenv for local development and plain old pip inside docker.
I think part of the drive around changes to Python packaging standards and tools has been inflated by a poor understanding and poor usage of existing tools.
Take setup.py for example - nearly everything you read in Python pushes using a requirements.txt file in your project. Why not define your project as an installable package with its own hard requirements - that are defined in your setup.py - and leave the Pip requirements.txt strictly for additional development/test dependencies? Or, maybe better, put test requirements in tests_require?
Nothing against Kenneth, but a big part of me wishes there were more anonymity in the open-source community. It's too easy for a single, well-known individual to come in and publicize <something> and everyone jumps on the <something> bandwagon without realizing that <other-thing> already exists, works well, and is an established standard.
Your pipeline should be responsible for ensuring things don't make it into the master branch that shouldn't. Run tests and linting on a pull request and make it a requirement for those to pass in order to merge the PR. Otherwise one of two things is going to happen:
1. People will not commit frequently and you will have a commit history that isn't as granular as it should be.
2. People will just bypass the githook check
TBH I think some of this stems from people's fear of rebasing. I've heard so many times, "But it rewrite's the history". Yes, but it's the history on YOUR branch. Nobody should care what you to do your branch and it is yours to perfect. You should want to rewrite the history of your branch in my opinion. If you're committing frequently there will inevitably be some commits you want to squash or fixup.
Aka, sometimes useful, but usually a bad idea.
I don't know why there's such a fear of rebasing, in a lot of situations it's the right way to go.
I don't like squashing though, but that's a personal choice - sometimes excessive use of squash can hide the history of why things developed the way they did, and that can sometimes be very useful information.
Also, huge fan of pytest (as is mentioned) and mypy (not mentioned, but quite helpful).
[edit] mypy is indeed mentioned! I must’ve missed that on first pass.
[0] https://www.python.org/dev/peps/pep-0518/#sticking-with-setu...
But I don’t like unnecessary different levels of reality (code one way, commit another) and hitting shift quote all those times sucks.
It’s funny how an “opinionated formatter” sounds great in theory until you realize the opinion is “wrong.”
Also it depends what you are using it for, 1) to keep your team focused, or 2) enable anyone in the python community to feel comfortable jumping into the project. Given not everyone uses black, #2 is not as common as you'd think.
I don’t think Black’s dream of all Python looking the same is that worthwhile. Especially if people don’t like some of Black’s decisions.
I might use Blacker if it existed, but I’m currently ok with not using Black and just sticking with flake8.
In code, I prefer whichever style tends to produce the fewest escape-sequence situations.
If the code contains hard-coded strings, that's usually double-quotes, though not always.
Otherwise I guess it makes less sense to want to push +shift+ everytime you enter a quote on a Python dict key, for example, versus using the single quote.
"this", "that", "and", "the", "other"
vs 'this', 'that', 'and', 'the', 'other'
However, in Ruby, PHP, Groovy, and JavaScript single quotes have actual functional advantages, either through simpler syntax abilities, or by not requiring escaping double quotes for HTML/XML.It’s not a big deal to me as I don’t care too much (similar to tabs vs space). I have a preference but would likely spend zero time caring if my team were trying to decide and would never in a million years try to change someone else’s project.
Addendum for clarification: part of the appeal of autoformatters is that what you type into your editor does not matter. I don't see the "difference of reality" because thanks to black, I don't need to care.
I’m happy to adopt to other folks projects as I don’t want to convert anyone. But purposely working on my own projects with a quote different than the record seems like an extra effort, even if minimal.
In projects where I am involved in, we usually set up hooks that run a few checks from https://github.com/pre-commit/pre-commit-hooks plus https://github.com/asottile/pyupgrade plus https://github.com/psf/black plus maybe the mypy and flake8 hooks. These hooks are also run in a "lint" stage by by tox, which is also run on the CI system. This catches some lints that slip through every now and then, before you go on to commit them. Also, a tox run will as a side effect also reformat the code before you check it in, which is a nice laziness feature.
I am currently thinking if I should move to the pytest plugins for mypy and flake8 because I find they make more sense as tests, especially if I'm developing inside a venv and repeatedly run pytest instead of tox. That would also mean that the mypy and flake8 checks are run repeatedly for every Python interpreter I want to tox, unkess I invest some time into coming up with better TOXENVs. Hm.
The fastest I've seen them run recently is 3 minutes. With about 800 tests, PyTest take a minimum of 45 seconds just to do test discovery--the tests actually run faster. We started with Flake8 and have been slowly adding PyLint checks, but each check (so far) has added a little more time. We diff the local "feature" branch against the remote dev branch and only run PyLint against the differences, but it still takes 1 min on average to run--experiments to run against a smaller set of files still result in coffee break worthy execution times most of the time.
Judging from history, if we enforced the use of Git hooks to run these tools it would result in mutiny with teams "secretly"--their manager(s) being onboard--working around and supplanting the tool. Small things like this result in a lot of frustration and a loss of goodwill.
We use a combination of Python Invoke and the flake8 & pylint CLI commands. At some point we plan to reinvestigate our use of Python Invoke as it doesn't run tasks in parallel--we were new to Python when we started this project two years ago and didn't understand the limitations of the tools we were using. (I should say, Python Invoke has worked out well for most of our developer centric tasks.)
We run both Flake8 and Pylint as we started out with Flake8 and later tried to use Pylint. The workload to fix the code base was too much for us as most developers are QA people learning good software design and how to share a large code base with their "extra", "volunteer" time. We've been slowly turning on more Pylint checks and cleaning up the code base. When we did try to move more quickly, we were deluged with complains about the cognitive load it placed on people and backed off.
We did find some differences, but I don't remember what they were and couldn't comment on the significance.
Another thing I like to do is create a skeleton project and keep it in Git, so that this stuff doesn't have to be done manually for each new git project. You can check out/fork/clone/whatever the skeleton and have most of this stuff pre-configured, including e.g. a baseline requirements.txt for whatever frameworks you use.
You can also put the pre-commit stuff into a ~/.git_template so that newly-created repos already have it configured. It's a bit harder to manage if you work with multiple unrelated languages/frameworks, but can be a real time-saver in a uniform environment.
It seems to be easier to do right in the first place than fix everything. JavaScript yarn is really good but only based on npm already done most things okayish.
A good news is that modern languages like Go, Rust, Elixir, etc designed more carefully with this, providing much better experiences.
Contrarian-for-the-sake-of-it and ultimately contentless comment = "Not Performance Art"?
Got it.
Why is it that every-time someone says something _everyone else should be thinking_, it gets downvoted to hell. I'm guessing it's because the way you said it, but something tells me the wiser, more experienced opinions such as yours just aren't flashy or trendy enough to get support in this modern, up-vote world.