8
$\begingroup$

I am in the process of writing a package, but my way of testing it just seems wrong and inefficient. Each time I edit the .m file, I save it, quit the kernel, call the package in a separate notebook and proceed to test.

Is there a more efficient way to test a package without having to save/quit kernel/rerun everything??

Thanks

$\endgroup$
3
  • $\begingroup$ Have a look at the Workbench. $\endgroup$ Commented Aug 16, 2014 at 15:17
  • 1
    $\begingroup$ <<myFile.m or Get["myFile.m"] $\endgroup$
    – user21
    Commented Aug 16, 2014 at 20:22
  • $\begingroup$ Related: (13473) $\endgroup$
    – Mr.Wizard
    Commented Oct 16, 2016 at 0:04

3 Answers 3

7
$\begingroup$

You can just add something like

ClearAll["MyPackage`*", "MyPackage`*`*"]

to the beginning of the package. Then you don't have to restart the kernel, just re-load the package the most convenient possible way (<<mypackage.m or if you edit it in the front end, then simply re-run it).

You need to be more cautious if your package maintains some sort of internal state or if it dynamically adds definitions to symbols (e.g. closures).

$\endgroup$
1
  • $\begingroup$ This is the way to go. One small suggestion: In a package you either have functions that are exported or those that are local. I'd put the ClearAll in the package before the local function. That way anyone who uses the package can just Get it and does not need to know that a ClearAll should be called first. $\endgroup$
    – user21
    Commented Aug 17, 2014 at 6:35
2
$\begingroup$

General

Some time ago, I wrote a package specifically to address this issue. It is named PackageManipulations and described in this post. The package can be imported as

Import["http://www.mathprogramming-intro.org/download/packages/PackageManipulations.m"]

It has an accompanying notebook with detailed explanations of how to use it, but I will give a brief summary here.

PackageManipulations package

The main functions in the package are PackageClear, PackageClearComplete, PackageReload, and PackageRemove. They do what they say.

Reloading the package

Use

PackageReload[your-package-context], 

to reload your package. Note that PackageReload calls PackageClearComplete (described below), and thus clears previous definitions that symbols in your package's context and its sub-contexts may have had (but does not remove the symbols). Thus, this should be the most frequently used tool in the context of package testing.

You may call

PackageReload[your-package-context, KillShadowing -> True]

if you want to resolve some existing shadowing conflict in favor of the symbol in the package being reloaded - the other symbol will then be Removed.

Clearing the symbols in the package without removing them.

If you just want to clear all the names of all symbols in the context of your package, but keep the package' s context and symbol names in the system, you can call

PackageClear[your-package-context]

To clear (but not remove) the context together with all sub - contexts, use

PackageClearComplete[your-package-context]

Removing the package from the system

To remove the context and all its sub-contexts, use PackageClearComplete with the RemovePackage -> True option :

PackageClearComplete[your-package-context, RemovePackage -> True]

A somewhat lower-level function to remove all package symbols and the entire package from the system is PackageRemove:

PackageRemove[your-package-context]

It Removes all the symbols in the specified context, and also removes the context from $ContextPath and $Packages, if it is there. It does not, however, deal with sub-contexts, so the proper way to completely remove the package from the system is to call PackageClearComplete with the RemovePackage -> True option, as mentioned above.

Note that removal is not an innocent operation, since all definitions outside the package being removed, which referenced some of the symbols in the package, will be permanently invalidated, until those definitions themselves are reloaded. Clearing definitions but keeping the symbols does not lead to this issue.

Notes

The linked notebook contains more detailed explanations and examples.

The package is rather old, and may not work in some cases. If something does not work, let me know, and I will make sure to fix the issue.

$\endgroup$
2
  • $\begingroup$ Hi @Leonid, I found your package very useful. However, I have some computations which are done in Parallel and therefore I do ParallelEvaluate[Get["mypackage.m"]. In this case, your PackageClearComplete is not working for me, even if I evaluate it in Parallel. Some symbols remain with values. Can you help me with that? $\endgroup$
    – Santiago
    Commented Feb 7, 2016 at 20:10
  • 1
    $\begingroup$ Hi @Santi, glad it helps. Re: parallel - alas, I won't have time to look into that for a while. My guess is that you have to clear things both on the parallel sub-kernels and the master kernel. Shared symbols might be trickier still. I will keep this in mind though. At some point soon, I will put the package on github, so that it will be open for pull requests. $\endgroup$ Commented Feb 7, 2016 at 20:26
0
$\begingroup$

This is how I do it assuming that your package has an exported function called myExportedGUIOrFunctionTestScript. Everytime you click on the button the package is loaded and the results of your test function is placed in a new notebook. This approach has benefits and weaknesses. I'll let the community help on the evaluation of this solution.

myExportedGUIOrFunctionTestScript := "myPkgFunction tested on " <> DateString[]

nbCmd[Button["Reload My Package",
   NotebookClose[bvnb];
   Get[ToFileName[{$HomeDirectory, 
      "WolframWorkspaces\\base\\myPkg\\myPkg"}, "myPkgMFile.m"]];
   bvnb = CreateDocument[myExportedGUIOrFunctionTestScript]
   , Method -> "Queued"
   ]
  , Saveable -> False
  , WindowSize -> All
  , WindowMargins -> {{Automatic, 0}, {Automatic, 0}}
  , WindowTitle -> "Testing My Package"
  ];

Other users may argue that the Workbench has a formal way of testing functions. The reason why I don't use it is because somethimes that formal process may get "out-of-synch" and there is no way to know about that but after you get tired of "fixing" your code. So, my experience has driven me to do things this way.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.