5
$\begingroup$

As explained in $Path hijacked by PacletManager? loading packages from custom directories may not be so intuitive. Not to mention absolute lack of documentation of interaction between $Path, PacletDirectoryAdd, paclet's version etc.

Recent update to linked question explains something that hit me hard lately:

The problem

If you have MyPackage` (V2) paclet installed in the default repo and MyPackage` (V1) in a customDir. Then:

PrependTo[ $Path, customDir];
PacletManager`PacletDirectoryAdd @ customDir;

<< MyPackage`

will still load MyPackage` V2 from the default repo.

I find this unexpected and really problematic because I failed to find a general enough way to manage this.

Real world use case

Let's say you are working on a dev branch developing V2.x. Part of testing involves packing it and installing locally, which means there will be V2.x in the default repo.

But before finishing V2.x you need to push a fix to V1 so you create another fix branch from the master branch (V1). You would like to load your code, but surprise, it loads V2.x from the default repo despite your changes to the $Path and paclet directories.

Questions

  • How to make sure that MyPackage` will be loaded from the customDir?

  • MyPackage` may contain 3rd part packages inside, e.g. MyPackage/WL/GitLink which it loads internally e.g. by temporarily blocking $Path and prepending MyPackage/WL. However, GitLink may already be installed locally, newer or older, does not matter, the one from customDir/MyPakcage/WL should be loaded. Which means the solution can't be based on fixing the issue for MyPackage` only.

  • On the other hand MyPackage` may require dependencies which are in the default repo so we can't just shield it off.

cross posted in community.wolfram.com

$\endgroup$
  • $\begingroup$ I think this is a fundamentally hard problem and I’m not sure with the existing context-based symbol lookup structure this necessarily is possible in general. I suppose the raw loading may be fixable with some work but I’m not sure what to do if a newer version of the package has already been loaded. In that case you’d need some form of kludge to mangle the names or move to a custom package structure that provides all its methods encapsulated on an object that you can take different versions of. $\endgroup$ – b3m2a1 Sep 21 '18 at 20:15
2
$\begingroup$

While delving in the clutter which

Trace[<<MyPackage`, TraceInternal -> True]

returned to me, I have spotted three symbols which seem to be involved in the question.

The first one is PacletManager`Manager`Private`$pathMap, which stores an Association between contexts and Paclets to load.

The second one is PacletManager`Manager`Private`getPathMap. getPathMap[] checks whether $pathMap is an Association and if not, it calls the third symbol of interest PacletManager`Manager`Private`rebuildPathMap.

rebuildPathMap[] seems to, well, rebuild $pathMap :).

So, the first solution having come to my mind is to Block $pathMap and temporarily delete all MyPackage paclets from it:

Block[
  {
    PacletManager`Manager`Private`$pathMap = Delete[
      PacletManager`Manager`Private`$pathMap,
      "MyPackage`"
    ]
  },
  << MyPackage`
]

This seems to force MMA to look for the package in the old fashion, using $Path. Well, at least it has solved the problem for the project which is currently opened in Wolfram Workbench on my machine. I hope, it can be of use for you either.

Unfortunately, I am pushed for time now and cannot investigate

Trace[<<MyPackage`, TraceInternal -> True]

deeper now.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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