hardcoding of the endpoints and __dir__ edition #1

Closed
opened 2018-06-26 19:39:35 +02:00 by chapeau · 13 comments
chapeau commented 2018-06-26 19:39:35 +02:00 (Migrated from gitlab2.federez.net)

@mael.kervella

Actuellement, on s'oblige à lister tous les endpoints qui peuvent exister dans extensions.urls, ce qui génère des jolies méthodes pour le Re2oAPIClient.

Du coup, on peut par exemple accéder à la méthode Re2oAPIClient.list_dns_zones(), et ça marche.

J'ai l'impression que tout ça est bien compliqué pour pas grand chose. De un, c'est compliqué et quand on voit un appel à une méthode qui n'est pas explicitement déclarée, on doit remonter la chaine pour comprendre ce qu'il se passe. De deux, on est obligé d'hardcoder les endpoints, du coup, dès qu'on veut rajouter un nouveau services clients, il faut modifier le dépôt principal, ce qui a l'air chiant.

Je pense que le code du client re2o devrait être le plus simple possible, donc sans utilisation du dir, et le plus générique possible, donc sans aucun harcodage lié à une appli spécifique.

Pourquoi ne pas juste avoir une méthode du genre Re2oAPIClient.get("services.regen"), ou Re2oAPIClient.get("services.regen",3), qui correspondrait à la query sur "/api/services/regen/" ou "/api/services/regen/3" ?

Si on veut absolument faire des raccourcis sur les endpoints, je serais plus pour qu'il soit harcodé dans chaque sous applis, et qu'on passe l'équivalent du urls en argument du init de Re2oClient par exemple.

On pourrait avoir dans une appli un truc du genre:
urls = { 'servicesregen-list': '/api/services/regen/', 'servicesregen-detail': '/api/services/regen/{pk}/', } api_client = Re2oAPIClient(api_hostname, api_username, api_password, urls) api_client.get("servicesregen-list")

@mael.kervella Actuellement, on s'oblige à lister tous les endpoints qui peuvent exister dans extensions.urls, ce qui génère des jolies méthodes pour le Re2oAPIClient. Du coup, on peut par exemple accéder à la méthode Re2oAPIClient.list_dns_zones(), et ça marche. J'ai l'impression que tout ça est bien compliqué pour pas grand chose. De un, c'est compliqué et quand on voit un appel à une méthode qui n'est pas explicitement déclarée, on doit remonter la chaine pour comprendre ce qu'il se passe. De deux, on est obligé d'hardcoder les endpoints, du coup, dès qu'on veut rajouter un nouveau services clients, il faut modifier le dépôt principal, ce qui a l'air chiant. Je pense que le code du client re2o devrait être le plus simple possible, donc sans utilisation du __dir__, et le plus générique possible, donc sans aucun harcodage lié à une appli spécifique. Pourquoi ne pas juste avoir une méthode du genre Re2oAPIClient.get("services.regen"), ou Re2oAPIClient.get("services.regen",3), qui correspondrait à la query sur "/api/services/regen/" ou "/api/services/regen/3" ? Si on veut absolument faire des raccourcis sur les endpoints, je serais plus pour qu'il soit harcodé dans chaque sous applis, et qu'on passe l'équivalent du urls en argument du init de Re2oClient par exemple. On pourrait avoir dans une appli un truc du genre: ` urls = { 'servicesregen-list': '/api/services/regen/', 'servicesregen-detail': '/api/services/regen/{pk}/', } api_client = Re2oAPIClient(api_hostname, api_username, api_password, urls) api_client.get("servicesregen-list") `
chapeau commented 2018-06-26 22:53:19 +02:00 (Migrated from gitlab2.federez.net)

Alors en vrai je comprends totalement ta remarque puisque c'est ce que j'étais parti pour faire au début.

