From 3d900a4737680b692691e1b151db817f0aa0bf19 Mon Sep 17 00:00:00 2001
From: Thibaut de Saivre <thibaut.de-saivre@polytechnique.edu>
Date: Thu, 12 Oct 2023 19:06:27 +0200
Subject: [PATCH] add python template

---
 .vscode/settings.json          |   8 +-
 README.md                      |   7 ++
 python/.gitignore              |   2 +
 python/.vscode/extensions.json |   8 ++
 python/.vscode/settings.json   |  16 ++++
 python/README.md               | 133 +++++++++++++++++++++++++++++++++
 python/lib/lib.py              |   2 +
 python/main.py                 |  23 ++++++
 python/pyproject.toml          |  66 ++++++++++++++++
 python/requirements.txt        |   1 +
 10 files changed, 265 insertions(+), 1 deletion(-)
 create mode 100644 python/.gitignore
 create mode 100644 python/.vscode/extensions.json
 create mode 100644 python/.vscode/settings.json
 create mode 100644 python/README.md
 create mode 100644 python/lib/lib.py
 create mode 100644 python/main.py
 create mode 100644 python/pyproject.toml
 create mode 100644 python/requirements.txt

diff --git a/.vscode/settings.json b/.vscode/settings.json
index ce19b10..4d8407d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -65,7 +65,13 @@
     "editor.defaultFormatter": "ms-python.black-formatter", // Use Black formatter for python
     "editor.formatOnType": true
   },
-  "python.analysis.typeCheckingMode": "basic", // or "strict" : use stricter python type checking
+  "python.analysis.typeCheckingMode": "strict", // or "strict" : use stricter python type checking
+
+  // Add explicit hints overlays for arguments, return types, variable types...
+  "python.analysis.inlayHints.functionReturnTypes": true,
+  "python.analysis.inlayHints.variableTypes": true,
+  "python.analysis.inlayHints.pytestParameters": true,
+  "python.analysis.inlayHints.callArgumentNames": "all",
 
   // Python Jupyter Notebooks
   "jupyter.interactiveWindow.textEditor.executeSelection": true,
diff --git a/README.md b/README.md
index 45122be..8573d78 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
 # VSCode Config
 
 Base VSCode config for a better dev experience.
+Base Project configs for common languages.
 
 ## Recommended Extensions
 
@@ -33,3 +34,9 @@ Good default settings for VSCode.
 
 - Configure **formatters** for every language you use.
 - Additional language configs (better linting, stricter python type checking...).
