In the middle of the desert you can say anything you want
Hugo generates anchors from headers automatically 1. Tested it - yes, except they’re lowercased and spaces get converted to -
(which makes sense).
As a refresher, in HTML it’s
<h2 id="anchor">..</h2>
<a name="anchor"></a>
<a href="#anchor">anchor link </a>
One additional way to check the type hints in #python is mypy
, installable as python package.
mypy -p package_name
checks the typing in the package, and found some potential errors in corner cases I didn’t know about in one of the projects I’m working on!
Finds wrong typing, missing/wrong return values, that kind of stuff.
It doesn’t like what: str or Path
typing output, I guess only Union[str, Path]
- is there a reason for it?
In any case I like it more than Pycharm’s way of outputting things and will be using it along with black
and flake8
in the future (along with typing itself).
#py/mypy
Tried to download a Teamcity artifact through wget
, and apparently you can if you provide a user/pass through wget!
I assume it’s HTTP auth or something
wget --user username --password my-password https://teamcity.location/repository/download/....
Had issues, asked for help, and then learned a lot of stuff.
git rebase branchname
!= git rebase origin/branchname
!
The first one is about the current local state of the branch, the second one about the one on remote.
BUT the one on remote as known by local != one on remote-remote! You need to update first!
git fetch --all
or whatever.
I’d previouly update / pull before through PyCharm before doing that, and this abstracted all of this away from me.
To access the #obsidian console, <C-S-i>
worked. It was the standard “Dev tools”.1
Since I seem to keep forgetting:
simple-scan
is the program I use to talk to scanners. You can select various options (scan document, photo etc).
Keeps #scanning in the exact same PDF document until you break it.
In #pycharm, “Pin tab” exists! But then it’s not “Tab 1” etc anymore and I can’t use my shortcuts
(Those too after a long talk to a colleague at work, this time #py/argparse)
Cool things about argparse
:1
parser.add_argument('--two-words')
would automatically map to args.two_words
(_
vs -
)!pathlib.Path()
works as expected, and even automagically parses string paths from args into the Path!
str or Path
ambiguity.“Be strict and clear from the very beginning, then you don’t have to deal Path or str”
parser.add_argument('a', type=argparse.FileType('w', encoding='latin-1'))
parser.add_argument('b', type=pathlib.Path)
os.environ()
! Then you can also run it as
WHATVEER_VALUE=234 python3 file.py
A nice structure for it all is:
if __name__ == '__main__':
runs a function like main()
getting rid of the scope issuesdef parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument('--input-directory' ..)
return parser.parse_args()
main()
we use it like args = parse_args(); if args.input_directory == ...
This is nice also because then we don’t have to deal with an arparse object in main, just its results.Also, in general, CLI programs have arguments like program --arg-one
, not program --arg_one
. I write the latter one because I still feel I’m in a python world, but Python would parse such dashed arguments into classic ones (see above). TODO look for some best practices for CLI programs, including Python ones, POSIX etc etc etc.
From a conversation with a colleague at work about #py/logging
Logger names can be used to cleanly output and separate them.
Assuming one has a package with multiple files/subfolders in it, it’s possible to give each one their own logger, like this:
In the main file of the package:
logger = logging.getLogger(__package__)
In all the other files:
logger = logging.getLogger(__name__)
That way paths ./package/my_module.py
lead to loggers named like package.my_module
that map the semantical and the directory structure.
In a setup above, one can then easily change the settings of the loggers referring to them by their names.
Configuring logging: Logging HOWTO — Python 3.10.0 documentation
Changing loglevel is easy from code,
if args.debug:
logger.setLevel(logging.DEBUG)
logging.config
allows to change the config from ini-like config files. Two main ways:
logging.config.fileConfig
reads ini-like config files,
logging.config.dictConfig
1 from dictionaries.
Sample .yaml that when converted to dict would change the loglevel of different loggers:
version: 1
loggers:
packageName.mymodule1:
level: DEBUG
packageName.mymodule2:
level: DEBUG
These loggers can even include external ones!
Short notes about #py/poetry for package management
poetry new packagename
creates a poetry project
From within the folder with the package:
poetry install
== pip3 install -r requierements.txt
poetry shell
== source .venv/bin/activate
exit
== deactivate
Basic usage | Documentation | Poetry - Python dependency management and packaging made easy:
{cache-dir}/virtualenvs
, which on my box is /home/me/.cache/pypoetry/virtualenvs/ptest-eeSDLvcF-py3.6/bin/activate
poetry.lock
caches the resolved packages once we install things once.
pyproject.toml
, a warning will be shown otherwisepoetry update
updates everything to the latest versions, overwriting poetry.lock
poetry init
initializes a project and creates a pyproject.toml
interactively, allowing even to search for packages etc!Adding packages:
poetry add yaml
adds a packagepoetry search yaml
looks for packages in remote repos! Will tell you that you actually want pyyaml