Skip to content

Commit

Permalink
add incomplete posts, update deps
Browse files Browse the repository at this point in the history
  • Loading branch information
phiresky committed Feb 12, 2021
1 parent 84d8f4d commit 78cfbaa
Show file tree
Hide file tree
Showing 9 changed files with 2,772 additions and 5,893 deletions.
6 changes: 3 additions & 3 deletions client/components/Pandoc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ export default function Pandoc({
{(config) => {
const renderers = { ...defaultRenderers, ...config.renderers }
if (ele.t in renderers) {
const C = renderers[ele.t] as React.FunctionComponent<
p.AnyElt
>
const C = renderers[
ele.t
] as React.FunctionComponent<p.AnyElt>
return <C {...ele} />
} else return <>[UNK:{ele.t}]</>
}}
Expand Down
62 changes: 28 additions & 34 deletions client/next.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const withCSS = require("@zeit/next-css")
const withSass = require("@zeit/next-sass")
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true",
})
Expand All @@ -14,36 +12,32 @@ const summary = require("../posts-built/summary.json")
// const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin")
const isProd = process.env.NODE_ENV === "production"

module.exports = withBundleAnalyzer(
withSass(
withCSS({
assetPrefix: isProd ? config.blogRoot : "/",
webpack: (config) => {
config.module.rules.push({
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 100000,
name: "[name].[ext]",
},
},
})
return config
module.exports = withBundleAnalyzer({
assetPrefix: isProd ? config.blogRoot : "/",
webpack: (config) => {
config.module.rules.push({
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 100000,
name: "[name].[ext]",
},
},
async exportPathMap() {
const { posts } = summary
const o = {
[config.blogRoot]: { page: "/" },
}
for (const post of posts) {
const { url, slug } = makeUrl(post)
o[url] = { page: "/post", query: { slug } }
}
console.log(o)
return o
},
exportTrailingSlash: true,
}),
),
)
})
return config
},
async exportPathMap() {
const { posts } = summary
const o = {
[config.blogRoot]: { page: "/" },
}
for (const post of posts) {
const { url, slug } = makeUrl(post)
o[url] = { page: "/post", query: { slug } }
}
console.log(o)
return o
},
trailingSlash: true,
})
1 change: 1 addition & 0 deletions client/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// https://github.com/zeit/next-plugins/issues/282
import "prismjs/themes/prism-tomorrow.css"
import "tachyons/css/tachyons.min.css"
import "../post.scss"
import App from "next/app"