+
+## Default Project configs & Workspace settings
+
+- give example docker configs & gitlab-ci configs (pb : ça va être chiant si on doit faire de la ci sécurisée...)
+- workspace settings
+- readme avec requirements.txt, faire un venv...
diff --git a/python/.gitignore b/python/.gitignore
new file mode 100644
index 0000000..01d7f95
--- /dev/null
+++ b/python/.gitignore
@@ -0,0 +1,2 @@
+__pycache__
+venv
\ No newline at end of file
diff --git a/python/.vscode/extensions.json b/python/.vscode/extensions.json
new file mode 100644
index 0000000..2c62afd
--- /dev/null
+++ b/python/.vscode/extensions.json
@@ -0,0 +1,8 @@
+{
+  "recommendations": [
+    "ms-python.python", // Python language support
+    "ms-python.vscode-pylance", // Python language server
+    "ms-python.black-formatter", // FORMATTER (black, one of the best python formatters)
+    "charliermarsh.ruff" // LINTER (ruff, blazingly fast python linter, written in rust)
+  ]
+}
diff --git a/python/.vscode/settings.json b/python/.vscode/settings.json
new file mode 100644
index 0000000..e57ae21
--- /dev/null
+++ b/python/.vscode/settings.json
@@ -0,0 +1,16 @@
+{
+  // Generic settings :
+  "editor.formatOnSave": true, // Format files on save
+  "formatFiles.runOrganizeImports": true, // Sort imports when formatting
+  "editor.codeActionsOnSave": {
+    // Organize imports on save
+    "source.organizeImports": true
+  },
+
+  // Python
+  "[python]": {
+    "editor.defaultFormatter": "ms-python.black-formatter", // Use Black formatter for python
+    "editor.formatOnType": true
+  },
+  "python.analysis.typeCheckingMode": "strict" // or "strict" : use stricter python type checking
+}
diff --git a/python/README.md b/python/README.md
new file mode 100644
index 0000000..705e604
--- /dev/null
+++ b/python/README.md
@@ -0,0 +1,133 @@
+# Template Python Project
+
+[![Python Version](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-311/)
+[![Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
+[![Ruff](https://img.shields.io/badge/linter-ruff-1a53f0.svg)](https://beta.ruff.rs/docs/)
+
+## VSCode Project Settings
+
+In order to ensure that everyone uses the same linting and formatting settings,
+we duplicate the relevant settings in [`.vscode/settings.json`](.vscode/settings.json).
+
+Relevant settings with python :
+
+- format on save
+- strict type checking
+- format using **Black**
+
+## Formatter - Black
+
+[Black](https://github.com/psf/black) is a popular python formatter which is strict and opinionated.
+Using a formatter ensures that the code you and your team write is consistent.
+You should always use a formatter.
+
+Additional configuration for the formatter can be added to the [`pyproject.toml`](./pyproject.toml) file,
+although the default settings are already pretty good.
+
+## Linter - Ruff
+
+[Ruff](https://github.com/astral-sh/ruff) is a good python linter, in the sense that it is strict enough, and coded in rust (blazingly fast).
+It is the fastest python linter available, which is nice when you want reactive linting during typing.
+Using a linter will help you write cleaner code, and avoid common mistakes.
+You should always use a linter.
+
+Additional configuration for the formatter can be added to the [`pyproject.toml`](./pyproject.toml) file,
+although the default settings are already pretty good.
+
+## Environment and reproducibility
+
+In order to make it easier for other developers to contribute to your project,
+and to enable deploying your application easily, you must indicate which python version and dependencies you are using.
+
+You typically indicate the python version in your [`pyproject.toml`](./pyproject.toml) or (`README.md`)(./README.md) file.
+
+### Create a virtual environment
+
+If you do not use `conda`, you may create a virtual environment. Virtual environments are often contained in a `venv` folder.
+Virtual environment enable you to have separate python versions and dependencies for each project.
+
+```bash
+python --version # Ensure that your current python version is the one you want to use. Use `pyenv` to change it if needed (see wikibr).
+python -m venv venv # Creates a virtual environment in the `venv` folder.
+
+# LINUX / MACOS : activate the virtual environment
+source venv/bin/activate
+
+# WINDOWS : activate the virtual environment
+venv\Scripts\activate
+```
+
+You must always activate your virtual environment before running your code or installing dependencies (else it will use your global python interpreter).
+
+### Install and Freeze dependencies
+
+Python depdendencies are typically indicated in a [`requirements.txt`](./requirements.txt) file.
+
+Install dependencies :
+
+```bash
+pip install --upgrade pip # Update pip (python package manager)
+pip install -r requirements.txt # Install dependencies read from the requirements file
+```
+
+Freeze dependencies :
+You can write your dependencies by hand in the `requirements.txt` file, or you can "freeze" your current environment.
+
+```bash
+pip freeze > requirements.txt # Write the current dependencies to the requirements file
+```
+
+### Git
+
+Some common gitignores for a python project :
+
+- `__pycache__` : python cache, generated at runtime.
+- `venv` : virtual environment folder.
+
+## Python Clean Code
+
+Some often-overlooked python clean code rules :
+
+### Docstrings
+
+Always write docstrings in order to describe the purpose of your functions and classes.
+
+```python
+def function():
+    """This function does something."""
+    pass
+```
+
+### Type hinting
+
+When you can (always), use type hints to indicate the types of the parameters of your functions, their return types, etc...
+You sometimes need to use the `typing` module to indicate more complex types.
+
+```python
+from typing import List
+def add_to_list(my_list: List[int], element: int) -> List[int]:
+    my_list.append(element)
+    return my_list
+```
+
+Since python 3.10, you can use the `|` operator to indicate that a parameter can be of multiple types, and use `list` and `dict` directly as type hints.
+
+```python
+def add_to_list(my_list: list[int | float], element: int | float) -> list[int | float]:
+    my_list.append(element)
+    return my_list
+```
+
+### Use modules
+
+When your code gets big, you should split it into multiple files.
+
+Use the following test in order to run module-specific code only when you run your module directly via `python module.py`, and not when you import it from another file.
+
+```python
+def module_function():
+    pass
+
+if __name__ == "__main__":
+    module_function()
+```
diff --git a/python/lib/lib.py b/python/lib/lib.py
new file mode 100644
index 0000000..ca1a381
--- /dev/null
+++ b/python/lib/lib.py
@@ -0,0 +1,2 @@
+def dependency_function(message: str) -> None:
+    print(f"Printing a message from the dependency: {message}")
diff --git a/python/main.py b/python/main.py
new file mode 100644
index 0000000..2ed7c8a
--- /dev/null
+++ b/python/main.py
@@ -0,0 +1,23 @@
+from lib.lib import dependency_function
+
+
+def test(a: int, b: int) -> bool:
+    """Tests the equality of two integers"""
+    return a == b
+
+
+def wrong_input_type(test: int):
+    """If you pass anything other than an integer to this function, Pylance will warn you !"""
+    return test
+
+
+if __name__ == "__main__":
+    a = 1
+    b = 2
+
+    print(test(a, b))
+
+    # Pylance will warn about wrong types thanks to "typeCheckingMode": "strict"
+    wrong_input_type("test")
+
+    dependency_function("message")
diff --git a/python/pyproject.toml b/python/pyproject.toml
new file mode 100644
index 0000000..9f004e6
--- /dev/null
+++ b/python/pyproject.toml
@@ -0,0 +1,66 @@
+###########################################################################################
+# EXAMPLE RUFF CONFIG (https://github.com/astral-sh/ruff/blob/main/docs/configuration.md) #
+###########################################################################################
+
+[tool.ruff]
+# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`)  codes by default.
+# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
+# McCabe complexity (`C901`) by default.
+select = ["E4", "E7", "E9", "F"]
+ignore = []
+
+# Allow fix for all enabled rules (when `--fix`) is provided.
+fixable = ["ALL"]
+unfixable = []
+
+# Exclude a variety of commonly ignored directories.
+exclude = [
+    ".bzr",
+    ".direnv",
+    ".eggs",
+    ".git",
+    ".git-rewrite",
+    ".hg",
+    ".mypy_cache",
+    ".nox",
+    ".pants.d",
+    ".pytype",
+    ".ruff_cache",
+    ".svn",
+    ".tox",
+    ".venv",
+    "__pypackages__",
+    "_build",
+    "buck-out",
+    "build",
+    "dist",
+    "node_modules",
+    "venv",
+]
+per-file-ignores = {}
+
+# Same as Black.
+line-length = 88
+
+# Allow unused variables when underscore-prefixed.
+dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
+
+# Assume Python 3.8
+target-version = "py38"
+
+################################################################################
+# EXAMPLE BLACK CONFIG (https://github.com/psf/black/blob/main/pyproject.toml) #
+################################################################################
+
+[tool.black]
+
+line-length = 88
+target-version = ['py37', 'py38']
+include = '\.pyi?$'
+extend-exclude = '''
+/(
+  # The following are specific to Black, you probably don't want those.
+  tests/data
+  | profiling
+)/
+'''
diff --git a/python/requirements.txt b/python/requirements.txt
new file mode 100644
index 0000000..296d654
--- /dev/null
+++ b/python/requirements.txt
@@ -0,0 +1 @@
+numpy
\ No newline at end of file
-- 
GitLab