Mais je me suis rendu compte que ça avait un gros désavantage: Les urls se retrouvent partout et tu peux plus y toucher. Je sais qu'en théorie, une fois l'API définie on est plus sensé y toucher mais bon je pense que vu comment Re2o est dev actuellement, ce sera pas le cas, il y aura toujours un moment où va vouloir renomer des urls en mode "Ha il y a un faute ici" ou "je trouve que ça rend mieux au pluriel"... Bref je suis a peu près sûr que les urls vont changer à un moment ou à un autre.
A ce moment là, le problème c'est que tu vas devoir retrouver TOUS les projets qui utilisent l'API, cherchez TOUS les endroits où tu utilise cette URL (probablement en oublier certains) et modifier TOUS tes projets.
Ce qu'il faut comprendre c'est que le but d'avoir défini un mapping des URLS n'est pas d'avoir des raccourcis ou des jolies méthodes parce qu'entre taper .list_dns_zones() et .get('https://....') la différence est pas violente. Non le but principal c'est d'avoir une couche d'abstraction qui te permette de modifier les URLs facilement si besoin et en même temps d'avoir une single source of truth : tes URLS sont définies à un seul et unique endroit et t'as pas à aller chercher partout.

En plus de ça, utiliser .get(url) à la place de .list_machin() a un énorme inconvénient : tu dois gérer toi-même la pagination et la structure de la réponse. En effet, .list_machin() ne fait pas qu'appeler une URL, elle en appelle autant qu'il y a de page d'info, assemble les résultats, ... Alors que le but du client est justement d'éviter ces trucs compliqués. Pour rebondire sur ça, je dirais même que les fonction .list_machin(), .view_machin() ... ne sont pas juste des wrappers pour "embellir" des appels à des URLS, il peut très bien y avoir plus de choses dedans. Example de .list_machin() ci-dessus mais aussi on pourrait imaginer d'autres fonctions qui font des trucs spécifique que t'as pas envie que chaque service réimplémente à sa manière (exemple marquer une regen comme terminée ou encore utiliser des filtres pour les requêtes comme "adhérent avec connexion active", ...). Bref en ajoutant une "couche d'abstraction", ça évite que chaque service réimplémente les trucs à sa façon.

Autre point: t'as pas envie de chercher à savoir si ce que tu doit faire c'est un GET, un POST, un DELETE, un PUT, un PATCH ou autre. C'est clairement du bas-level ça. Ce que tu veux faire par contre c'est "modifier telle valeur", "avoir les détails de tel objet", .... sans te poser de question.

Je sais pas si je suis clair (je sais que souvent je le suis pas) mais j'ai essayé d'argumenter pourquoi selon moi, c'est mieux d'avoir les URLS définis à un seul endroit et utiliser des .do_something_machin() plutôt que d'utiliser des trucs beaucoup plus bas niveau comme .get, .delete, ... Et j'ai l'impression de ce que je lis que pour toi, j'avais fait ça pour faire "joli" mais c'est pas du tout l'intention, c'est vraiment pour des raisons d'abstraction et de single source of truth.

By moamoak on 2018-06-26T20:53:19 (imported from GitLab)

