mirror of
https://github.com/jbranchaud/til
synced 2026-07-02 23:58:25 +00:00
Compare commits
3 Commits
ab8331000f
...
a8c35e2458
| Author | SHA1 | Date | |
|---|---|---|---|
| a8c35e2458 | |||
| c0ad3cee4d | |||
| 9bd1bb413a |
@@ -10,7 +10,7 @@ working across different projects via [VisualMode](https://www.visualmode.dev/).
|
||||
|
||||
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
||||
|
||||
_1780 TILs and counting..._
|
||||
_1783 TILs and counting..._
|
||||
|
||||
See some of the other learning resources I work on:
|
||||
|
||||
@@ -1050,6 +1050,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Access Instance Variables](python/access-instance-variables.md)
|
||||
- [Access Most Recent Return Value In REPL](python/access-most-recent-return-value-in-repl.md)
|
||||
- [Access Variables Outside Loop Scope](python/access-variables-outside-loop-scope.md)
|
||||
- [Assert Is Only A Development Check](python/assert-is-only-a-development-check.md)
|
||||
- [Avoid Modification With Frozen Dataclass](python/avoid-modification-with-frozen-dataclass.md)
|
||||
- [Break Debugger On First Line Of Program](python/break-debugger-on-first-line-of-program.md)
|
||||
- [Check If Package Is Installed With Pip](python/check-if-package-is-installed-with-pip.md)
|
||||
@@ -1057,6 +1058,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Create A Dummy DataFrame In Pandas](python/create-a-dummy-dataframe-in-pandas.md)
|
||||
- [Create A Range Of Descending Values](python/create-a-range-of-descending-values.md)
|
||||
- [Deduplicate A List Into A Tuple](python/deduplicate-a-list-into-a-tuple.md)
|
||||
- [Define Sequence Of Tests With Parametrize Decorator](python/define-sequence-of-tests-with-parametrize-decorator.md)
|
||||
- [Dunder Methods](python/dunder-methods.md)
|
||||
- [Easy Key-Value Aggregates With defaultdict](python/easy-key-value-aggregates-with-defaultdict.md)
|
||||
- [Install With PIP For Specific Interpreter](python/install-with-pip-for-specific-interpreter.md)
|
||||
@@ -1796,6 +1798,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Rename A Bunch Of Files By Constructing mv Commands](unix/rename-a-bunch-of-files-by-constructing-mv-commands.md)
|
||||
- [Repeat Yourself](unix/repeat-yourself.md)
|
||||
- [Replace Pattern Across Many Files In A Project](unix/replace-pattern-across-many-files-in-a-project.md)
|
||||
- [Reverse Each Line Of A File](unix/reverse-each-line-of-a-file.md)
|
||||
- [Run A Command Repeatedly Several Times](unix/run-a-command-repeatedly-several-times.md)
|
||||
- [Run A cURL Command Without The Progress Meter](unix/run-a-curl-command-without-the-progress-meter.md)
|
||||
- [Safely Edit The Sudoers File With Vim](unix/safely-edit-the-sudoers-file-with-vim.md)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Assert Is Only A Development Check
|
||||
|
||||
The `assert` keyword is used in Python to write a statement that will check some
|
||||
assertion and raise an error if it isn't met. This is only meant to be used as a
|
||||
check during development because it can be easily optimized out of the code.
|
||||
|
||||
```python
|
||||
stuff = None
|
||||
|
||||
assert stuff, "We need to have some stuff to proceed"
|
||||
|
||||
print(f"We have {stuff or 'something'}!")
|
||||
```
|
||||
|
||||
If I execute this code with `python`, it will raise on that second line of code.
|
||||
|
||||
```bash
|
||||
❯ python assert_example.py
|
||||
Traceback (most recent call last):
|
||||
File "/Users/lastword/dev/jbranchaud/py-vmt/assert_example.py", line 3, in <module>
|
||||
assert stuff, "We need to have some stuff to proceed"
|
||||
^^^^^
|
||||
AssertionError: We need to have some stuff to proceed
|
||||
```
|
||||
|
||||
This `assert` statement will be stripped out of the compiled bytecode if the
|
||||
`-O` (capital o) flag is used. Notice how running the same file with that flag
|
||||
does not lead to an `AssertionError`.
|
||||
|
||||
```python
|
||||
❯ python -O assert_example.py
|
||||
We have something!
|
||||
```
|
||||
|
||||
If I want to make sanity checks for situations that would be caused by a bug in
|
||||
the code, an `assert` statement can be a good candidate. However, if I am making
|
||||
runtime checks like validating user input, then an `if` statement and raising
|
||||
something like a `ValueError` is better.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Define Sequence Of Tests With Parametrize Decorator
|
||||
|
||||
I have a function that I want to test across a bunch of different inputs. That
|
||||
way I can make sure the logic of that function handles all the different
|
||||
scenarios I have in mind.
|
||||
|
||||
While working on [`py-vmt`](https://github.com/jbranchaud/py-vmt), I started by
|
||||
writing a big single test function with a sequence of variable assignments and
|
||||
`assert` statements. Here's my starting point:
|
||||
|
||||
```python
|
||||
def test_format_time_delta_everything():
|
||||
# less than a minute
|
||||
thirty_seconds = timedelta(seconds=30)
|
||||
assert "30s" == format_time_delta(thirty_seconds)
|
||||
|
||||
# one minute exactly
|
||||
one_minute = timedelta(seconds=60)
|
||||
assert "1m" == format_time_delta(one_minute)
|
||||
|
||||
# more than a minute
|
||||
assert "1m30s" == format_time_delta(one_minute + thirty_seconds)
|
||||
|
||||
# bunch of minutes and seconds
|
||||
delta = timedelta(minutes=24, seconds=8)
|
||||
assert "24m8s" == format_time_delta(delta)
|
||||
|
||||
# one hour exactly
|
||||
one_hour = timedelta(hours=1)
|
||||
assert "1h" == format_time_delta(one_hour)
|
||||
|
||||
# more than one hour
|
||||
assert "1h24m" == format_time_delta(one_hour + delta)
|
||||
```
|
||||
|
||||
I knew I would eventually need to break it up into individual test functions,
|
||||
but I couldn't bare to start there because it seemed quite repetitive.
|
||||
|
||||
There is another way to approach this without all the duplication. Pytest comes
|
||||
with [a "parametrize" decorator](https://docs.pytest.org/en/stable/example/parametrize.html). This is
|
||||
used to define a set of test data (and expected values) that will get passed
|
||||
one-by-one to the test function as parameters.
|
||||
|
||||
```python
|
||||
@pytest.mark.parametrize("input,expected", [
|
||||
(timedelta(seconds=30), "30s"),
|
||||
(timedelta(seconds=60), "1m"),
|
||||
(timedelta(seconds=90), "1m30s"),
|
||||
(timedelta(minutes=24, seconds=8), "24m8s"),
|
||||
(timedelta(hours=1), "1h"),
|
||||
(timedelta(hours=1, minutes=24, seconds=8), "1h24m"),
|
||||
])
|
||||
def test_format_time_delta(input, expected):
|
||||
assert format_time_delta(input) == expected
|
||||
```
|
||||
|
||||
I ditch all of the duplication this way. I define a list of tuples that
|
||||
represent my input values and expected values. Then the body of the test can be
|
||||
minimal. And I get a separate test execution for each parameter tuple making it
|
||||
easier to see fine-grained pass/fail results.
|
||||
@@ -0,0 +1,64 @@
|
||||
# Reverse Each Line Of A File
|
||||
|
||||
The [`rev` command](https://man7.org/linux/man-pages/man1/rev.1.html) can be
|
||||
used to reverse each line in a file. Every line is left where it is relative to
|
||||
other lines, but the contents of each line is reversed.
|
||||
|
||||
So a file that contains the following text:
|
||||
|
||||
```bash
|
||||
❯ cat stuff.md
|
||||
Three
|
||||
Two
|
||||
One
|
||||
go racecar go
|
||||
```
|
||||
|
||||
can be piped to `rev` to get the following output:
|
||||
|
||||
```bash
|
||||
❯ rev stuff.md
|
||||
eerhT
|
||||
owT
|
||||
enO
|
||||
og racecar og
|
||||
```
|
||||
|
||||
This is an odd utility that doesn't have too much use that I can imagine. After
|
||||
a brief chat with Claude where I asked for some practical use cases, the one
|
||||
that stood out the most to me is to reverse a list of filenames, sort them, and
|
||||
then reverse them again (putting them back in readable order). This can shuffle
|
||||
filenames with similar endings near each other like source and test files.
|
||||
|
||||
Here is a list of files for me [`py-vmt`
|
||||
project](https://github.com/jbranchaud/py-vmt):
|
||||
|
||||
```bash
|
||||
❯ fd -t f .
|
||||
README.md
|
||||
pyproject.toml
|
||||
src/py_vmt/__init__.py
|
||||
src/py_vmt/cli.py
|
||||
src/py_vmt/session.py
|
||||
src/py_vmt/time_helpers.py
|
||||
tests/src/py_vmt/test_cli.py
|
||||
tests/src/py_vmt/test_session.py
|
||||
```
|
||||
|
||||
Now I can pipe the output of that `fd` command through `rev | sort | rev` to get
|
||||
my files organized in a different way.
|
||||
|
||||
```bash
|
||||
❯ fd -t f . | rev | sort | rev
|
||||
README.md
|
||||
pyproject.toml
|
||||
src/py_vmt/__init__.py
|
||||
tests/src/py_vmt/test_cli.py
|
||||
src/py_vmt/cli.py
|
||||
tests/src/py_vmt/test_session.py
|
||||
src/py_vmt/session.py
|
||||
src/py_vmt/time_helpers.py
|
||||
```
|
||||
|
||||
Again the value of doing something like this is a bit tenuous. At the very least
|
||||
it is fun to know about.
|
||||
Reference in New Issue
Block a user