PDA

Voir la version complète : Résolu Importer script python dans un plugin python



Pandoxyd
26/09/2016, 19h15
Bonjour !

J'ai commencé à créer mon premier plugin en python, pour Cinema4D.

J'aimerais créer une grosse boîte à outils, avec tous mes scripts à l'intérieur, que j'ai créé indépendamment.

Comment puis-je les importer ? En gros, le code de mon plugin serait juste que l'ajout de bouton sur une fenêtre, où chaque bouton lancerait un script différent.

J'ai essayé plusieurs méthodes (placer des fichiers vides '__init__.py', importer en changeant le chemin actuel, placer mes scripts à la racine du plugin, etc...) et j'ai toujours la même erreur : ImportError: no module named MonScript

Si vous avez une idée, je suis preneur :D

oli_d
27/09/2016, 07h19
Salut,

Si j'ai bien compris tu veux te créer ta propre bibliothèque avec tes fonctions ou classes. Tu as en gros 3 possibilités :


Tu rajoutes ta bibliothèque dans un des dossier utilisé par sys.path
Tu rajoutes un ou plusieurs dossiers "ressource" via le code à sys.path
Tu rajoutes un ou plusieurs dossiers "ressource" via un fichier .pth


1
Pour voir les dossiers qu'utilise le python de c4d, tu peux faire:

import c4d
import sys

def main():
for path in sys.path:
print path

if __name__=='__main__':
main()
Dans mon cas (je suis sur mac), cela m'imprime une dizaine de lignes dans la console qui représentent les dossiers dans lesquels python va chercher des bibliothèques externes. Tu n'as plus qu'à rajouter ta bibliothèque dans un de ces dossier (plutôt les deux derniers, soit le dossier site-packages, ou le dossier personnel de ta session si tu n'as pas les droits admin. Attention de redémarrer c4d pour que cela fonctionne.

2
Tu peux rajouter temporairement un dossier à ta liste sys.path en rajoutant une ligne sys.path.append("Ton/chemin/vers/le/dossier") avant ton import:


import c4d
import sys

sys.path.append("/Users/olid/Documents/BibliosPython")
import olid

def main():
pass

if __name__=='__main__':
main()

[EDIT] et j'allais oublier que tu as la variable __file__ qui te permets de récupérer le chemin de ton fichier, et donc si ta bibliothhèque est dans le même dossier que ton scripts tu peux faire :

import c4d,sys,os

path = os.path.dirname(__file__)
sys.path.append(path)

import maLib

def main():
pass

if __name__=='__main__':
main()

3
Tu peux te créer un fichier avec une extension .pth que tu places dans un des dossier du sys.path (voir exemple 1), dans lequel tu écrits une ligne par dossier que tu veux rajouter. C'est super pratique pour rajouter des bibliothèques externes qui sont déjà utilisées sur le python de ta machine. J'ai un fichier od_path.pth dans le dossier site-packages qui contient ça :


/Library/Frameworks/GEOS.framework/Versions/3/Python/2.7/site-packages
/Library/Python/2.7/site-packages
/Library/Frameworks/GDAL.framework/Versions/1.11/Python/2.7/site-packages
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/

Là aussi, il faut redémarrer c4d pour que cela fonctionne.

Pandoxyd
27/09/2016, 11h07
Salut oli_d,

Merci pour ta réponse aussi complète que rapide ! J'ai effectivement trouvé comment importer un script externe. J'ai mon pluginsqui possède un dossier "scripts" et je peux maintenant les charger en combinant les deux codes de ta méthode 2 (mon script externe s'appelle "batch.py"):



import c4d
from c4d import bitmaps, gui, plugins
import os, sys

path = os.path.dirname(__file__)
sys.path.append(path) #je pointe vers le chemin du plugin exécuté

sys.path.append(path+"\scripts") #je rajoute le sous dossier 'scripts' afin de loader les différents scripts qui seront placés là

import batch
from batch import *

("Batch.py" est un petit script, avec interface, qui sert à renommer par lot des objets d'une scène)

Le script se lance bien depuis le bouton du plugin, l'interface apparaît grâce à :



def Command(self,id,msg):
if id == RENAMER:
batch.BatchRename()
return True


(BatchRename() étant le 'main' de mon script)

Mais dès que je le manipule (via les boutons de l'interface du plugin), la console me rapporte l'erreur suivante :



"NameError: global name 'doc' is not defined"


Le "doc" correspondant à la ligne 82 de "batch.py" qui est :



objs = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELE CTIONORDER) #Récupération des objets sélectionnés dans l'ordre


Que s'est-il passé ? Dois-revenir dans les chemins des modules de bases de Cinema4D afin qu'il reconnaisse le mot "doc" (qu'il reconnait très bien quand je lance le script seul) ? Ou dois-je déclarer d'une manière plus explicite le module "doc" dans mon script "batch.py" ?

gr4ph0s
27/09/2016, 11h21
C'est juste que ton doc n'est pas définis (ce qui se passe si tu exécutes via un plugin).
Il faut bien comprendre que doc est une variable faite par c4d pour facilité l'accès au document.

Bref il te suffit de recup le doc courant.


doc = c4d.documents.GetActiveDocument()
objs = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELE CTIONORDER) #Récupération des objets sélectionnés dans l'ordre

Pandoxyd
27/09/2016, 12h03
Super ! :thumbup:

Ça marche en effet, mais je dois le re-déclarer le 'doc' pour chaque fonction qui l'utilise et ce, pour tous mes scripts ? N'y a-t-il pas moyen de déclarer qu'une seule fois dans mon plugin, en tant que global ?

J'ai tenté sauvagement un 'doc = c4d.documents.GetActiveDocument()' au début du code (une première fois du plugin et une fois dans le script), puis des 'global doc' avant de l'utiliser, mais la console me retourne :



ReferenceError: the object 'c4d.documents.BaseDocument' is not alive


Ou je dois remettre à jour tous mes scripts ?

gr4ph0s
27/09/2016, 13h10
Bha actuellement enfaite tu mets la valeur de retour de GetActiveDocument dans la variable doc. Donc si tu change de doc il faut relancer la fonction.

Donc oui il faut a chaque fois. Sinon tu peux faire doc = c4d.documents.GetActiveDocument
Sans les parentheses comme sa ta variable correspond a la fonction et voila.

Pandoxyd
27/09/2016, 14h30
Ok, ba pas grave, je rendrais mes codes plus propres comme ça.

Merci à vous en tout cas, c'est parfait !

oli_d
28/09/2016, 06h40
A part ça tu peux toujours aussi appeler ton scripts via un CallCommand(), c'est peut-être plus simple:

Tu ouvre l'historique de script du menu script
Tu lances ton scripts
Tu recopie la ligne CallCommand(xxxxxxx,xxxxxx)#nom_script de l'historique dans ton code


Une autre chose évite d'ajouter un dossier ou un fichier à ton path avec un +:
sys.path.append(path+"\scripts") -> sur mac ça plante

Utilise plutôt os.path.join : sys.path.append(os.path.join(path,"scripts")) Avec ça tu es certain que ça passe sur toutes les plateformes

Sir Gong
28/09/2016, 10h48
Salut Pandoxyd, te voilà membre reconnu.