web-dev-qa-db-fra.com

Comment recharger un module dans une session Julia active après une modification?

Mise à jour 2018: Assurez-vous de vérifier toutes les réponses, car la réponse à cette question a changé plusieurs fois au fil des ans. Au moment de cette mise à jour, la réponse Revise.jl Est probablement la meilleure solution.

J'ai un fichier "/SomeAbsolutePath/ctbTestModule.jl", dont le contenu est:

module ctbTestModule
export f1
f1(x) = x + 1
end

Je lance Julia dans un terminal qui exécute "~/.juliarc.jl". Le code de démarrage comprend la ligne:

Push!(LOAD_PATH, "/SomeAbsolutePath/")

Par conséquent, je peux immédiatement taper dans la console Julia:

using ctbTestModule

pour charger mon module. Comme prévu, f1(1) renvoie 2. Maintenant, je décide soudainement que je veux modifier f1. J'ouvre "/SomeAbsolutePath/ctbTestModule.jl" dans un éditeur et change le contenu en:

module ctbTestModule
export f1
f1(x) = x + 2
end

J'essaie maintenant de recharger le module dans ma session Julia active. J'essaie

using ctbTestModule

mais f1(1) renvoie toujours 2. Ensuite j'essaye:

reload("ctbTestModule")

comme suggéré ici , mais f1(1) renvoie toujours 2. Enfin, j'essaye:

include("/SomeAbsolutePath/ctbTestModule.jl")

comme suggéré ici , ce qui est pas idéal car je dois taper le chemin absolu complet car le répertoire actuel n'est peut-être pas "/ SomeAbsolutePath". Je reçois le message d'avertissement Warning: replacing module ctbTestModule Qui semble prometteur, mais f1(1) renvoie toujours 2.

Si je ferme la session Julia en cours, que j'en démarre une nouvelle et que je tape using ctbTestModule, J'obtiens maintenant le comportement souhaité, c'est-à-dire que f1(1) renvoie 3. Mais évidemment, je veux faire ça sans redémarrer Julia.

Alors, qu'est-ce que je fais mal?

Autres détails: Julia v0.2 sur Ubuntu 14.04.

55
Colin T Bowers

La base de ce problème est la confluence de recharger un module, mais de ne pas pouvoir redéfinir quelque chose dans le module Main ( voir la documentation ici ) - c'est-à-dire au moins jusqu'à ce que le nouvel espace de travail de fonction () soit disponible le 13 juillet 2014. Versions récentes de la version 0.3 la version devrait l'avoir.

Avant l'espace de travail ()

Considérez le module simpliste suivant

module TstMod
export f

function f()
   return 1
end

end

Ensuite, utilisez-le ....

Julia> using TstMod

Julia> f()
1

Si la fonction f () est remplacée par retourne 2 et que le module est rechargé, f est en fait mis à jour. Mais pas redéfini dans le module Main .

Julia> reload("TstMod")
Warning: replacing module TstMod

Julia> TstMod.f()
2

Julia> f()
1

Les avertissements suivants clarifient le problème

Julia> using TstMod
Warning: using TstMod.f in module Main conflicts with an existing identifier.

Julia> using TstMod.f
Warning: ignoring conflicting import of TstMod.f into Main

Utilisation de workspace ()

Cependant, la nouvelle fonction espace de travail () efface Main le préparer pour le rechargement TstMod

Julia> workspace()

Julia> reload("TstMod")

Julia> using TstMod

Julia> f()
2

En outre, le précédent Main est stocké sous la forme LastMain

Julia> whos()
Base                          Module
Core                          Module
LastMain                      Module
Main                          Module
TstMod                        Module
ans                           Nothing

Julia> LastMain.f()
1
55
waTeim

Utilisez le package Revise, par exemple.

Pkg.add("Revise") # do this only once

include("src/my_module.jl")
using Revise
import my_module

Vous devrez peut-être le démarrer dans une nouvelle session REPL. Notez l'utilisation de import au lieu de using, car using ne redéfinit pas la fonction dans le module Main (comme expliqué par @Maciek Leks et @waTeim).

Autres solutions : Deux avantages de Revise.jl Par rapport à workspace() sont que (1) c'est beaucoup plus rapide, et (2) il est à l'épreuve du temps, car workspace() a été déprécié en 0.7, comme discuté dans ce problème GitHub :

