Skip to content
This repository was archived by the owner on Apr 25, 2023. It is now read-only.

Commit 4de34fd

Browse files
committed
First part of second session
1 parent 4e0ec81 commit 4de34fd

File tree

1 file changed

+183
-0
lines changed

1 file changed

+183
-0
lines changed

sessions/02_layout-unit-tests.ipynb

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {
6+
"slideshow": {
7+
"slide_type": "slide"
8+
}
9+
},
10+
"source": [
11+
"![IE](../img/ie.png)\n",
12+
"\n",
13+
"# Sessions 2 & 3: Project layout and unit tests\n",
14+
"\n",
15+
"### Juan Luis Cano Rodríguez <jcano@faculty.ie.edu> - Master in Business Analytics and Big Data (2019-04-03)"
16+
]
17+
},
18+
{
19+
"cell_type": "markdown",
20+
"metadata": {},
21+
"source": [
22+
"## Triangular workflows in git\n",
23+
"\n",
24+
"When collaborating with a project hosted online on GitHub or GitLab, the most common setup is having a central repository, one remote fork per user, and local clones/checkouts:\n",
25+
"\n",
26+
"![Triangular workflow](https://github.blog/wp-content/uploads/2015/07/5dcdcae4-354a-11e5-9f82-915914fad4f7.png?resize=2000%2C951)\n",
27+
"\n",
28+
"(Source: https://github.blog/2015-07-29-git-2-5-including-multiple-worktrees-and-triangular-workflows/)\n",
29+
"\n",
30+
"Following this workflow requires discipline and sticking to a subset of actions and git commands to avoid common mistakes. This website contains all you need to know to setup your triangular workflow and we don't need to reproduce it here:\n",
31+
"\n",
32+
"https://www.asmeurer.com/git-workflow/\n",
33+
"\n",
34+
"*Notice* the different naming conventions between this website and the first image:\n",
35+
"\n",
36+
"1. **Convention 1**: upstream/origin/local\n",
37+
"2. **Convention 2**: origin/&#x3C;username&#x3E;/local\n",
38+
"\n",
39+
"We will be consistent with the Aaron Meurer guide and therefore use Convention 2 all the time.\n",
40+
"\n",
41+
"### ⚠ After creating a pull request ⚠\n",
42+
"\n",
43+
"After your pull request has been merged to `master`, your local `master` and `<username>/master` will be outdated with respect to `origin/master`. On the other hand, **you should avoid working on this branch anymore in the future**: remember branches should be ephemeral and short-lived.\n",
44+
"\n",
45+
"To put yourself in a clean state again, you have to:\n",
46+
"\n",
47+
"1. Click \"remove branch\" in the pull request (don't click \"remove fork\"!)\n",
48+
"2. `git checkout master` to go back to `master`\n",
49+
"3. `git fetch origin` (**never, ever use `git pull` unless you know exactly what you're doing**)\n",
50+
"4. `git merge --ff-only origin master` (this will update your local `master` with `origin/master`, and fail if you accidentally made any commit in `master`)\n",
51+
"5. `git fetch -p <username>` :star2: this will acknowledge the removal of the branch :star2:\n",
52+
"6. `git push <username> master` (this will update your fork with respect to `origin`)\n",
53+
"7. `git checkout -b new-branch` to start working in the new feature!\n",
54+
"\n",
55+
"This process **has to be repeated after every pull request**.\n",
56+
"\n",
57+
"🌈 "
58+
]
59+
},
60+
{
61+
"cell_type": "markdown",
62+
"metadata": {},
63+
"source": [
64+
"## Project layout\n",
65+
"\n",
66+
"Most data science projects will start with a bunch of notebooks. However, at some point we will want to reuse code between them, and eventually put our models in production without the need to use the notebooks themselves ([unless you are Netflix](https://medium.com/netflix-techblog/notebook-innovation-591ee3221233)). Choosing a good project layout is extremely important to organize the code, avoid common pitfalls and be predictable (i.e. imitate the rest of the ecosystem to minimize surprise). On the other hand, there is lots (**lots**) of outdated, bad or wrong advice on the Internet about this topic, so here we will present The Truth™.\n",
67+
"\n",
68+
"### References\n",
69+
"\n",
70+
"* Packaging a Python library https://blog.ionelmc.ro/2014/05/25/python-packaging/\n",
71+
"* Less known packaging features and tricks https://blog.ionelmc.ro/presentations/packaging/\n",
72+
"* setuptools documentation https://setuptools.readthedocs.io/en/stable/setuptools.html"
73+
]
74+
},
75+
{
76+
"cell_type": "markdown",
77+
"metadata": {},
78+
"source": [
79+
"### The `src` layout\n",
80+
"\n",
81+
"```\n",
82+
"├─ src\n",
83+
"│ └─ packagename\n",
84+
"│ ├─ __init__.py\n",
85+
"│ └─ ...\n",
86+
"├─ tests\n",
87+
"│ └─ ...\n",
88+
"├─ README.txt\n",
89+
"├─ setup.py\n",
90+
"└─ setup.cfg\n",
91+
"```\n",
92+
"\n",
93+
"* The `src/packagename` contains the source code of the library.\n",
94+
" - The `packagename` is what users type after `import` in a Python script, and therefore should not contain special characters.\n",
95+
" - It should contain a `__init__.py` that can be empty (more on that below).\n",
96+
" - The `src` segment prevents you from *shooting yourself in the foot*, because it's common to do `import packagename` when you are developing, and this will import the code from the directory, not from your `sys.path`. Always include it.\n",
97+
"\n",
98+
"* The `tests` directory contains the tests. It **must not** contain any `__init__.py` because it's not meant to be imported as a package. In very specific cases it's included inside `src/packagename`.\n",
99+
"\n",
100+
"* Every project contains a `README.txt` that at least explains what the project is.\n",
101+
"\n",
102+
"* `setup.py` can be an extremely simple file containing only this:\n",
103+
"\n",
104+
"```\n",
105+
"from setuptools import setup\n",
106+
"\n",
107+
"setup()\n",
108+
"```\n",
109+
"\n",
110+
"(This requires `setuptools > 30.3.0`, released 8 Dec 2016)\n",
111+
"\n",
112+
"* `setup.cfg` contains the metadata of the project. The absolutely required fields are `name`, `version`, and `packages`, therefore you will need something like this:\n",
113+
"\n",
114+
"```\n",
115+
"[metadata]\n",
116+
"name = my_package\n",
117+
"version = 0.1.0\n",
118+
"\n",
119+
"# Magic! Don't touch below this line\n",
120+
"[options]\n",
121+
"package_dir=\n",
122+
" =src\n",
123+
"packages=find:\n",
124+
"\n",
125+
"[options.packages.find]\n",
126+
"where=src\n",
127+
"```\n",
128+
"\n",
129+
"The `name` is what users will have to type after `pip install` and therefore can contain hyphens. **Do not confuse this** with what users have to type on `import` (see above).\n",
130+
"\n",
131+
"With this layout, **you can `pip install` your code** in your Python environment:\n",
132+
"\n",
133+
"```\n",
134+
"$ pip install --editable .\n",
135+
"$ python\n",
136+
">>> import packagename\n",
137+
">>>\n",
138+
"```\n",
139+
"\n",
140+
"This is an alternative to modifying the `PYTHONPATH` environment variable (see first session)."
141+
]
142+
},
143+
{
144+
"cell_type": "markdown",
145+
"metadata": {},
146+
"source": [
147+
"### Exercise\n",
148+
"\n",
149+
"1. Create a directory called `test-package`\n",
150+
"2. `git init` inside it\n",
151+
"3. Create a basic `src` layout in it, with `name = test-package` and the source in `src/test_package`\n",
152+
"4. Create a `src/test_package/__init__.py` with a `print(\"Hello, world!\")`\n",
153+
"5. Install it in editable mode using `pip` and test that `>>> import test_package` prints `Hello, world!`\n",
154+
"6. Include a `README.txt` and an appropriate `.gitignore` from http://gitignore.io/\n",
155+
"7. Commit the changes\n",
156+
"8. Create a new GitHub project and push the repository there\n",
157+
"\n",
158+
"🎉"
159+
]
160+
}
161+
],
162+
"metadata": {
163+
"kernelspec": {
164+
"display_name": "Python 3",
165+
"language": "python",
166+
"name": "python3"
167+
},
168+
"language_info": {
169+
"codemirror_mode": {
170+
"name": "ipython",
171+
"version": 3
172+
},
173+
"file_extension": ".py",
174+
"mimetype": "text/x-python",
175+
"name": "python",
176+
"nbconvert_exporter": "python",
177+
"pygments_lexer": "ipython3",
178+
"version": "3.7.1"
179+
}
180+
},
181+
"nbformat": 4,
182+
"nbformat_minor": 2
183+
}

0 commit comments

Comments
 (0)