Alors en vrai je comprends totalement ta remarque puisque c'est ce que j'étais parti pour faire au début. Mais je me suis rendu compte que ça avait un gros désavantage: **Les urls se retrouvent partout et tu peux plus y toucher**. Je sais qu'en théorie, une fois l'API définie on est plus sensé y toucher mais bon je pense que vu comment Re2o est dev actuellement, ce sera pas le cas, il y aura toujours un moment où va vouloir renomer des urls en mode "Ha il y a un faute ici" ou "je trouve que ça rend mieux au pluriel"... Bref je suis a peu près sûr que les urls vont changer à un moment ou à un autre. A ce moment là, le problème c'est que tu vas devoir retrouver TOUS les projets qui utilisent l'API, cherchez TOUS les endroits où tu utilise cette URL (probablement en oublier certains) et modifier TOUS tes projets. Ce qu'il faut comprendre c'est que le but d'avoir défini un mapping des URLS n'est pas d'avoir des *raccourcis* ou des *jolies méthodes* parce qu'entre taper `.list_dns_zones()` et .get('https://....') la différence est pas violente. Non le but principal c'est d'avoir une couche d'abstraction qui te permette de modifier les URLs facilement si besoin et en même temps d'avoir une *single source of truth* : tes URLS sont définies à un seul et unique endroit et t'as pas à aller chercher partout. En plus de ça, utiliser `.get(url)` à la place de `.list_machin()` a un énorme inconvénient : tu dois gérer toi-même la pagination et la structure de la réponse. En effet, `.list_machin()` ne fait pas qu'appeler une URL, elle en appelle autant qu'il y a de page d'info, assemble les résultats, ... Alors que le but du client est justement d'éviter ces trucs compliqués. Pour rebondire sur ça, je dirais même que les fonction `.list_machin()`, `.view_machin()` ... ne sont pas juste des wrappers pour "embellir" des appels à des URLS, il peut très bien y avoir plus de choses dedans. Example de `.list_machin()` ci-dessus mais aussi on pourrait imaginer d'autres fonctions qui font des trucs spécifique que t'as pas envie que chaque service réimplémente à sa manière (exemple marquer une regen comme terminée ou encore utiliser des filtres pour les requêtes comme "adhérent avec connexion active", ...). Bref en ajoutant une "couche d'abstraction", ça évite que chaque service réimplémente les trucs à sa façon. Autre point: t'as pas envie de chercher à savoir si ce que tu doit faire c'est un GET, un POST, un DELETE, un PUT, un PATCH ou autre. C'est clairement du bas-level ça. Ce que tu veux faire par contre c'est "modifier telle valeur", "avoir les détails de tel objet", .... sans te poser de question. Je sais pas si je suis clair (je sais que souvent je le suis pas) mais j'ai essayé d'argumenter pourquoi selon moi, c'est mieux d'avoir les URLS définis à un seul endroit et utiliser des `.do_something_machin()` plutôt que d'utiliser des trucs beaucoup plus bas niveau comme `.get`, `.delete`, ... Et j'ai l'impression de ce que je lis que pour toi, j'avais fait ça pour faire "joli" mais c'est pas du tout l'intention, c'est vraiment pour des raisons d'abstraction et de *single source of truth*. *By moamoak on 2018-06-26T20:53:19 (imported from GitLab)*
chapeau commented 2018-06-26 23:00:16 +02:00 (Migrated from gitlab2.federez.net)

Je pense que le code du client re2o devrait être le plus simple possible, donc sans utilisation du dir, et le plus générique possible, donc sans aucun harcodage lié à une appli spécifique.

Par rapport à cette phrase en particulier j'ai deux remarques:

  1. __dir__ n'est là que pour que quand tu fasse tab dans ipython, tu puisses autocompléter la fonction sans avoir à chercher l'écriture exacte ("il y a un s ? c'est un - ou un _ ? ...."). Qu'il soit là ou non ne change absolument pas le comportement du client api.
  2. si tu veux un truc qui n'est spécifique à rien, ça existe ça s'appelle requests :) Re2oAPIClient est un client API pour Re2o, il est donc adapté à Re2o et pas fait pour être utilisé avec autre chose. Je veux dire tu peux pas faire un truc universel en mode "Les réponses ont ce format", "Il faut passer telle option dans les requetes pour optimiser", "Cette API a un comportement pas standard (si un tel standard existe)", ... Le client est forcément adapté à l'API que t'as en face sinon tu refais un truc aussi générique que requests (donc ça sert à rien)

By moamoak on 2018-06-26T21:00:56 (imported from GitLab)

