From 3248e48d5041abbc8d9002a2033cabefad8bcaed Mon Sep 17 00:00:00 2001 From: makayabou Date: Thu, 6 Aug 2020 03:06:40 +0200 Subject: [PATCH] modify 1st project and rest --- docs/cours/python/1stproject.md | 48 +++--- docs/cours/python/rest.md | 269 +++++++++++++++++++++++++++++--- 2 files changed, 276 insertions(+), 41 deletions(-) diff --git a/docs/cours/python/1stproject.md b/docs/cours/python/1stproject.md index a77a834a..0df0ba0f 100644 --- a/docs/cours/python/1stproject.md +++ b/docs/cours/python/1stproject.md @@ -3,16 +3,16 @@ ## Création du projet ??? important "Note importante pour les étudiants" - Ne créez pas un nouveau dossier, - 1. clonez plutôt le projet d'évaluation - 2. basculez sur la branche start - 3. Créez une nouvelle branche nommée `start-votre-id-gitlab` - ``` - git clone https://gitlab.com/devopsp1/python-webscrap.git` - cd python-webscrap - git checkout start - git checkout -b start-mon-id-gitlab - ``` + Ne créez pas un nouveau dossier, + 1. clonez plutôt le projet d'évaluation + 2. basculez sur la branche start + 3. Créez une nouvelle branche nommée `start-votre-id-gitlab` + ``` + git clone https://gitlab.com/devopsp1/python-webscrap.git` + cd python-webscrap + git checkout start + git checkout -b start-mon-id-gitlab + ``` On démarre un projet simplement en créant un dossier, dans lequel (par convention), on crée le fichier `main.py` @@ -26,23 +26,27 @@ On met un **shebang** en 1ère ligne pour indiquer la version de python. Dans ce script on déclare deux variables, qu'on nomme `base_url`et `endpoint1`, auxquelles on donne une valeur. -``` -#!/usr/bin/env python3 +!!! note "main.py" + ``` + #!/usr/bin/env python3 -base_url = "https://gitlab.com/api/v4" -print(base_url) -endpoint1 = base_url + "/groups" -print(endpoint1) -``` + api_url = "https://gitlab.com/api/v4" + print(api_url) + dataset = "/groups" + print(dataset) + endpoint = api_url + dataset + print(endpoint) + ``` -On peut simplement exécuter ce script avec `python poi.py` ou l'exécuter en mode **interactif** (-i) pour continuer à manipuler les variables et les fonctions du programme: +On peut simplement exécuter ce script avec `python main.py` ou l'exécuter en mode **interactif** (-i) pour continuer à manipuler les variables et les fonctions du programme: ``` user@host:~$ python -i main.py https://gitlab.com/api/v4 +/groups https://gitlab.com/api/v4/groups >>> ->>> type(endpoint1) +>>> type(endpoint) ``` @@ -75,7 +79,7 @@ Il y a d'autre variables simples: >>> VAR_B=True >>> type(VAR_B) # VAR_B est un `boolean`, une valeur booléenne, \ - # qui ne peut être que `True` ou `False` + # qui ne peut être que `True` ou `False` >>> VAR_C = 10 >>> type(VAR_C) @@ -137,6 +141,6 @@ coding and playing ``` ??? important "Note importante pour les étudiants" - Pour l'évaluation, vous devez demander une merge request depuis votre branche vers la branche start. - ![Faire une merge request](img/creating-merge-request.png) + Pour l'évaluation, vous devez demander une merge request depuis votre branche vers la branche start. + ![Faire une merge request](img/creating-merge-request.png) diff --git a/docs/cours/python/rest.md b/docs/cours/python/rest.md index 613f112e..6f2588cf 100644 --- a/docs/cours/python/rest.md +++ b/docs/cours/python/rest.md @@ -15,22 +15,6 @@ L'API utilisée, appellée REST API communique avec le site web par des requête Nous allons utiliser l'APi de Gitlab qui contient énormément d'informations sur les projets hébergés. - ---- - - - -## Générer un jeton d'authentification - -Pour accéder aux données présentées par l'API (par exemple, la liste des 'issues' qui me sont attribuées), -Gitlab a besoin de m'identifier. - -Pour cela, à partir de notre interface web utilisateur de Gitlab, nous allons générer un **jeton d'authentification**. - -Vous pouvez utiliser ce [tutoriel pour générer votre jeton d'API](https://screenful.com/gitlab/gitlab-apikey){target=_blank} - - - --- @@ -84,13 +68,260 @@ Dans notre fichier `main.py` nous devons maintenant importer les libraires import requests import json - base_url = "https://gitlab.com/api/v4" - endpoint1 = base_url + "/groups" + api_url = "https://gitlab.com/api/v4" + dataset = "/groups" + endpoint = api_url + dataset ``` --- ## Accès à l'API -Nous allons ajouter à notre code une fonction, issue de la bibliothèque requests, pour accéder aux données via l'API REST. +Nous allons maintenant éxecuter ce code en mode interactif, et accéder à l'API dans la console python: +!!! bug "" + ``` + user@host:~$ python -i main.py + >>> r = requests.get(endpoint) + ``` + Nous avons placé dans la variable `r`le résultat de la fonction `get`, prise de la bibliothèque `requests`, avec comme 1er argument `endpoint`, c'est à dire `https://gitlab.com/api/v4/groups` + +!!! bug "" + ``` + >>> print(r) + + ``` + Le résultat ne semble pas encourageant, et pourtant ! Le code **200** signifie qu'une URL a bien été trouvée, ce qu'on préfère à une erreur **404**! + +!!! bug "" + ``` + >>> type(r) + + ``` + Le type de `r` est une classe, c'est un **objet Python**, qui contient d'autres données que ce simple `**Status Code 200**` + + +!!! bug "" + ``` + >>> help(r) + >>> dir(r) + ['__attrs__', '__bool__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_content', '_content_consumed', '_next', 'apparent_encoding', 'close', 'connection', 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history', 'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines', 'json', 'links', 'next', 'ok', 'raise_for_status', 'raw', 'reason', 'request', 'status_code', 'text', 'url'] + ``` + Les fonctions `help()` et `dir()` nous aident à manipuler cet objet. + + +!!! bug "" + ``` + >>> r.__attrs__ + ['_content', 'status_code', 'headers', 'url', 'history', 'encoding', 'reason', 'cookies', 'elapsed', 'request'] + ``` + La **méthode** `__attrs` nous donne une liste d'attributs de notre objet `r` + + +!!! bug "" + ``` + >>> r.url + 'https://gitlab.com/api/v4/groups' + ``` + On peut ainsi vérifier l'URL sollicitée. + + +!!! bug "" + ``` + >>> r.content + ``` + Avant d'accéder au contenu, il va falloir le mettre en forme! + + +--- + +## Formuler un requête à l'API + +Comme il y a beaucoup de données (ici, tous les groupes créés sur Gitlab, il est nécessaire de filtrer notre requête. + +Nous allons pour cela utiliser des paramètres, écrits au format **json** et stockés dans une variable nommée `payload` + +!!! bug "" + ``` + >>> payload = {"search": "garage"} + >>> r = requests.get(endpoint,params=payload) + ``` + nous chercherons ainsi les groupes qui contiennent le mot **garage** + La fonction get prend comme deuxième argument les données json. + On place ces données dans la variable `params` afin de préserver `payload` + +!!! bug "" + ``` + >>> r.headers + {'Date': 'Wed, 05 Aug 2020 18:42:47 GMT', 'Content-Type': 'application/json', 'Transfer-Encoding': 'chunked', + 'Connection': 'keep-alive', 'Set-Cookie': '__cfduid=dcbe4c6164f5e175674b0abff0fb011c71596652967; expires=Fri, 04-Sep-20 18:42:47 GMT; + path=/; domain=.gitlab.com; HttpOnly; SameSite=Lax; Secure', 'Vary': 'Accept-Encoding, Origin', 'Cache-Control': 'max-age=0, + private, must-revalidate', 'Etag': 'W/"44cfa1c513193c8d78cdfc584f6dea72"', 'Link': '; + rel="next", ; + rel="first", ; + rel="last"', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'SAMEORIGIN', 'X-Next-Page': '2', 'X-Page': '1', 'X-Per-Page': '20', 'X-Prev-Page': '', + 'X-Request-Id': 'wo9iLfsTax', 'X-Runtime': '0.116039', 'X-Total': '37', 'X-Total-Pages': '2', 'Strict-Transport-Security': 'max-age=31536000', + 'Referrer-Policy': 'strict-origin-when-cross-origin', 'Content-Encoding': 'gzip', 'GitLab-LB': 'fe-12-lb-gprd', 'GitLab-SV': 'api-18-sv-gprd', + 'CF-Cache-Status': 'DYNAMIC', 'cf-request-id': '046187edf40000edab20af4200000001', 'Expect-CT': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"', + 'Server': 'cloudflare', 'CF-RAY': '5be2a8f65905edab-CDG'} + >>> + >>> r.headers['X-Total'] + '37' + ``` + Les headers nous donnent des informations intéressantes, et notamment ce `X-Total`, qui est le nombre total de résultats obtenus. + **Rappel : ** Les headers sont encadrés par des accolades ( `curly brackets : { }` ). C'est donc un objet de la classe `dic`. On accède à ses éléments en mettant entre crochets et guillemets la clé dont on veut voir la valeur, ici ` r.headers['X-Total']` + + +--- + +## Accéder au contenu de la requête + +Il nous faut maintenant accéder aux données contenues dans la requête + +!!! bug "" + ``` + >>> data = r.json() + >>> + >>> type(data) + + ``` + On créé la variable data, dans lequelle on met le contenu `r` sur lequel on a appliqué la fonction `json()` + +!!! bug "" + ``` + >>> data[0].keys() + dict_keys(['id', 'web_url', 'name', 'path', 'description', 'visibility', 'share_with_group_lock', + 'require_two_factor_authentication', 'two_factor_grace_period', 'project_creation_level', 'auto_devops_enabled', + 'subgroup_creation_level', 'emails_disabled', 'mentions_disabled', 'lfs_enabled', 'default_branch_protection', + 'avatar_url', 'request_access_enabled', 'full_name', 'full_path', 'created_at', 'parent_id', 'ldap_cn', 'ldap_access']) + ``` + Prenons le 1er élément de la liste `data` (numéroté 0), et consultons la liste de ses `keys()`. + Chaque élément de la liste `data`correspond à un résultat de la recherche, et est constitué d'un dictionnaire dans lequel nous allons pouvoir `itérer` + +--- + +## Itération dans la liste de résultats + +### `for` + +Nous allons utiliser la boucle `for` pour **répéter une action sur chaque élément de la liste** (=itérer) + +!!! bug "" + ``` + >>> for i in data: + ... print(i['name']) # Appuyez 2 fois Entrée pour créer un 1ère ligne non indentée + ... # et marquer la fin des instructions de for + AppGarage + Atheed-Garage + Code Garage + [..] + Garagenum + >>> + ``` + Retenez bien la syntaxe simple de la boucle `for`dans Python: les `:` pour marquer le début des instructions, et c'est l'indentation ( `4` ++space++ en début de ligne) seulement qui marque la liste des instructions. + +### `if` + +Nous pouvons maintenant utiliser if pour afficher les détails d'un des résultats obtenus, que nous stockerons dans une variable nommée result: + +!!! bug "" + ``` + >>> for i in data: + ... if i['name'] == "Garagenum": + ... result = i + ... + >>> print(result) + {'id': 4160307, 'web_url': 'https://gitlab.com/groups/garagenum', 'name': 'Garagenum', 'path': 'garagenum', 'description': '', 'visibility': 'public', 'share_with_group_lock': False, 'require_two_factor_authentication': False, 'two_factor_grace_period': 48, 'project_creation_level': 'developer', 'auto_devops_enabled': None, 'subgroup_creation_level': 'owner', 'emails_disabled': None, 'mentions_disabled': None, 'lfs_enabled': True, 'default_branch_protection': 2, 'avatar_url': None, 'request_access_enabled': False, 'full_name': 'Garagenum', 'full_path': 'garagenum', 'created_at': '2018-11-30T14:35:23.504Z', 'parent_id': None, 'ldap_cn': None, 'ldap_access': None} + ``` + Syntaxe similaire que pour le `for`, ici le `if`est imbriqué dans le `for` + +### Affichage + +Nous utiliserons aussi la boucle `for`pour afficher les résultats de manière lisible: + +!!! bug "" + ``` + >>> for i in result: + ... print(i + " : " + str(result[i])) + ... + id : 4160307 + web_url : https://gitlab.com/groups/garagenum + name : Garagenum + [...] + ``` + + Le `str(result[i])`permet de transformer chaque valeur de `result`en **chaîne de caractères (str)**, pour permettre l'affichage par `print()` + + + +--- + + + +## Authentification + +Certaines données peuvent demander une authentification pour en autoriser l'accès. + +Cherchons par exemple, dans les sous-groupes du garage, un groupe privé nommé `interventions`: + +!!! bug "" + ``` + >>> r = requests.get(endpoint,{"search":"garage"}) + >>> + >>> for i in r.json(): + ... if i['name'] == "Garagenum": + ... gn_id = i['id'] + ... + >>> print("L'ID du groupe Garagenum est " + gn_id) + L'ID du groupe Garagenum est 4160307 + >>> + >>> + >>> gn_endpoint = "https://gitlab.com/api/v4/groups/gn_id/subgroups" + >>> + >>> payload = {'search': 'interventions'} + >>> + >>> r = requests.get(gn_endpoint, params = payload) + >>> for i in r.json(): + ... print(i['name']) + ... + >>> + ``` + +Aucun résultat, et pourtant, ce groupe existe! + +Pour vous authentifier, il vous faut d'abord créer un jeton d'authentification dans gitlab + +## Générer un jeton d'authentification + +Pour accéder aux données présentées par l'API (par exemple, la liste des 'issues' qui me sont attribuées), +Gitlab a besoin de m'identifier. + +Pour cela, à partir de notre interface web utilisateur de Gitlab, nous allons générer un **jeton d'authentification**. + +Vous pouvez utiliser ce [tutoriel pour générer votre jeton d'API](https://screenful.com/gitlab/gitlab-apikey){target=_blank} + + +### Accès authentifié + +Il vous suffit maintenant de modifier la variable `payload` , qui contient la liste des options pour la requête. + +!!! bug "" + ``` + >>> payload['private_token'] = "p4zggV-SY1rB4s" + >>> + >>> r = requests.get(gn_endpoint, payload) + >>> + >>> for i in r.json(): + ... print(i['name']) + ... + interventions + ``` + **Notez bien** la manière dont une nouvelle clé `private-token` a été ajoutée au dictonnaire `payload` + +--- + +## Pour les étudiants + +??? important "Conditions de validation" + Pour valider cette unité, il faut que vous fassiez une merge-request vers la branche `start` + Votre code doit permettre d'obtenir le résultat