rianahmamy-de-toolkit 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rianahmamy_de_toolkit-0.1.0/PKG-INFO +304 -0
- rianahmamy_de_toolkit-0.1.0/README.md +288 -0
- rianahmamy_de_toolkit-0.1.0/pyproject.toml +22 -0
- rianahmamy_de_toolkit-0.1.0/src/rianahmamy_de_toolkit/__init__.py +0 -0
- rianahmamy_de_toolkit-0.1.0/src/rianahmamy_de_toolkit/main.py +13 -0
- rianahmamy_de_toolkit-0.1.0/src/rianahmamy_de_toolkit/vm.py +24 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rianahmamy-de-toolkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary:
|
|
5
|
+
Author: rianahmamy
|
|
6
|
+
Author-email: rianahmamy@hotmail.fr
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
13
|
+
Requires-Dist: click (>=8.5.0,<9.0.0)
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# 🎯 Goal
|
|
17
|
+
|
|
18
|
+
The goal of this challenge is to:
|
|
19
|
+
- Create a command line tool to start and stop your VM using python and shell scripts.
|
|
20
|
+
- Use `poetry` to create the python package and manage dependencies.
|
|
21
|
+
- Publish the package so that your package is available to install anywhere.
|
|
22
|
+
- Firstly to the public **PyPI** repository
|
|
23
|
+
- Secondly to a private package repository: **Gemfury**
|
|
24
|
+
- Optional: install the package locally if you have a local developer environment.
|
|
25
|
+
|
|
26
|
+
<br>
|
|
27
|
+
|
|
28
|
+
# 1️⃣ Lets start by creating a new poetry package!
|
|
29
|
+
|
|
30
|
+
We'll start with creating the package outside of the `data-engineering-challenges` folder so it is entirely separate from the challenges and can have its own github repository.
|
|
31
|
+
|
|
32
|
+
<details>
|
|
33
|
+
<summary markdown='span'>If you need a quick refresher on python packages</summary>
|
|
34
|
+
https://docs.python.org/3/tutorial/modules.html
|
|
35
|
+
</details>
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
poetry new ~/code/<user.github_nickname>/<user.lower_github_nickname>-de-toolkit && cd $_
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
☝️ Here we are using poetry to create a new package. Another useful terminal command is `$_`, which is the most recent parameter. In this case, the folder we've just created with `poetry new` lets us `cd` right into it.
|
|
43
|
+
|
|
44
|
+
Then, open this folder in your VS code Explorer, so that you see your package AND today's challenge in the same editor.
|
|
45
|
+
```bash
|
|
46
|
+
code -a . # open the folder in another workspace in the same VS code
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
At this point, we will have our `README.md`, a basic `pyproject.toml`, `<user.lower_github_nickname>_de_toolkit` package directory to populate, and a `tests/` folder if needed.
|
|
50
|
+
|
|
51
|
+
Your `pyproject.toml` should look like this:
|
|
52
|
+
|
|
53
|
+
```toml
|
|
54
|
+
[toml.poetry]
|
|
55
|
+
name = "<user.lower_github_nickname>-de-toolkit"
|
|
56
|
+
version = "0.1.0"
|
|
57
|
+
description = ""
|
|
58
|
+
authors = ["Your Name <example@email.com>"]
|
|
59
|
+
readme = "README.md"
|
|
60
|
+
packages = [{include = "<user.lower_github_nickname>_de_toolkit"}]
|
|
61
|
+
|
|
62
|
+
[tool.poetry.dependencies]
|
|
63
|
+
python = "^3.12"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
[build-system]
|
|
67
|
+
requires = ["poetry-core"]
|
|
68
|
+
build-backend = "poetry.core.masonry.api"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
❗ Make sure that your `pyproject.toml` includes the `packages = [{...}]` line. This tells poetry that you want to install the package `<user.lower_github_nickname>_de_toolkit` as a python package. We're building a command line tool so we definitely want our package to be installed!
|
|
72
|
+
|
|
73
|
+
<details>
|
|
74
|
+
<summary markdown='span'>💡 When wouldn't I want to install my own package?</summary>
|
|
75
|
+
If you were only using poetry purely as an external python package dependency manager and didn't want to install your python project locally. An example would be in a DBT or Airflow project, but we can save that idea for later!
|
|
76
|
+
</details>
|
|
77
|
+
|
|
78
|
+
Lets add [click](https://click.palletsprojects.com/en/8.1.x/) to our project to help develop our CLI:
|
|
79
|
+
```bash
|
|
80
|
+
poetry add click
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
❓ Now, **create** a main file to create our entry point and populate it with the code below:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
touch <user.lower_github_nickname>_de_toolkit/main.py
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import click
|
|
91
|
+
|
|
92
|
+
@click.group()
|
|
93
|
+
def cli():
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if __name__ == '__main__':
|
|
98
|
+
cli()
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Here, we are setting up the skeleton of a CLI using [group](https://click.palletsprojects.com/en/8.1.x/commands/) with the `@click.group()` decorator. This is where we will add other commands to flesh it out.
|
|
102
|
+
|
|
103
|
+
Now, if you run `poetry run python <user.lower_github_nickname>_de_toolkit/main.py`, you should see some empty documentation appear. One of the great features of click is how it uses doc strings in order to generate readable CLI feedback!
|
|
104
|
+
|
|
105
|
+
💡 **Let's alias** this long command. Add a line to our `pyproject.toml` to create alias `deng`:
|
|
106
|
+
|
|
107
|
+
```toml
|
|
108
|
+
[tool.poetry.scripts]
|
|
109
|
+
deng = '<user.lower_github_nickname>_de_toolkit.main:cli'
|
|
110
|
+
```
|
|
111
|
+
Now, we can run our CLI with `poetry run deng` instead 👌
|
|
112
|
+
|
|
113
|
+
<br>
|
|
114
|
+
|
|
115
|
+
# 2️⃣ Core logic
|
|
116
|
+
🎯 The goal of this package is to help you start and stop your VM at the start and end of every session in one line of code!
|
|
117
|
+
|
|
118
|
+
At the end, we'll want to use it as follows, from your local machine:
|
|
119
|
+
|
|
120
|
+
1️⃣ `deng start`: Start the vm (using `gcloud`)
|
|
121
|
+
2️⃣ `deng stop`: Stop the vm (using `gcloud`)
|
|
122
|
+
3️⃣ `deng connect` Connect directly to VScode inside your challenge folder!
|
|
123
|
+
|
|
124
|
+
❓ Create a new file `touch <user.lower_github_nickname>_de_toolkit/vm.py` to contain our vm commands. **Try to implement these** in the function shells below using the inbuilt [subprocess](https://docs.python.org/3/library/subprocess.html) module!
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
import click
|
|
128
|
+
import subprocess
|
|
129
|
+
|
|
130
|
+
@click.command()
|
|
131
|
+
def start():
|
|
132
|
+
"""Start your vm"""
|
|
133
|
+
# your code here
|
|
134
|
+
|
|
135
|
+
@click.command()
|
|
136
|
+
def stop():
|
|
137
|
+
"""Stop your vm"""
|
|
138
|
+
# your code here
|
|
139
|
+
|
|
140
|
+
@click.command()
|
|
141
|
+
def connect():
|
|
142
|
+
"""Connect to your vm in vscode inside your ~/code/<user.lower_github_nickname>/folder """
|
|
143
|
+
# your code here
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
<details>
|
|
147
|
+
<summary markdown='span'>💡 Hints: gcloud commands</summary>
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# start vm
|
|
151
|
+
gcloud compute instances start --zone=<vm zone> <vm name>
|
|
152
|
+
# stop vm
|
|
153
|
+
gcloud compute instances stop --zone=<vm zone> <vm name>
|
|
154
|
+
# code into vm
|
|
155
|
+
code --folder-uri vscode-remote://ssh-remote+username@<host as defined in local ~/.ssh/config>/<path inside vm>
|
|
156
|
+
# eg. code --folder-uri vscode-remote://ssh-remote+<user.lower_github_nickname>@de-vm.europe-west1-b.lw-bootcamp/home/<user.lower_github_nickname>/
|
|
157
|
+
```
|
|
158
|
+
</details>
|
|
159
|
+
|
|
160
|
+
❓ Add these three commands to our `cli` group using `cli.add_command(<your command>)` in main.py
|
|
161
|
+
|
|
162
|
+
Running `poetry run deng` should now list you these 3 options
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
$ poetry run deng
|
|
166
|
+
Usage: deng [OPTIONS] COMMAND [ARGS]...
|
|
167
|
+
|
|
168
|
+
Options:
|
|
169
|
+
--help Show this message and exit.
|
|
170
|
+
|
|
171
|
+
Commands:
|
|
172
|
+
connect Connect to your vm in vscode inside your...
|
|
173
|
+
start Start your vm
|
|
174
|
+
stop Stop your vm
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
<br>
|
|
178
|
+
|
|
179
|
+
# 3️⃣ Publishing your package
|
|
180
|
+
|
|
181
|
+
## 3.1. Publish to PyPI
|
|
182
|
+
<img src="https://wagon-public-datasets.s3.amazonaws.com/data-engineering/W0D1/pypi-logo.png" width=100>
|
|
183
|
+
|
|
184
|
+
🎯 Now we have our CLI. We want to publish it to make it available from any computer with python without needing the `.py` files.
|
|
185
|
+
|
|
186
|
+
The python package index, known as **PyPI**, is where packages that you can install directly with `pip` or in our case `poetry`, so that your package can become available on a new setup without having to re-clone the repository.
|
|
187
|
+
|
|
188
|
+
❓ Sign up to [PyPI](https://pypi.org/account/register/). Then create an api token from [account settings](https://pypi.org/manage/account/) and make sure it has the scope entire account so that it can generate new projects!
|
|
189
|
+
|
|
190
|
+
**Then create a `.env` at the root of your package** containing the following to store your token:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
PYPI_USERNAME=__token__
|
|
194
|
+
PYPI_TOKEN=<Your Token>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
This is the perfect place to use **direnv**. Let's create a .envrc to load our .env file:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
echo "dotenv" > .envrc
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Now, you can verify that your token is available as an environment variable with:
|
|
204
|
+
```bash
|
|
205
|
+
echo $PYPI_TOKEN
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
If it doesn't work, you may need to `direnv allow` once for all for this folder.
|
|
209
|
+
|
|
210
|
+
**Lets use poetry to quickly build and publish our package!**
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
poetry publish --build --username $PYPI_USERNAME --password $PYPI_TOKEN
|
|
215
|
+
```
|
|
216
|
+
(no worries, `.env` are not going to be part of the built archive, so won't be pushed to pypi by poetry)
|
|
217
|
+
|
|
218
|
+
Now go to [your package](https://pypi.org/project/<user.github_nickname>-de-toolkit/) directly on pypi. You should now be able to install this package from any machine. With pypi, the package is publicly available which is not an issue in our case but be careful in cases when you do not want to share the code with the rest of the world. The solution is using private package repositories instead!
|
|
219
|
+
|
|
220
|
+
👉 Go to this [page](https://pypi.org/manage/project/<user.github_nickname>-de-toolkit/settings/) to delete your package.
|
|
221
|
+
|
|
222
|
+
<br>
|
|
223
|
+
|
|
224
|
+
## 3.2. Publish to private repository instead with Gemfury
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
There are plenty of solutions for private repositories even hosting them [yourself](https://pypi.org/project/pypiserver/)! For ease, we will use [gemfury](https://gemfury.com/), you can login with Github and then go to this [page](https://manage.fury.io/manage/<user.github_nickname>/tokens/full) to get a full access token.
|
|
228
|
+
|
|
229
|
+
❓ Add the token to the `.env` file:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
GEMFURY_TOKEN=<your_token>
|
|
233
|
+
GEMFURY_PASSWORD=<your_gemfury_password>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Now to publish to your private repository you can follow this workflow!**
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# Configure poetry to read your Gemfury repositories:
|
|
240
|
+
poetry config repositories.fury https://pypi.fury.io/<user.lower_github_nickname>/
|
|
241
|
+
|
|
242
|
+
poetry config http-basic.fury $GEMFURY_TOKEN $GEMFURY_PASSWORD
|
|
243
|
+
|
|
244
|
+
# Push the package and any future build versions with:
|
|
245
|
+
poetry publish --build --repository fury
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Then, to use your packages from your private repo in another package, all you need to do is:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
poetry source add fury https://pypi.fury.io/<user.lower_github_nickname>/
|
|
252
|
+
poetry add --source fury <user.lower_github_nickname>_de_toolkit
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
You can see that this workflow is slightly more long-winded than publishing to PyPI, but it is something you only need to do at the start or end of projects and can add a lot of flexibility to how you distribute python packages around your team.
|
|
256
|
+
|
|
257
|
+
<br>
|
|
258
|
+
|
|
259
|
+
# 4️⃣ Optional: Install your private package on your LOCAL machine
|
|
260
|
+
|
|
261
|
+
>🚨 **ONLY DO THIS SECTION IF PYTHON IS INSTALLED ON YOUR LOCAL HOST MACHINE, OTHERWISE PLEASE SKIP.**
|
|
262
|
+
|
|
263
|
+
- Assumes you have GCP authentication on your **local** computer
|
|
264
|
+
- You do not need to have python locally installed on your machine for this bootcamp
|
|
265
|
+
- You do not have time to configure your local machine today
|
|
266
|
+
|
|
267
|
+
If you have python and pip installed locally, there are two options for installing your package locally:
|
|
268
|
+
|
|
269
|
+
**Option 1**: Create a `~/.pip/pip.conf` with these credentials below:
|
|
270
|
+
```bash
|
|
271
|
+
[global]
|
|
272
|
+
trusted-host = pypi.fury.io
|
|
273
|
+
extra-index-url = https://<YOUR_GEMFURY_TOKEN_HERE>@repo.fury.io/<user.lower_github_nickname>/
|
|
274
|
+
```
|
|
275
|
+
Pip will now use Gemfury instead of PyPI whenever the package name exists on the former:
|
|
276
|
+
```bash
|
|
277
|
+
pip install <user.github_nickname>-de-toolkit
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Option 2**: Just give the gemfury as a one-off, with pip or pipx:
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# Inside your local python virtualenv
|
|
284
|
+
pip install <user.lower_github_nickname>-de-toolkit --index-url https://<your-token>@repo.fury.io/<gemfury-username>/
|
|
285
|
+
# OR globally with pipx
|
|
286
|
+
pipx install <user.lower_github_nickname>-de-toolkit --pip-args='--extra-index-url https://<YOUR_GEMFURY_TOKEN_HERE>@repo.fury.io/<user.lower_github_nickname>/'
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
If install was successful, try to run the following commands on your local computer to test it out:
|
|
290
|
+
|
|
291
|
+
👉 Try to `deng connect` !
|
|
292
|
+
👉 `deng start` at the start of every session
|
|
293
|
+
👉 `deng stop` at the end of every session
|
|
294
|
+
|
|
295
|
+
<br>
|
|
296
|
+
|
|
297
|
+
# 🏁 Finishing up
|
|
298
|
+
|
|
299
|
+
Being able to create command line tools is a very useful skill to have! In this challenge we created a tool to start, stop, and connect to your VM. The idea is easily extensible to fleets of Virtual Machines and other GCP Services!
|
|
300
|
+
|
|
301
|
+
Another great use case is bulk editing of files. If you have ever had to manually edit multiple files by opening each one, making an change, saving, and then repeating - creating a tool that can do that for you will be a boost to your productivity! And a fun algorithm challenge as well 🚀
|
|
302
|
+
|
|
303
|
+
<br>
|
|
304
|
+
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# 🎯 Goal
|
|
2
|
+
|
|
3
|
+
The goal of this challenge is to:
|
|
4
|
+
- Create a command line tool to start and stop your VM using python and shell scripts.
|
|
5
|
+
- Use `poetry` to create the python package and manage dependencies.
|
|
6
|
+
- Publish the package so that your package is available to install anywhere.
|
|
7
|
+
- Firstly to the public **PyPI** repository
|
|
8
|
+
- Secondly to a private package repository: **Gemfury**
|
|
9
|
+
- Optional: install the package locally if you have a local developer environment.
|
|
10
|
+
|
|
11
|
+
<br>
|
|
12
|
+
|
|
13
|
+
# 1️⃣ Lets start by creating a new poetry package!
|
|
14
|
+
|
|
15
|
+
We'll start with creating the package outside of the `data-engineering-challenges` folder so it is entirely separate from the challenges and can have its own github repository.
|
|
16
|
+
|
|
17
|
+
<details>
|
|
18
|
+
<summary markdown='span'>If you need a quick refresher on python packages</summary>
|
|
19
|
+
https://docs.python.org/3/tutorial/modules.html
|
|
20
|
+
</details>
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
poetry new ~/code/<user.github_nickname>/<user.lower_github_nickname>-de-toolkit && cd $_
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
☝️ Here we are using poetry to create a new package. Another useful terminal command is `$_`, which is the most recent parameter. In this case, the folder we've just created with `poetry new` lets us `cd` right into it.
|
|
28
|
+
|
|
29
|
+
Then, open this folder in your VS code Explorer, so that you see your package AND today's challenge in the same editor.
|
|
30
|
+
```bash
|
|
31
|
+
code -a . # open the folder in another workspace in the same VS code
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
At this point, we will have our `README.md`, a basic `pyproject.toml`, `<user.lower_github_nickname>_de_toolkit` package directory to populate, and a `tests/` folder if needed.
|
|
35
|
+
|
|
36
|
+
Your `pyproject.toml` should look like this:
|
|
37
|
+
|
|
38
|
+
```toml
|
|
39
|
+
[toml.poetry]
|
|
40
|
+
name = "<user.lower_github_nickname>-de-toolkit"
|
|
41
|
+
version = "0.1.0"
|
|
42
|
+
description = ""
|
|
43
|
+
authors = ["Your Name <example@email.com>"]
|
|
44
|
+
readme = "README.md"
|
|
45
|
+
packages = [{include = "<user.lower_github_nickname>_de_toolkit"}]
|
|
46
|
+
|
|
47
|
+
[tool.poetry.dependencies]
|
|
48
|
+
python = "^3.12"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
[build-system]
|
|
52
|
+
requires = ["poetry-core"]
|
|
53
|
+
build-backend = "poetry.core.masonry.api"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
❗ Make sure that your `pyproject.toml` includes the `packages = [{...}]` line. This tells poetry that you want to install the package `<user.lower_github_nickname>_de_toolkit` as a python package. We're building a command line tool so we definitely want our package to be installed!
|
|
57
|
+
|
|
58
|
+
<details>
|
|
59
|
+
<summary markdown='span'>💡 When wouldn't I want to install my own package?</summary>
|
|
60
|
+
If you were only using poetry purely as an external python package dependency manager and didn't want to install your python project locally. An example would be in a DBT or Airflow project, but we can save that idea for later!
|
|
61
|
+
</details>
|
|
62
|
+
|
|
63
|
+
Lets add [click](https://click.palletsprojects.com/en/8.1.x/) to our project to help develop our CLI:
|
|
64
|
+
```bash
|
|
65
|
+
poetry add click
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
❓ Now, **create** a main file to create our entry point and populate it with the code below:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
touch <user.lower_github_nickname>_de_toolkit/main.py
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
import click
|
|
76
|
+
|
|
77
|
+
@click.group()
|
|
78
|
+
def cli():
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if __name__ == '__main__':
|
|
83
|
+
cli()
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Here, we are setting up the skeleton of a CLI using [group](https://click.palletsprojects.com/en/8.1.x/commands/) with the `@click.group()` decorator. This is where we will add other commands to flesh it out.
|
|
87
|
+
|
|
88
|
+
Now, if you run `poetry run python <user.lower_github_nickname>_de_toolkit/main.py`, you should see some empty documentation appear. One of the great features of click is how it uses doc strings in order to generate readable CLI feedback!
|
|
89
|
+
|
|
90
|
+
💡 **Let's alias** this long command. Add a line to our `pyproject.toml` to create alias `deng`:
|
|
91
|
+
|
|
92
|
+
```toml
|
|
93
|
+
[tool.poetry.scripts]
|
|
94
|
+
deng = '<user.lower_github_nickname>_de_toolkit.main:cli'
|
|
95
|
+
```
|
|
96
|
+
Now, we can run our CLI with `poetry run deng` instead 👌
|
|
97
|
+
|
|
98
|
+
<br>
|
|
99
|
+
|
|
100
|
+
# 2️⃣ Core logic
|
|
101
|
+
🎯 The goal of this package is to help you start and stop your VM at the start and end of every session in one line of code!
|
|
102
|
+
|
|
103
|
+
At the end, we'll want to use it as follows, from your local machine:
|
|
104
|
+
|
|
105
|
+
1️⃣ `deng start`: Start the vm (using `gcloud`)
|
|
106
|
+
2️⃣ `deng stop`: Stop the vm (using `gcloud`)
|
|
107
|
+
3️⃣ `deng connect` Connect directly to VScode inside your challenge folder!
|
|
108
|
+
|
|
109
|
+
❓ Create a new file `touch <user.lower_github_nickname>_de_toolkit/vm.py` to contain our vm commands. **Try to implement these** in the function shells below using the inbuilt [subprocess](https://docs.python.org/3/library/subprocess.html) module!
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
import click
|
|
113
|
+
import subprocess
|
|
114
|
+
|
|
115
|
+
@click.command()
|
|
116
|
+
def start():
|
|
117
|
+
"""Start your vm"""
|
|
118
|
+
# your code here
|
|
119
|
+
|
|
120
|
+
@click.command()
|
|
121
|
+
def stop():
|
|
122
|
+
"""Stop your vm"""
|
|
123
|
+
# your code here
|
|
124
|
+
|
|
125
|
+
@click.command()
|
|
126
|
+
def connect():
|
|
127
|
+
"""Connect to your vm in vscode inside your ~/code/<user.lower_github_nickname>/folder """
|
|
128
|
+
# your code here
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
<details>
|
|
132
|
+
<summary markdown='span'>💡 Hints: gcloud commands</summary>
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# start vm
|
|
136
|
+
gcloud compute instances start --zone=<vm zone> <vm name>
|
|
137
|
+
# stop vm
|
|
138
|
+
gcloud compute instances stop --zone=<vm zone> <vm name>
|
|
139
|
+
# code into vm
|
|
140
|
+
code --folder-uri vscode-remote://ssh-remote+username@<host as defined in local ~/.ssh/config>/<path inside vm>
|
|
141
|
+
# eg. code --folder-uri vscode-remote://ssh-remote+<user.lower_github_nickname>@de-vm.europe-west1-b.lw-bootcamp/home/<user.lower_github_nickname>/
|
|
142
|
+
```
|
|
143
|
+
</details>
|
|
144
|
+
|
|
145
|
+
❓ Add these three commands to our `cli` group using `cli.add_command(<your command>)` in main.py
|
|
146
|
+
|
|
147
|
+
Running `poetry run deng` should now list you these 3 options
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
$ poetry run deng
|
|
151
|
+
Usage: deng [OPTIONS] COMMAND [ARGS]...
|
|
152
|
+
|
|
153
|
+
Options:
|
|
154
|
+
--help Show this message and exit.
|
|
155
|
+
|
|
156
|
+
Commands:
|
|
157
|
+
connect Connect to your vm in vscode inside your...
|
|
158
|
+
start Start your vm
|
|
159
|
+
stop Stop your vm
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
<br>
|
|
163
|
+
|
|
164
|
+
# 3️⃣ Publishing your package
|
|
165
|
+
|
|
166
|
+
## 3.1. Publish to PyPI
|
|
167
|
+
<img src="https://wagon-public-datasets.s3.amazonaws.com/data-engineering/W0D1/pypi-logo.png" width=100>
|
|
168
|
+
|
|
169
|
+
🎯 Now we have our CLI. We want to publish it to make it available from any computer with python without needing the `.py` files.
|
|
170
|
+
|
|
171
|
+
The python package index, known as **PyPI**, is where packages that you can install directly with `pip` or in our case `poetry`, so that your package can become available on a new setup without having to re-clone the repository.
|
|
172
|
+
|
|
173
|
+
❓ Sign up to [PyPI](https://pypi.org/account/register/). Then create an api token from [account settings](https://pypi.org/manage/account/) and make sure it has the scope entire account so that it can generate new projects!
|
|
174
|
+
|
|
175
|
+
**Then create a `.env` at the root of your package** containing the following to store your token:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
PYPI_USERNAME=__token__
|
|
179
|
+
PYPI_TOKEN=<Your Token>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This is the perfect place to use **direnv**. Let's create a .envrc to load our .env file:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
echo "dotenv" > .envrc
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Now, you can verify that your token is available as an environment variable with:
|
|
189
|
+
```bash
|
|
190
|
+
echo $PYPI_TOKEN
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
If it doesn't work, you may need to `direnv allow` once for all for this folder.
|
|
194
|
+
|
|
195
|
+
**Lets use poetry to quickly build and publish our package!**
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
poetry publish --build --username $PYPI_USERNAME --password $PYPI_TOKEN
|
|
200
|
+
```
|
|
201
|
+
(no worries, `.env` are not going to be part of the built archive, so won't be pushed to pypi by poetry)
|
|
202
|
+
|
|
203
|
+
Now go to [your package](https://pypi.org/project/<user.github_nickname>-de-toolkit/) directly on pypi. You should now be able to install this package from any machine. With pypi, the package is publicly available which is not an issue in our case but be careful in cases when you do not want to share the code with the rest of the world. The solution is using private package repositories instead!
|
|
204
|
+
|
|
205
|
+
👉 Go to this [page](https://pypi.org/manage/project/<user.github_nickname>-de-toolkit/settings/) to delete your package.
|
|
206
|
+
|
|
207
|
+
<br>
|
|
208
|
+
|
|
209
|
+
## 3.2. Publish to private repository instead with Gemfury
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
There are plenty of solutions for private repositories even hosting them [yourself](https://pypi.org/project/pypiserver/)! For ease, we will use [gemfury](https://gemfury.com/), you can login with Github and then go to this [page](https://manage.fury.io/manage/<user.github_nickname>/tokens/full) to get a full access token.
|
|
213
|
+
|
|
214
|
+
❓ Add the token to the `.env` file:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
GEMFURY_TOKEN=<your_token>
|
|
218
|
+
GEMFURY_PASSWORD=<your_gemfury_password>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Now to publish to your private repository you can follow this workflow!**
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# Configure poetry to read your Gemfury repositories:
|
|
225
|
+
poetry config repositories.fury https://pypi.fury.io/<user.lower_github_nickname>/
|
|
226
|
+
|
|
227
|
+
poetry config http-basic.fury $GEMFURY_TOKEN $GEMFURY_PASSWORD
|
|
228
|
+
|
|
229
|
+
# Push the package and any future build versions with:
|
|
230
|
+
poetry publish --build --repository fury
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Then, to use your packages from your private repo in another package, all you need to do is:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
poetry source add fury https://pypi.fury.io/<user.lower_github_nickname>/
|
|
237
|
+
poetry add --source fury <user.lower_github_nickname>_de_toolkit
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
You can see that this workflow is slightly more long-winded than publishing to PyPI, but it is something you only need to do at the start or end of projects and can add a lot of flexibility to how you distribute python packages around your team.
|
|
241
|
+
|
|
242
|
+
<br>
|
|
243
|
+
|
|
244
|
+
# 4️⃣ Optional: Install your private package on your LOCAL machine
|
|
245
|
+
|
|
246
|
+
>🚨 **ONLY DO THIS SECTION IF PYTHON IS INSTALLED ON YOUR LOCAL HOST MACHINE, OTHERWISE PLEASE SKIP.**
|
|
247
|
+
|
|
248
|
+
- Assumes you have GCP authentication on your **local** computer
|
|
249
|
+
- You do not need to have python locally installed on your machine for this bootcamp
|
|
250
|
+
- You do not have time to configure your local machine today
|
|
251
|
+
|
|
252
|
+
If you have python and pip installed locally, there are two options for installing your package locally:
|
|
253
|
+
|
|
254
|
+
**Option 1**: Create a `~/.pip/pip.conf` with these credentials below:
|
|
255
|
+
```bash
|
|
256
|
+
[global]
|
|
257
|
+
trusted-host = pypi.fury.io
|
|
258
|
+
extra-index-url = https://<YOUR_GEMFURY_TOKEN_HERE>@repo.fury.io/<user.lower_github_nickname>/
|
|
259
|
+
```
|
|
260
|
+
Pip will now use Gemfury instead of PyPI whenever the package name exists on the former:
|
|
261
|
+
```bash
|
|
262
|
+
pip install <user.github_nickname>-de-toolkit
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Option 2**: Just give the gemfury as a one-off, with pip or pipx:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
# Inside your local python virtualenv
|
|
269
|
+
pip install <user.lower_github_nickname>-de-toolkit --index-url https://<your-token>@repo.fury.io/<gemfury-username>/
|
|
270
|
+
# OR globally with pipx
|
|
271
|
+
pipx install <user.lower_github_nickname>-de-toolkit --pip-args='--extra-index-url https://<YOUR_GEMFURY_TOKEN_HERE>@repo.fury.io/<user.lower_github_nickname>/'
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
If install was successful, try to run the following commands on your local computer to test it out:
|
|
275
|
+
|
|
276
|
+
👉 Try to `deng connect` !
|
|
277
|
+
👉 `deng start` at the start of every session
|
|
278
|
+
👉 `deng stop` at the end of every session
|
|
279
|
+
|
|
280
|
+
<br>
|
|
281
|
+
|
|
282
|
+
# 🏁 Finishing up
|
|
283
|
+
|
|
284
|
+
Being able to create command line tools is a very useful skill to have! In this challenge we created a tool to start, stop, and connect to your VM. The idea is easily extensible to fleets of Virtual Machines and other GCP Services!
|
|
285
|
+
|
|
286
|
+
Another great use case is bulk editing of files. If you have ever had to manually edit multiple files by opening each one, making an change, saving, and then repeating - creating a tool that can do that for you will be a boost to your productivity! And a fun algorithm challenge as well 🚀
|
|
287
|
+
|
|
288
|
+
<br>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "rianahmamy-de-toolkit"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = ""
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "rianahmamy",email = "rianahmamy@hotmail.fr"}
|
|
7
|
+
]
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"click (>=8.5.0,<9.0.0)"
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[tool.poetry]
|
|
15
|
+
packages = [{include = "rianahmamy_de_toolkit", from = "src"}]
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
19
|
+
build-backend = "poetry.core.masonry.api"
|
|
20
|
+
|
|
21
|
+
[tool.poetry.scripts]
|
|
22
|
+
deng = 'rianahmamy_de_toolkit.main:cli'
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import subprocess
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@click.command()
|
|
6
|
+
def start():
|
|
7
|
+
"""Start your vm"""
|
|
8
|
+
subprocess.run(["gcloud", "compute", "instances", "start", "data-eng-vm"])
|
|
9
|
+
|
|
10
|
+
@click.command()
|
|
11
|
+
def stop():
|
|
12
|
+
"""Stop your vm"""
|
|
13
|
+
subprocess.run(["gcloud", "compute", "instances", "stop", "data-eng-vm"])
|
|
14
|
+
|
|
15
|
+
@click.command()
|
|
16
|
+
def connect():
|
|
17
|
+
"""Connect to your vm in vscode inside your ~/code/rianahmamy/folder """
|
|
18
|
+
subprocess.run(
|
|
19
|
+
[
|
|
20
|
+
"code",
|
|
21
|
+
"--folder-uri",
|
|
22
|
+
"vscode-remote://ssh-remote+de_vm/home/rianahmamy/code/rianahmamy",
|
|
23
|
+
]
|
|
24
|
+
)
|