> Je pense que le code du client re2o devrait être le plus simple possible, donc sans utilisation du **dir**, et le plus générique possible, donc sans aucun harcodage lié à une appli spécifique. Par rapport à cette phrase en particulier j'ai deux remarques: 1. `__dir__` n'est là que pour que quand tu fasse `tab` dans ipython, tu puisses autocompléter la fonction sans avoir à chercher l'écriture exacte ("il y a un s ? c'est un - ou un _ ? ...."). Qu'il soit là ou non ne change absolument pas le comportement du client api. 2. si tu veux un truc qui n'est spécifique à rien, ça existe ça s'appelle `requests` :) Re2oAPIClient est un client API pour Re2o, il est donc adapté à Re2o et pas fait pour être utilisé avec autre chose. Je veux dire tu peux pas faire un truc universel en mode "Les réponses ont ce format", "Il faut passer telle option dans les requetes pour optimiser", "Cette API a un comportement pas standard (si un tel standard existe)", ... Le client est forcément adapté à l'API que t'as en face sinon tu refais un truc aussi générique que `requests` (donc ça sert à rien) *By moamoak on 2018-06-26T21:00:56 (imported from GitLab)*
chapeau commented 2018-06-26 23:09:14 +02:00 (Migrated from gitlab2.federez.net)

De deux, on est obligé d'hardcoder les endpoints, du coup, dès qu'on veut rajouter un nouveau services clients, il faut modifier le dépôt principal, ce qui a l'air chiant.

Le but n'est justement pas de coder un endpoint à chaque fois que t'as besoin d'un service. Sinon on se retrouve comme avant avec des endpoints écrit un peu à l'arrache et qui n'ont plus vraiment de sens. Le but est d'utiliser les endpoints déjà créés (en exposant tous les modèles, toutes les infos sont déjà disponibles). Après il est vrai qu'il y a des exceptions pour le dhcp et le dns parce que c'est des trucs qui ont des fortes contraintes comme le besoin d'être executé très fréquement. Si on utilisait les endpoints "model-based" il faudrait des miliers de requetes pour avoir toutes les infos. (j'avais commencé comme ça pour le dhcp pour tester, et il me fallait plus de 30 min pour générer un dhcp avec 150 users alors que les deux machines étaient sur le même virtualiseur, même vlan donc c'était pas le réseau le pb :) )

Pour tous les services qui ont n'ont pas vraiment besoin de ce genre d'optimisation (exemple: si c'est un truc qui est lancé qu'une fois par mois), c'est pas nécessaire d'ajouter un endpoints spécifique à ça.

By moamoak on 2018-06-26T21:09:45 (imported from GitLab)

> De deux, on est obligé d'hardcoder les endpoints, du coup, dès qu'on veut rajouter un nouveau services clients, il faut modifier le dépôt principal, ce qui a l'air chiant. Le but n'est justement pas de coder un endpoint à chaque fois que t'as besoin d'un service. Sinon on se retrouve comme avant avec des endpoints écrit un peu à l'arrache et qui n'ont plus vraiment de sens. Le but est d'utiliser les endpoints déjà créés (en exposant tous les modèles, toutes les infos sont déjà disponibles). Après il est vrai qu'il y a des exceptions pour le dhcp et le dns parce que c'est des trucs qui ont des fortes contraintes comme le besoin d'être executé très fréquement. Si on utilisait les endpoints "model-based" il faudrait des miliers de requetes pour avoir toutes les infos. (j'avais commencé comme ça pour le dhcp pour tester, et il me fallait plus de 30 min pour générer un dhcp avec 150 users alors que les deux machines étaient sur le même virtualiseur, même vlan donc c'était pas le réseau le pb :) ) Pour tous les services qui ont n'ont pas vraiment besoin de ce genre d'optimisation (exemple: si c'est un truc qui est lancé qu'une fois par mois), c'est pas nécessaire d'ajouter un endpoints spécifique à ça. *By moamoak on 2018-06-26T21:09:45 (imported from GitLab)*
chapeau commented 2018-06-26 23:45:14 +02:00 (Migrated from gitlab2.federez.net)

Non le but principal c'est d'avoir une couche d'abstraction qui te permette de modifier les URLs facilement si besoin et en même temps d'avoir une single source of truth : tes URLS sont définies à un seul et unique endroit et t'as pas à aller chercher partout.

