Skip to content

Commit 4de2be3

Browse files
Merge pull request #36 from MarcellPerger1/add-code-style-readme
docs: Add code style
2 parents 2d335f4 + 847649d commit 4de2be3

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,44 @@
66
This language would eventually be used:
77
- either as an internal representaion (e.g. a function for each of the opcodes of python) so I don't have to implement everythin using drag-and-drop
88
- or as the language that can be compiled to scratch
9+
10+
### Code style/guidelines
11+
- Rule 0: **`readability counts`**.
12+
- I generally follow [PEP 8](https://peps.python.org/pep-0008/) except:
13+
- Line length:
14+
- Lines longer than 93 characters should be wrapped
15+
- When wrapping lines, each component should be at most 80 characters.
16+
- i.e. If a statement is over multiple lines, max length is 80 If it's a single line, max length is 93.
17+
- Quotes:
18+
- Generally use double quotes (`"`), especially for error message and similar (makes it easier to add `'` if the error message is tweaked).
19+
- Single quotes (`'`) may be used for internal IDs and strings not directly displayed to the used (e.g. `'<='`, `'call_args'`)
20+
- Private names (`__private`):
21+
- Don't use them. They cause problems with getattr and similar annoyances.
22+
- Indentation in long wrapped conditions (`if`/`while`):
23+
- Add an extra indent (4 spaces) to distinguish the 2nd/3rd line of the condition from the body of the block.
24+
- Type annotations:
25+
- Always use them for parameter types, even in internal/private functions.
26+
- Use them for return types if the IDE (Pycharm for me) can't figure it out, or if it's unclear, or you just feel like it.
27+
- Even use them for local varaibles (if the IDE can't infer the types - e.g. the typechecker doesn't know what type goes in the list if it's `ls = []`)
28+
- Use the most accurate/precise types possible (e.g. `dict[str | tuple[str, int], type[NamedNodeCls]` instead of `dict` (which gives almost no information))
29+
- If type are getting too long/repetitive/recursive, use type variables.
30+
- Try to make typing work without resorting to `Any` (e.g. using `cast`).
31+
- `from __future__ import annotations` + `if TYPE_CHECKING` is good if you expereince circular import issues due to types.
32+
- `assert`s:
33+
- Highly encouraged to describe assumptions (e.g. about a function's inputs) - as long as it isn't way too many of them.
34+
- Don't `assert` the type of arguments - types should be specfied in the annotations (these can be considered assertions as IDEs/type checkers should catch violations of these).
35+
- Don't `assert` if it massively deteriorates performance (e.g. don't check every element in the list if you aren't already iterating over it) - put a comment instead if the assumption is non-obvious.
36+
- Only use assert for internal assumptions. Don't use it as a shortcut to raising errors (e.g. don't use it to raise syntax errors in the source code).
37+
- Keyword arguments:
38+
- Pass an argument as keyword arg (e.g. `foo(bar=True)`) if it would otherwise be unclear what it is doing.
39+
- (e.g. `tformat(obj, 1, True, False)` is very unclear/not very readable. `tformat(obj, indent=1, verbose=True, append_lf=False)` is much better, makes sense even to people who haven't seen this codebase before).
40+
- Wildcard imports
41+
- Importing from outside this project: no (we don't know what extra stuff other projects put in their module namespace that might break our code).
42+
- Importing internally within the project:
43+
- Useful when you need *everything* from a module that has many *similar* classes
44+
- (e.g. importing all the nodes (`parser/cst/nodes.py`) in the CST generation code (`parser/cst/treegen.py`) is good).
45+
- The threshold for 'many' here is around 10-15 classes.
46+
- Otherwise (if the classes/functions are unrelated (e.g. in `utils.py`), or you don't need all/most of them, or the module has few classes), just list them out.
47+
- You must not `import *` from a module without a `__all__` (to avoid polluting your globals with their internal stuff, like the stuff they import from elsewhere). The one exception to this is re-exporting stuff (e.g. in `__init__.py`).
48+
- In general, be sensible, use your judgement as to what makes it more readable. If in doubt, just choose one, don't waste time on formtting that is easy to change later.
49+
- Good code with bad formatting is much better than bad code with good formatting (although good code with good formatting is preferable to both).

0 commit comments

Comments
 (0)