export default App
1 change: 0 additions & 1 deletion client/pages/post.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { Code } from "../components/Code"
import { WithRouterProps } from "next/dist/client/with-router"
import { config } from "../config"
import { formatDate } from "../utils/date"
import "../post.scss"
import Pandoc from "../components/Pandoc"
import { InlineMath, BlockMath } from "react-katex"
import "katex/dist/katex.min.css"
Expand Down
57 changes: 27 additions & 30 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,63 +13,60 @@
"commit": "rm -rf dist/* && yarn build && ./postprocess.sh"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^3.4.0",
"@typescript-eslint/parser": "^3.4.0",
"eslint-config-prettier": "^6.11.0",
"@typescript-eslint/eslint-plugin": "^4.15.0",
"@typescript-eslint/parser": "^4.15.0",
"eslint-config-prettier": "^7.2.0",
"eslint-plugin-prettier": "^3.1.4",
"husky": ">=1",
"husky": "^5.0.9",
"lint-staged": ">=8.2.1",
"next": "^9.1.5",
"next": "^10.0.6",
"prettier": "^2.0.5",
"processmd": "^4.4.2",
"standard": "^14.3.1"
"standard": "^16.0.3"
},
"dependencies": {
"@babel/core": "^7.4.5",
"@next/bundle-analyzer": "^9.1.5",
"@types/js-yaml": "^3.12.1",
"@next/bundle-analyzer": "^10.0.6",
"@types/js-yaml": "^4.0.0",
"@types/rc-tooltip": "^3.7.1",
"@types/react": "^16.8.20",
"@types/react-dom": "^16.8.4",
"@types/react": "^17.0.1",
"@types/react-dom": "^17.0.0",
"@types/recharts": "^1.1.16",
"@types/styled-jsx": "^2.2.8",
"@types/webpack": "^4.41.0",
"@zeit/next-css": "^1.0.1",
"@zeit/next-sass": "^1.0.1",
"@zeit/next-typescript": "^1.1.1",
"anchorme": "^2.1.2",
"babel-loader": "^8.0.6",
"eslint": "^7.3.1",
"feed": "^4.0.0",
"glob": "^7.1.4",
"js-yaml": "^3.13.1",
"js-yaml": "^4.0.0",
"next-routes": "^1.4.2",
"node-sass": "^4.12.0",
"node-sass": "^5.0.0",
"pandoc-filter": "^2.0.0",
"pandoc-url2cite": "^0.6.4",
"rc-tooltip": "^4.0.0-alpha.3",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"rc-tooltip": "^5.0.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-katex": "^2.0.2",
"react-markdown": "^4.0.8",
"react-syntax-highlighter": "^12.2.1",
"react-markdown": "^5.0.3",
"react-syntax-highlighter": "^15.4.3",
"recharts": "^2.0.0-beta.1",
"remark-frontmatter": "^2.0.0",
"remark-parse": "^8.0.2",
"remark-react": "^7.0.1",
"remark-stringify": "^8.1.0",
"strip-markdown": "^3.0.3",
"remark-frontmatter": "^3.0.0",
"remark-parse": "^9.0.0",
"remark-react": "^8.0.0",
"remark-stringify": "^9.0.1",
"strip-markdown": "^4.0.0",
"styled-jsx": "^3.2.1",
"styled-jsx-plugin-sass": "^1.0.0",
"tachyons": "^4.11.1",
"ts-loader": "^7.0.5",
"ts-node": "^8.2.0",
"ts-loader": "^8.0.17",
"ts-node": "^9.1.1",
"tsconfig-paths-webpack-plugin": "^3.2.0",
"typescript": "^3.9.5",
"typescript": "^4.1.5",
"unified": "^9.0.0",
"url-loader": "^4.1.0",
"val-loader": "^2.0.2",
"webpack": "^4.34.0"
"val-loader": "^3.0.0",
"webpack": "^5.21.2"
},
"husky": {
"hooks": {
Expand Down
198 changes: 198 additions & 0 deletions posts/2021/python-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
---
title: "10 underused features of modern Python [incomplete]"
subtitle: ""
date: 2021-02-15
hidden: true
---

## Named tuple

```py
from typing import NamedTuple

class EnvParams(NamedTuple):
name: str
nr_agents: int
mode: Literal["uniform", "relative"] = "uniform"

def get_params() -> EnvParams:
return EnvParams(name="hello", nr_agents=42)
```

- automatic constructor generation etc
- strong typing
- immutable
- same memory usage as normal tuples
- default values
- more safety than tuples, access `params.name` like objects, order does not matter
- compatible API with tuples

## Typing

## F strings

```py
def fn(x):
return x * x

x = 5
print(f"for input {x:.1f}, {fn(x)=}")
```

Prints: `for input 5.0, fn(x)=25`

Similar to `"x is {x}".format(x=x)` but easier to read and write.
You can add simple expression inside the {}.
The special format specifier `f"{foo=}"` is the same as doing `f"foo={foo}"`

## Pathlib

```py
from pathlib import Path

mydir = Path("foo")

myfile = mydir / "filename.txt"
```

If you pass file paths around as strings, you have to figure out when to add slashes and when not to, and unless you always use `os.path.sep` your code will work differently depending on the OS.

`Path`s have great methods for manipulating filenames that are much more readable than their `os.path` equivalents:

```py
myfile = Path("foo/filename.txt")
myfile.parent # Path("foo")
myfile.name # "filename.txt"
myfile.suffix # ".txt"
# replace file extension
myfile.with_suffix('.csv') # foo/filename.csv
```

`Path`s also have neat methods for opening / reading / writing files:

```py
myfile.write_text("hello")

if myfile.exists():
with myfile.open("r") as f:
# ...
pass

text = (mydir / "input.txt").read_text()


for file in Path("foo").glob("*.txt"):
# every txt file in foo/
pass
```

## Relative imports

The following is fairly common python code:

```
import util
util.foo()
```

But what is `util`? It can be either a global module or a local file / directory. If there is a local file named `util.py`, it will shadow the corresponding module. This is a pretty common issue, and happens even to [experienced devs](https://github.com/pytorch/pytorch/issues/24807#issuecomment-524155619).

Instead, in my opinion you should always use relative imports if you want to import a relative module instead of global ones.

```py
from . import util
# or
from .util import foo
```

Sadly this ambiguity issue is not completely fixeable without a breaking change in python itself, and due to a bad design decision in the Python module system relative imports have [some issues when python files are loaded in a specific way called "script mode"](https://stackoverflow.com/a/28154841/2639190), which you will probably come across sooner or later.

## Ordered unordered dicts

Since Python 3.6, Python uses a more compact representation of dicts (and thus `kwargs`).
Since Python 3.7, it is guaranteed that dicts are always iterated over in insertion order.

This means that every dict is basically an `OrderedDict` except some utility functions are missing. This is really useful, because it means you can use normal dicts as ordered associative arrays.

```py
x = {
"c": True,
"b": False,
"d": False
}
for key in x:
# guaranteed to always go through keys in the order "c", "b", "d"!
```

# Multiprocessing

There's a ton of libraries for multithreading / multiprocessing in python, with varying degrees of magicness. But in Python 3, there's actually an integrated way to run a function on a large set of data quickly: [`multiprocessing.Pool`](https://docs.python.org/3/library/multiprocessing.html)

```py
def f(x):
# expensive computation
return x * x

from multiprocessing import Pool

with Pool() as p:
for result in p.imap(f, [1, 2, 3], chunksize=100):
# ... handle result
```

This code does the same as `for i in [1,2,3]: f(i)` except using all your CPU cores.

## Poetry

Here is all the stages of a Python developer's slow decent into madness:

1. You write single file .py scripts without imports and functions. It's so easy to get so much done! You feel enlightened.
2. You start splitting your code in multiple functions in .py files, and feel enlightened of how structured your code is now.
3. You need to do some maths, so you learn about `pip` and run `pip install numpy` globally. You feel enlightened about how easy it is to use libraries. It's as easy as [import antigravity](https://xkcd.com/353/)!
4. At some point you have some multiple projects that need different versions of some libraries. You learn about virtualenvs. You are confused about the difference between `venv`, `virtualenv`, `virtualenvwrapper`, but some random memorized commands works so you start using virtualenvs.
5. You try to use some older library from GitHub. You learn about `setup.py` files and `requirements.txt` files, and you feel enlightened! This is how you define exactly what you need to run your program! The project you're trying to use has a requirements.txt file like this:

pandas
numpy

So you eagerly run

```sh
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

Then you try running the project, but it turns out it actually also needs `sklearn`. So you try `pip install sklearn` only to realize that `sklearn` is actually a random package from someone else and to get `sklearn` you actually need to install `scikit-learn`. You realize that package names are not actually related to the names of python modules (except incidentally) and feel enlightened by the power!

But the code still doesn't run, theer's some weird issue. After an hour of investigation, you find some obscure bug [caused by an incompatible change](http://blog.khinsen.net/posts/2017/11/16/a-plea-for-stability-in-the-scipy-ecosystem/) some time 5 years ago in numpy. You try some old numpy versions until you find one that works. You learn about semver and freezing, and you feel enlightened! The developer should have just put `numpy==1.10` into their requirements.txt!

6. You find [something that recommends using Conda](https://pytorch.org/get-started/locally/). You are somewhat confused why the conda download is taking so long and eats up 2GB of bandwidth.
After accepting a random EULA and having your shell changed prompt always say `(base) $`, you realize that in conda, everything is an env! It's so quick to add libraries, [even weird native ones](https://anaconda.org/anaconda/mkl) ! You feel enlightened.
7. You read some documentation and call a python function, but the function does not exist. After some reading, you see that the package you installed via conda is an outdated version. You now understand that conda is a completely different package manager from pip, and that conda packages are actually managed by third parties, some of which are outdated, and many don't exist at all. You start using `pip` for some things and `conda` for other things, all in the same environment.
8. The find out about the Official Modern Python Packaging tool [pipenv](https://pipenv.pypa.io/en/latest/)! Pipenv always and automatically manages a virtualenv with the exact dependencies as defined in a `Pipfile`, which is like a supercharged `requirements.txt`. It's amazing! Except you soon try to install a package and get a `Could not resolve dependencies` error. You google a while, and figure out that most pypi packages don't actually have correctly specified dependencies, and that pip just doesn't really care about that. You also find out that [pipenv only really pretended to be an official tool](https://chriswarrick.com/blog/2018/07/17/pipenv-promises-a-lot-delivers-very-little/).
9. You find out about [poetry](https://python-poetry.org/). It's like pipenv but actually good! It only takes 2 minutes to resolve dependencies instead of 10! It even puts your virtualenv in `~/.cache` because it _really_ doesn't matter if it gets deleted!
# Typed Argparse
Argparse is a neat library to create a simple command line interface. But arguments are declared as strings, and the IDE can't know about them.

With [Typed-Argparse](https://github.com/swansonk14/typed-argument-parser), your arguments are parsed directly into a class instance!

![TAP example](https://raw.githubusercontent.com/swansonk14/typed-argument-parser/master/images/tap.png)

````

```
```

```
```

```
```
````
Loading

0 comments on commit 78cfbaa

Please sign in to comment.