Ben, j'ai l'impression que tu fais des choix de dev par rapport au fait que le projet est mal developpé, et que tu fais des concessions "batardes". Soit tu veut une _ single source of truth_, et à ce moment là, ton api est clairement défini côté serveur, l'url est défini de manière claire et précise par rapport à la position dans le projet, c'est fixé, ça bouge plus, et côté client tu sais que un list_machines est mappé de par les règles de l'api sur /api/machines/whatever. Et tu n'as pas besoin d'un dictionnaire qui tu sors les endpoints.

Parce que là, on a deux sources of truth, le serveur ET le client. J'ai vraiment l'impression que la bonne pratique c'est dire, le serveur c'est la vérité, on a fixé tel schema d'api, les clients doivent utiliser ça.

En plus de ça, utiliser .get(url) à la place de .list_machin() a un énorme inconvénient

Je me suis mal fait comprendre la. Je veux pas un get(url). Le client doit quand même s'occuper de format, etc. Je voulais un get("list_machines"), qui se comportent exactement comme un .list_machines(), mais sans la surcouche où tu fais du python complexe pour générer des méthodes à partir du code.

J'avais dit:

Je pense que le code du client re2o devrait être le plus simple possible, donc sans utilisation du dir, et le plus générique possible, donc sans aucun harcodage lié à une appli spécifique.

Quand j'ai dit ça, le mot appli voulait dire machines/users/..., pas re2o. L'api devrait découler de la structure du code, et si je rajoute un model dans le machines.models, je sais de par les règles de l'api que son url d'accès c'est /api/machines/monnouveaumodel. Je devrait pas avoir à dire à mon API client, hey, y a ce nouveau model qui existe, pour pouvoir l'utiliser.

Le but n'est justement pas de coder un endpoint à chaque fois que t'as besoin d'un service.

Là, si on veut rajoute un compte mail, il faut enregistre le model dans le serveur, puis mettre le serializer dans l'appli api du serveur, puis dans l'api client, et je peux faire enfin faire une fonction qui fait appel à mon truc. Je trouve que ça fait beaucoup de couche, et si on peut retirer notamment celle où je dois enregistrer mon modele coté api client, c'est pas mal.

By jacomme on 2018-06-26T21:45:47 (imported from GitLab)

> Non le but principal c'est d'avoir une couche d'abstraction qui te permette de modifier les URLs facilement si besoin et en même temps d'avoir une _single source of truth_ : tes URLS sont définies à un seul et unique endroit et t'as pas à aller chercher partout. Ben, j'ai l'impression que tu fais des choix de dev par rapport au fait que le projet est mal developpé, et que tu fais des concessions "batardes". Soit tu veut une _ single source of truth_, et à ce moment là, ton api est clairement défini côté serveur, l'url est défini de manière claire et précise par rapport à la position dans le projet, c'est fixé, ça bouge plus, et côté client tu sais que un list_machines est mappé de par les règles de l'api sur /api/machines/whatever. Et tu n'as pas besoin d'un dictionnaire qui tu sors les endpoints. Parce que là, on a deux sources of truth, le serveur ET le client. J'ai vraiment l'impression que la bonne pratique c'est dire, le serveur c'est la vérité, on a fixé tel schema d'api, les clients doivent utiliser ça. > En plus de ça, utiliser .get(url) à la place de .list_machin() a un énorme inconvénient Je me suis mal fait comprendre la. Je veux pas un get(url). Le client doit quand même s'occuper de format, etc. Je voulais un get("list_machines"), qui se comportent exactement comme un .list_machines(), mais sans la surcouche où tu fais du python complexe pour générer des méthodes à partir du code. J'avais dit: > Je pense que le code du client re2o devrait être le plus simple possible, donc sans utilisation du **dir**, et le plus générique possible, donc sans aucun harcodage lié à une appli spécifique. Quand j'ai dit ça, le mot appli voulait dire machines/users/..., pas re2o. L'api devrait découler de la structure du code, et si je rajoute un model dans le machines.models, je __sais__ de par les règles de l'api que son url d'accès c'est /api/machines/monnouveaumodel. Je devrait pas avoir à dire à mon API client, hey, y a ce nouveau model qui existe, pour pouvoir l'utiliser. > Le but n'est justement pas de coder un endpoint à chaque fois que t'as besoin d'un service. Là, si on veut rajoute un compte mail, il faut enregistre le model dans le serveur, puis mettre le serializer dans l'appli api du serveur, puis dans l'api client, et je peux faire enfin faire une fonction qui fait appel à mon truc. Je trouve que ça fait beaucoup de couche, et si on peut retirer notamment celle où je dois enregistrer mon modele coté api client, c'est pas mal. *By jacomme on 2018-06-26T21:45:47 (imported from GitLab)*
chapeau commented 2018-06-26 23:56:19 +02:00 (Migrated from gitlab2.federez.net)

