Skip to content

Extend TOC CLI script #131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ ignore =
E501
W503
E203
TRY301
per-file-ignores =
binder/ipython_config.py:E266
30 changes: 30 additions & 0 deletions .github/workflows/build-docker-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: Build Tutorial Container
on:
push:
branches:
- main
paths-ignore:
- '*.md'
- slides/**
- images/**
- .gitignore
workflow_dispatch:

jobs:
repo2docker:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: checkout files in repo
uses: actions/checkout@main

- name: update jupyter dependencies with repo2docker
uses: jupyterhub/repo2docker-action@master
with:
DOCKER_USERNAME: ${{ github.actor }}
DOCKER_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
DOCKER_REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
FORCE_REPO2DOCKER_VERSION: jupyter-repo2docker==2023.06.0
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,4 @@ dmypy.json
.DS_Store
*_files/
*.html
.idea/
10 changes: 10 additions & 0 deletions .mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[mypy]
; Do not warn about missing return statements
warn_no_return = False
; Show error messages in context
show_error_context = True
; Allow untyped definitions and calls
disallow_untyped_defs = False
disallow_untyped_calls = False
; Disable import errors
disable_error_code = import
12 changes: 6 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,21 @@ repos:
- id: isort
args: [--profile, black, --filter-files]
- repo: https://github.com/PyCQA/autoflake
rev: v2.2.0
rev: v2.2.1
hooks:
- id: autoflake
- repo: https://github.com/asottile/pyupgrade
rev: v3.9.0
rev: v3.14.0
hooks:
- id: pyupgrade
args: [--py38-plus]
- repo: https://github.com/psf/black
rev: 23.7.0
rev: 23.9.1
hooks:
- id: black
language_version: python3 # Should be a command that runs python3.6+
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
rev: 6.1.0
hooks:
- id: flake8
args: [--count, --show-source, --statistics]
Expand All @@ -45,7 +45,7 @@ repos:
- pyflakes
- tryceratops
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.4.1
rev: v1.5.1
hooks:
- id: mypy
additional_dependencies:
Expand All @@ -58,7 +58,7 @@ repos:
hooks:
- id: yamlfmt
- repo: https://github.com/asottile/setup-cfg-fmt
rev: v2.4.0
rev: v2.5.0
hooks:
- id: setup-cfg-fmt
- repo: https://github.com/kynan/nbstripout
Expand Down
61 changes: 55 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
# python-tutorial

[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/empa-scientific-it/python-tutorial.git/main?labpath=index.ipynb)

[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/empa-scientific-it/python-tutorial.git/main?labpath=index.ipynb) [![Build Docker container](https://github.com/empa-scientific-it/python-tutorial/actions/workflows/build-docker-image.yml/badge.svg)](https://github.com/empa-scientific-it/python-tutorial/actions/workflows/build-docker-image.yml)

## Run the tutorial on your computer

### 0. Prerequisites
You have two ways in which you can run the tutorial **locally**.

### 1. With a `conda` environment

#### 0. Prerequisites

To run the tutorial locally, you should first install [conda](https://docs.conda.io/en/latest/miniconda.html) (or [mamba](https://mamba.readthedocs.io/en/latest/installation.html)).

It is also suggested that you have a recent version of `git`. Check out [how to install `git`](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) on your operating system.

### 1. Download the material
#### 1. Download the material

Go to the directory on your machine where you want to download the material and clone the repository:

Expand All @@ -25,7 +28,7 @@ Alternatively, you can manually download a ZIP archive with the latest version o

Extract the archive in a directory of your choice.

### 2. Create a dedicated environment
#### 2. Create a dedicated environment

Enter the tutorial folder with

Expand All @@ -45,6 +48,7 @@ conda env create -f binder/environment.yml
> If you are on Windows and using Command Prompt or the PowerShell, please make sure to adjust the paths in the commands above accordingly.

Then activate the environment with

```console
conda activate python-tutorial
```
Expand All @@ -55,9 +59,54 @@ You can update the existing environment (that is, downloading the latest version
conda env update -f binder/environment.yml
```

### 3. Launch the tutorial via Jupyter
#### 3. Launch the tutorial via Jupyter

Finally, launch JupyterLab with

```console
jupyter lab
```

To update the existing environment, run

```console
conda env update -f environment.yml
```

### 2. With Docker

> **Note**
>
> The following instructions are for Windows. With minor changes, the steps work on macOS or Linux as well.

1. Install Docker Desktop: First, you need to install Docker Desktop on your Windows machine. You can download it from the official Docker website: https://www.docker.com/products/docker-desktop.

2. Create a folder: Open File Explorer and create a new folder where you want to save the tutorial's materials. For example, you could create a folder called "python-tutorial" on your Desktop.

3. Open PowerShell: Once Docker Desktop is installed, open PowerShell on your Windows machine. You can do this by pressing the "Windows" key and typing "PowerShell" in the search bar.

4. Pull the Docker image: In PowerShell, run the following command to pull the "empascientificit/python-tutorial" Docker image:

```console
docker pull ghcr.io/empa-scientific-it/python-tutorial:latest
```

5. Run the Docker container: Once the image is downloaded, run the following command to start a Docker container from the image:

```console
docker run -p 8888:8888 --name python_tutorial -v /path/to/python-tutorial:/home/jovyan/work ghcr.io/empa-scientific-it/python-tutorial:latest jupyter lab --ip 0.0.0.0 --no-browser
```

Replace `/path/to/python-tutorial` with the path to the folder you created in step 2, for example `C:/Users/yourusername/Desktop/python-tutorial`.

> **Note**
>
> The above command will **mirror** the content of your local folder (e.g., `C:/Users/yourusername/Desktop/python-tutorial`) to the `work/` folder **inside the container**. In this way, every file or folder you copy or create into `work/` will be saved on your machine, and will remain there **even if you stop Docker**.

6. Access the Jupyter Notebook: Open a web browser and navigate to `http://localhost:8888/lab`. You should see the Jupyter Notebook interface. Enter the token provided in the PowerShell console to access the notebook. Alternatively, you can directly click on the link that appears in the PowerShell after the container has started.

You can now use the Jupyter in the Docker container to run the python-tutorial. When you're done, you can stop the container by pressing `Ctrl+C` in the PowerShell console.

> **Note**
>
> If you want to restart the container, you can simply run the command `docker container start python_tutorial`.
2 changes: 1 addition & 1 deletion binder/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: python-tutorial
channels:
- conda-forge
dependencies:
- python
- python=3.10
- pip
- pip:
- numpy
Expand Down
2 changes: 1 addition & 1 deletion binder/ipython_config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Configuration file for ipython.

c = get_config() # noqa
c = get_config() # noqa # type: ignore

# ------------------------------------------------------------------------------
# InteractiveShellApp(Configurable) configuration
Expand Down
7 changes: 1 addition & 6 deletions magic_example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,8 @@
"%%ipytest\n",
"# or %%ipytest test_module_name\n",
"\n",
"len('a')\n",
"def solution_power2(x: int) -> int:\n",
" print('hi')\n",
" len('b')\n",
" print(len('bb'))\n",
" return x ** 2\n",
"len('aaa')"
" return x * 2"
]
},
{
Expand Down
32 changes: 14 additions & 18 deletions tutorial/tests/test_control_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def is_prime(num: int) -> bool:
return True


def reference_solution_find_factors(num: int) -> List[int]:
def reference_find_factors(num: int) -> List[int]:
"""Dumb way to find the factors of an integer"""
if is_prime(num):
return [1, num]
Expand All @@ -149,7 +149,7 @@ def reference_solution_find_factors(num: int) -> List[int]:

@pytest.mark.parametrize("num", [350, 487, 965, 816, 598, 443, 13, 17, 211])
def test_find_factors(num: int, function_to_test) -> None:
assert function_to_test(num) == reference_solution_find_factors(num)
assert function_to_test(num) == reference_find_factors(num)


#
Expand All @@ -162,7 +162,7 @@ def test_find_factors(num: int, function_to_test) -> None:
)


def reference_solution_find_pair(nums: List[int]) -> int:
def reference_find_pair(nums: List[int]) -> int:
"""Reference solution (part 1)"""
complements = {}
for num in nums:
Expand All @@ -173,10 +173,10 @@ def reference_solution_find_pair(nums: List[int]) -> int:

@pytest.mark.parametrize("nums", [nums_1, nums_2])
def test_find_pair(nums: List[int], function_to_test) -> None:
assert function_to_test(nums) == reference_solution_find_pair(nums)
assert function_to_test(nums) == reference_find_pair(nums)


def reference_solution_find_triplet_slow(nums: List[int]) -> int:
def reference_find_triplet_slow(nums: List[int]) -> int:
"""Reference solution (part 2), O(n^3)"""
n = len(nums)
for i in range(n - 2):
Expand All @@ -186,7 +186,7 @@ def reference_solution_find_triplet_slow(nums: List[int]) -> int:
return nums[i] * nums_2[j] * nums[k]


def reference_solution_find_triplet(nums: List[int]) -> int:
def reference_find_triplet(nums: List[int]) -> int:
"""Reference solution (part 2), O(n^2)"""
n = len(nums)
for i in range(n - 1):
Expand All @@ -201,15 +201,15 @@ def reference_solution_find_triplet(nums: List[int]) -> int:

@pytest.mark.parametrize("nums", [nums_1, nums_2])
def test_find_triplet(nums: List[int], function_to_test) -> None:
assert function_to_test(nums) == reference_solution_find_triplet(nums)
assert function_to_test(nums) == reference_find_triplet(nums)


#
# Exercise 3: Cats with hats
#


def reference_solution_cats_with_hats() -> int:
def reference_cats_with_hats() -> int:
"""Solution with dictionaries"""
cats = {i: False for i in range(1, 101)}

Expand All @@ -222,7 +222,7 @@ def reference_solution_cats_with_hats() -> int:


def test_cats_with_hats(function_to_test) -> None:
assert function_to_test() == reference_solution_cats_with_hats()
assert function_to_test() == reference_cats_with_hats()


#
Expand All @@ -241,9 +241,7 @@ def parse_data(filename: str) -> List[List[int]]:
trees_1, trees_2 = (parse_data(f"trees_{num}.txt") for num in (1, 2))


def reference_solution_toboggan_p1(
trees_map: List[List[int]], right: int, down: int
) -> int:
def reference_toboggan_p1(trees_map: List[List[int]], right: int, down: int) -> int:
"""Reference solution (part 1)"""
start, trees, depth, width = [0, 0], 0, len(trees_map), len(trees_map[0])
while start[0] < depth:
Expand All @@ -262,18 +260,16 @@ def reference_solution_toboggan_p1(
def test_toboggan_p1(
trees_map: List[List[int]], right: int, down: int, function_to_test
) -> None:
assert function_to_test(trees_map, right, down) == reference_solution_toboggan_p1(
assert function_to_test(trees_map, right, down) == reference_toboggan_p1(
trees_map, right, down
)


def reference_solution_toboggan_p2(
trees_map: List[List[int]], slopes: Tuple[Tuple[int]]
) -> int:
def reference_toboggan_p2(trees_map: List[List[int]], slopes: Tuple[Tuple[int]]) -> int:
"""Reference solution (part 2)"""
total = 1
for right, down in slopes:
total *= reference_solution_toboggan_p1(trees_map, right, down)
total *= reference_toboggan_p1(trees_map, right, down)
return total


Expand All @@ -293,6 +289,6 @@ def reference_solution_toboggan_p2(
def test_toboggan_p2(
trees_map: List[List[int]], slopes: Tuple[Tuple[int]], function_to_test
) -> None:
assert function_to_test(trees_map, slopes) == reference_solution_toboggan_p2(
assert function_to_test(trees_map, slopes) == reference_toboggan_p2(
trees_map, slopes
)
Loading