Julia> VERSION
v"0.7.0-DEV.3089"

Julia> workspace()
ERROR: UndefVarError: workspace not defined

et un contributeur GitHub a recommandé Revise.jl:

Devrions-nous ajouter un message comme "l'espace de travail est obsolète, consultez plutôt Revise.jl"?

Même dans Julia 0.6.3, les trois solutions précédentes de workspace(), import et reload échouent lorsqu'un module appelle d'autres modules, tels que DataFrames . Avec les trois méthodes, j'ai eu la même erreur lorsque j'ai appelé ce module la deuxième fois dans le même REPL:

ERROR: LoadError: MethodError: all(::DataFrames.##58#59, ::Array{Any,1}) is ambiguous. Candidates: ...

J'ai également reçu de nombreux messages d'avertissement tels que:

WARNING: Method definition macroexpand(Module, ANY) in module Compat at /Users/mmorin/.Julia/v0.6/Compat/src/Compat.jl:87 overwritten in module Compat at /Users/mmorin/.Julia/v0.6/Compat/src/Compat.jl:87.

Le redémarrage de la session Julia a fonctionné, mais c'était lourd. J'ai trouvé ce problème dans le package Reexport , avec un message d'erreur similaire:

MethodError: all(::Reexport.##2#6, ::Array{Any,1}) is ambiguous.

et a suivi la suggestion d'un contributeur:

Est-ce que cela se produit sans utiliser workspace ()? Cette fonction est connue pour interagir mal avec les packages, c'est pourquoi elle a été dépréciée en 0.7.

13
mmorin

À mon humble avis, la meilleure façon est d'utiliser import dès le début au lieu de using pour le problème signalé.

Considérez le module:

module ModuleX1
  export produce_text
  produce_text() = begin
    println("v1.0") 
  end
  println("v1.0 loaded")
end

Puis dans REPL:

Julia> import ModuleX1
v1.0 loaded

Julia> ModuleX1.produce_text()
v1.0

Mettez à jour le code du module et enregistrez-le:

module ModuleX1
  export produce_text
  produce_text() = begin
    println("v2.0")  
  end
  println("v2.0 loaded")
end

Ensuite, dans le REPL:

Julia> reload("ModuleX1")
Warning: replacing module ModuleX1
v2.0 loaded

Julia> ModuleX1.produce_text()
v2.0

Avantages de l'utilisation de import par rapport à using:

  • éviter toute ambiguïté dans les appels de fonction (Quoi appeler: ModuleX1.produce_text () ou produc_text () après le rechargement?)
  • pas besoin d'appeler workspace() pour se débarrasser de l'ambiguïté

Inconvénients de l'utilisation de import sur using:

  • un nom complet dans chaque appel pour chaque nom exporté est nécessaire

Modifié: ignoré "accès complet au module, même aux noms non exportés" de "Inconvénients ..." selon la conversation ci-dessous.

10
Maciek Leks

Dans Julia v0.6. il semble que l'utilisation de workspace () est non plus nécessaire: je peux simplement recharger (MyModule) dans une session REPL active, et cela fonctionne comme prévu (les modifications apportées au fichier source qui contient MyModule sont reflétées dans la session REPL) active).

Cela s'applique aux modules qui ont été intégrés dans la portée par import ou sing

8
pragMATHiC

Je voulais créer un nouveau module à partir de zéro, et j'ai essayé les différentes réponses avec 1.0 et je n'ai pas obtenu de résultat satisfaisant, mais j'ai trouvé que ce qui suit fonctionnait pour moi:

Depuis Julia REPL dans le répertoire que je veux utiliser pour mon projet que je lance

pkg> generate MyModule

Cela crée un sous-répertoire comme la structure suivante:

MyModule
├── Project.toml
└── src
    └── MyModule.jl

J'ai mis mon code de module dans MyModule.jl. Je passe dans le répertoire MyModule (ou l'ouvre dans mon IDE) et j'ajoute un fichier Scratch.jl avec le code suivant:

Pkg.activate(“.”)
using Revise
import MyModule

Ensuite, je peux ajouter mon code pour tester ci-dessous et tout se met à jour sans recharger le REPL.

1
Carl Morris