Bref je suis a peu près sûr que les urls vont changer à un moment ou à un autre.

Je viens d'y penser, mais cet argument est aussi vrai pour les .list_machin()...
Si demain, on décide de dire, en fait, list_machin, ce serait mieux avec en .machin_list, ben il faut aussi se replonger partout pour tout modifier.

Le dictionnaire extensions, au lieu de créer une single source, double le problème.

Option 1) les urls côté serveur, et les services dns/dhcp/... qui doivent être en accord avec ces urls

Option 2) les urls côté serveur, l'API client qui doit etre en accord avec les urls et qui définit des noms de fonctions, et les services dns/dhcp/... qui doivent être en accord avec les noms de fonctions.

Je préfère vraiment l'option 1.

By jacomme on 2018-06-26T21:56:39 (imported from GitLab)

> Bref je suis a peu près sûr que les urls vont changer à un moment ou à un autre. Je viens d'y penser, mais cet argument est aussi vrai pour les .list_machin()... Si demain, on décide de dire, en fait, list_machin, ce serait mieux avec en .machin_list, ben il faut aussi se replonger partout pour tout modifier. Le dictionnaire extensions, au lieu de créer une single source, double le problème. Option 1) les urls côté serveur, et les services dns/dhcp/... qui doivent être en accord avec ces urls Option 2) les urls côté serveur, l'API client qui doit etre en accord avec les urls et qui définit des noms de fonctions, et les services dns/dhcp/... qui doivent être en accord avec les noms de fonctions. Je préfère vraiment l'option 1. *By jacomme on 2018-06-26T21:56:39 (imported from GitLab)*
chapeau commented 2018-06-27 11:46:48 +02:00 (Migrated from gitlab2.federez.net)

ok je vois ce que tu veux dire. Je crois cerner à peu près le problème, je vais voir si je peux modifier ça pour ne pas utiliser le mapping.

By moamoak on 2018-06-27T09:46:48 (imported from GitLab)

ok je vois ce que tu veux dire. Je crois cerner à peu près le problème, je vais voir si je peux modifier ça pour ne pas utiliser le mapping. *By moamoak on 2018-06-27T09:46:48 (imported from GitLab)*
chapeau commented 2018-06-27 12:24:27 +02:00 (Migrated from gitlab2.federez.net)

A choisir tu dirais que c'est quoi le mieux en terme de compréhension/facilité:

apiclient.view('machines/extension/1')

ou

apiclient.view('machines', 'extension', '1')

ou même (mais la diff est pas grande avec la ligne du dessus, juste un str() dans le code en plus)

apiclient.view('machines', 'extension', 1)

By moamoak on 2018-06-27T10:30:16 (imported from GitLab)

A choisir tu dirais que c'est quoi le mieux en terme de compréhension/facilité: ``` apiclient.view('machines/extension/1') ``` ou ``` apiclient.view('machines', 'extension', '1') ``` ou même (mais la diff est pas grande avec la ligne du dessus, juste un `str()` dans le code en plus) ``` apiclient.view('machines', 'extension', 1) ``` *By moamoak on 2018-06-27T10:30:16 (imported from GitLab)*
chapeau commented 2018-06-27 12:29:05 +02:00 (Migrated from gitlab2.federez.net)

et est-ce que selon toi il y a un intérêt à proposer

apiclient.view_machines_extension_1()

ou

apiclient.view_machines_extension(1)

en plus de la méthode .view() ?

(je sais je tiens pas mal à ces méthodes même si j'avoue qu'elles perdent de leur intérêt là)

By moamoak on 2018-06-27T10:29:05 (imported from GitLab)

et est-ce que selon toi il y a un intérêt à proposer ``` apiclient.view_machines_extension_1() ``` ou ``` apiclient.view_machines_extension(1) ``` en plus de la méthode `.view()` ? (je sais je tiens pas mal à ces méthodes même si j'avoue qu'elles perdent de leur intérêt là) *By moamoak on 2018-06-27T10:29:05 (imported from GitLab)*
chapeau commented 2018-06-27 12:34:57 +02:00 (Migrated from gitlab2.federez.net)

J'avoue, je suis pas sur d'avoir d'avis aussi fin qui puisse être pertinent^^

Je préfère apiclient.view('machines/extension/1'), qui me semble plus concis.

Je suis vraiment pas convaincu de l'intérêt des apiclient.view_machines_extension(1), mais si tu y tiens, j'ai pas vraiment grand chose contre. Cela dit, faudra bien expliquer dans des commentaires qu'on génère à la volée des méthodes, c'est le genre de truc qui peut bien perturber les débutants en python.

By jacomme on 2018-06-27T10:34:57 (imported from GitLab)

J'avoue, je suis pas sur d'avoir d'avis aussi fin qui puisse être pertinent^^ Je préfère `apiclient.view('machines/extension/1')`, qui me semble plus concis. Je suis vraiment pas convaincu de l'intérêt des `apiclient.view_machines_extension(1)`, mais si tu y tiens, j'ai pas vraiment grand chose contre. Cela dit, faudra bien expliquer dans des commentaires qu'on génère à la volée des méthodes, c'est le genre de truc qui peut bien perturber les débutants en python. *By jacomme on 2018-06-27T10:34:57 (imported from GitLab)*
chapeau commented 2018-06-27 13:13:23 +02:00 (Migrated from gitlab2.federez.net)

oui, j'ai réfléchi aux versions en apiclient.view_machines_extension(1) en mangeant et j'en suis aussi arrivé à la conclusion que ça apporte rien a part une autre façon d'écrire la meme chose (et c'est meme pas plus court ou plus facile)

By moamoak on 2018-06-27T11:13:23 (imported from GitLab)

oui, j'ai réfléchi aux versions en `apiclient.view_machines_extension(1)` en mangeant et j'en suis aussi arrivé à la conclusion que ça apporte rien a part une autre façon d'écrire la meme chose (et c'est meme pas plus court ou plus facile) *By moamoak on 2018-06-27T11:13:23 (imported from GitLab)*
chapeau commented 2018-06-27 13:20:07 +02:00 (Migrated from gitlab2.federez.net)

mentioned in commit c3277c2e6e

By moamoak on 2018-06-27T11:20:07 (imported from GitLab)

mentioned in commit c3277c2e6eb3a85e8580c906266cad46c4043677 *By moamoak on 2018-06-27T11:20:07 (imported from GitLab)*
chapeau commented 2018-06-27 16:37:17 +02:00 (Migrated from gitlab2.federez.net)

@mael.kervella
Nice, j'aime beaucoup la nouvelle version :D
C'est joli !

By jacomme on 2018-06-27T14:37:17 (imported from GitLab)

@mael.kervella Nice, j'aime beaucoup la nouvelle version :D C'est joli ! *By jacomme on 2018-06-27T14:37:17 (imported from GitLab)*
chapeau commented 2018-06-27 16:37:18 +02:00 (Migrated from gitlab2.federez.net)

closed

By jacomme on 2018-06-27T14:37:18 (imported from GitLab)

closed *By jacomme on 2018-06-27T14:37:18 (imported from GitLab)*
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: re2o/re2oapi#1
No description provided.