21
$\begingroup$

WRI Technical Support [CASE:4868964]


Preamble

So far I am using Wolfram Workbench (i.e., a plugin to the Eclipse IDE) to develop packages collecting often used Wolfram Language functionality. For some time now, the way to go about developing, testing, and deploying packages has been the Paclet system:

Paclets are units of Wolfram functionality, packaged up in a way that allows them to be discovered, installed, updated, and integrated seamlessly into the Wolfram environment. The essential element that makes a paclet is the PacletInfo.wl file, a small, simple file of metadata that describes the paclet, its requirements, and the ways in which it extends the Wolfram environment.

Unfortunately, starting in Version 12.1 the format of PacletInfo.wl has changed, PacletManager` functions have been added to the System` context and Paclet[...] has become PacletObject[ ...]. For more details and advice I would like to point to the new tech note in Version 13's documentation center.

While the new format will not be compatible with earlier versions of the Wolfram Langauge, the ease of working with paclets makes "going with the flow of development" an appealing option. Alas, Wolfram Workbench and its support for Paclet Development appear rather outdated (e.g., PacletInfo.wl is not recognized as such, the file structure within the package will not match the new default one etc.).

How to Best Use Workbench With the New PacletInfo.wl format?

Let's start by first creating a paclet from within a notebook

Needs["PacletTools`];

$pacletDir = FileNameJoin @ { "D:", "git-local" } (* or wherever you develop... *);

(* if $pacletDir does not yet exist, it needs to be created first *)

obj = PacletObject[ <|
    "Name"           -> "MyFirstPaclet",
    "Version"        -> "0.1",
    "WolframVersion" -> "12.2+", (* paclet will be invisible to earlier versions *)
    "Creator"        -> "My Name <me@domain>",
    "Description"    -> "My first package further developed in Workbench.",
    "Extensions"     -> {
        { "Kernel", "Root" -> "Kernel", "Context" -> { "MyFirstPaclet`" } },
        { "Documentation" }
        (* maybe also { "Path" }? Note, that { "FrontEnd" } does not work in 12.3 *)  
    }
|> ];

CreatePaclet[ obj, $pacletDir ] (* creates files and directory structure *) 

In $pacletDir we will now find the following files and directories:

MyFirstPaclet/
    Documentation/
    Kernel/
        MyFirstPaclet.wl
    PacletInfo.wl
    

QUESTION 1: Upon inspection we note that "Creator" and "Description" information has been dropped and is not contained in PacletInfo.wl. How can this be avoided and are there appropriate ways to come up with a PacletInfo.wl file from within Workbench?

We can now add a project notebook

We can open a new notebook and save it as ProjectNotebook.nb to $pacletDir/MyFirstPaclet/ (i.e., next to where PacletInfo.wl is located). The notebook will be used to test and show the functions contained in the package.

If we were to run a project notebook from outside Workbench, we can do so by adding the following:

PacletDirectoryLoad @ NotebookDirectory[];
PacletDataRebuild[]; (* to make sure that changes in PacletInfo.wl are recognized *)

(* the code above is made an `Initialization Cell`*)

Needs[ "MyFirstPaclet`" ]

SayHello[ "Bob" ] (* this is by default included in MyFirstPaclet.wl :) *)
(* Hello Bob! *)

When we run a project notebook directly from Workbench, as far as I can see, neither PacletDirectoryLoad[ ], PacletDataRebuild[ ] nor Needs[ ] are needed: Simply select ProjectNotebook.nb in the Package Explorer and then right click: Run as > 1 Wolfram). So, when we add another function:

BeginPackage["MyFirstPaclet`"]

...

SayGoodbye

Begin["`Private`"] 

...

SayGoodbye[ ___ ] := Print[ "Goodbye." ]

End[]

EndPackage[]

... and save these changes in the editor, we can immediately use the function in the running ProjectNotebook.nb as is the usual development process in Workbench.

Question 2: How can a project notebook be employed that is automatically created by Workbench, e.g., when you select the main directory and run the project as is usually the case in Workbench?

Question 3: How to best deploy a paclet from Workbench?

$\endgroup$
10
  • 2
    $\begingroup$ For further reference one must of course point at Szabolcs excellent posts 132064 and the linked posts as well. In comparison we see the changes that the Paclet system has undergone. $\endgroup$
    – gwr
    Oct 21, 2021 at 16:52
  • 4
    $\begingroup$ Good question! I'm waiting until 13. comes out for the Paclet Repo before I dig in but I think the big thing will be that you don't need Workbench for paclet dev. $\endgroup$
    – b3m2a1
    Oct 21, 2021 at 17:37
  • $\begingroup$ @b3m2a1 I am aware of the priority given to Notebook development. But my personal preference (want) still remains: Code development -> Workbench, Documentation development -> Notebook. $\endgroup$
    – gwr
    Oct 21, 2021 at 18:16
  • 2
    $\begingroup$ @b3m2a1 Imagine merging two git branches together when working with notebooks ... This is the situation I'm in now (documentation only), and it's a major pain to sort out the differences ... For as long as everything is linear, incremental changes to a file, there's no problem. But as soon as you get divergent branches, notebooks become a major inconvenience. $\endgroup$
    – Szabolcs
    Oct 21, 2021 at 18:53
  • 1
    $\begingroup$ Just adding a cross-reference to another way to build paclets and documentation. $\endgroup$
    – user21
    Jul 8, 2022 at 6:49

1 Answer 1

10
$\begingroup$

A New Kind of Tutorial

Since some time has passed now without getting any answers, I have experimented myself using

$Version
(* 12.3.1 for Microsoft Windows (64-bit) (June 19, 2021) *)

and

Eclipse IDE for Java Developers
Version: Neon.3 Release (4.6.3)
Build id: 20170314-1500

Plugin: Wolfram Workbench Core (10.1.1087)

So bear with me.

1 Creating Paclets in Wolfram Workbench 3.0 as of v12.2+

1.1 Create a new project

By selecting File>New>Project we can enter the process of creating a new project as usual:

1.1.1 Select a wizard

We may select the Application Project wizard that is well suited for Wolfram Language package development:

1.1.2 Wolfram Language project name and location

Next we create a new project called MyFirstPaclet. We can use the default workspace or a location of our choice. Since I am also using git for version control, I am collecting my projects in a directory called \git-local. Using the Browse... button I can create a new subdirectory \git-local\MyFirstPaclet and select it as Location:

1.1.3 Project References

In the next dialog we are asked for referenced projects—I will skip this for our minimal example by choosing Next >.

1.1.4 Application details

Finally, we need to give the application name which I also set to MyFirstPaclet. I will leave the default choices for the boxes unchanged. Note, that we are not choosing to create PactletInfo.m here—we will take care of this manually later on.

Upon selecting Finish we should have a project structure that looks like this in the Package Explorer window (note, that I deselected any filters to show all files):

1.2 Adapt the project structure

1.2.1 Modify the project's properties

By right clicking on the project directory in the Package Explorer we can modify the project's properties. The Wolfram entry has <<MyFirstPaclet` listed in the window titled Execution Build Command—we get rid of this and close the dialog with Ok.

1.2.2 Move and delete files

We will not need init.m and can thus delete it. We then move the file MyFirstPaclet.m into the directory \Kernel and we then rename (Refactor>Rename in the context menu) it to MyFirstPaclet.wl to be on the modern side of things; also we do not need the additional directory MyFirstPaclet so we can move the \Kernel directory to the top level and delete the subdirectory \MyFirstPaclet. We also delete the hidden file .WolframResources (it will always be recreated upon changes to the project properties).

Our project structure should by now look like this:

1.3 Create PacketInfo.wl

1.3.1 Create custom PacletInfo file

Select the top level project directory MyFirstPaclet and enter the context menu with a right click to create a new Other... file and select the wizard for PacletInfo File:

In the PacletInfo file wizard dialog we change PacletInfo.m to PacletInfo.wl and enter the paclet name acordingly. We can also deselect the Function Paclet option since we will be completely rewriting the file:

Upon closing the dialog with Finish a PacletInfo.wl file has be added at the top level of our project directory.

1.3.2 Modify PacletInfo.wl

If it is not yet shown in the editor, we can double click the newly created PacletInfo.wl file to enter the editor:

(* Paclet Info File *)

(* created 2021.11.02*)

Paclet[
  Name -> "MyFirstPaclet",
  Version -> "0.0.1",
  WolframVersion -> "6+",
  Extensions -> {
    {"Documentation", Language -> "English"}
}]

As we can see, the format is old and thus we can simply rewrite the Paclet[ ] section to be a PacletObject[ ]:

(* Paclet Info File *)

(* created 2021.11.02*)

PacletObject[
    <| 
        "Name" -> "MyFirstPaclet",
        "Version" -> "0.1",
        "WolframVersion" -> "12.2+", (* paclet will be invisible to earlier versions *)
        "Creator" -> "Bingo S. Little <bsl@domain>",
        "Description" -> "My first paclet developed in Workbench.",
        "Extensions" -> {
           { "Kernel", "Root" -> "Kernel", "Context"-> { "MyFirstPaclet`" } }
        }
    |>
]

2 Developing the paclet

2.1 Writing code

We are now al set and can develop our package. In this simple example we will just edit the main package MyFirstPaclet.wl in the /Kernel directory (to meet the example created in the OP by using CreatePaclet[ ]) as follows:

(* Wolfram Language Package *)

(* Created by the Wolfram Workbench 02.11.2021 *)

BeginPackage["MyFirstPaclet`"]
(* Exported symbols added here with SymbolName::usage *) 

SayHello

Begin["`Private`"]
(* Implementation of the package *)

SayHello[ name_String ] := Print[ "Hello ", name, "!" ]

End[]

EndPackage[]

When we are done we simply save the modified file [Ctrl + s].

2.2 Running code

As is the typical development process, once we have written some code, we can test it by running the project, for example by entering the context menu for our project directory:

Even though the Project Notebook opens rather quickly, we should patiently wait until the Console tab shows Initialization Complete:

As we can see in the Project Notebook, our code works just fine:

While our Run Session is still running, we can add another function to MyFirstPaclet.wl:

(* Wolfram Language Package *)

(* Created by the Wolfram Workbench 02.11.2021 *)

BeginPackage["MyFirstPaclet`"]
(* Exported symbols added here with SymbolName::usage *) 

SayHello

SayGoodbye

Begin["`Private`"]
(* Implementation of the package *)

SayHello[ name_String ] := Print[ "Hello ", name, "!" ]

SayGoodbye[ name_String ] := Print[ "Goodbye ", name, "." ]

End[]

EndPackage[]

Upon saving the modified file [Ctrl + s] the console will automatically load the package again:

And indeed we can immediately test the new code in the project notebook:

3 Deploying the paclet

For what follows I assume that you are going to deploy your paclet to some paclet server. Again please refer to Todd's excellent guide for how to set this up. Personally, I am using a local directory in my \Dropbox directory, which works out nicely.

3.1 Creating a script for deployment

As before, by right clicking on the project directory we add a new file, which we call deployPaclet.wls:

We then open deployPaclet.wls using the Text Editor:

We then enter the following script, which of course has to be adapted, and save it [Ctrl + s]:

#!/usr/bin/env wolframscript

(* deploy the paclet to the local paclet server and update the paclet site files *)
Needs[ "PacletManager`" ]

$localPacletServer = "D:\\Dropbox\\BSLPacletServer" (* the location of the paclet server as needed for CreatPacletArchive[ ] *)

$thisPaclet = "D:\\git-local\\MyFirstPaclet"

CreatePacletArchive[ $thisPaclet, $localPacletServer ]   (* create the .paclet archive *)

PacletManager`BuildPacletSitesFiles[ $localPacletServer ] (* update the paclet site files *)

Now, all we have to do is to tell Workbench that deployPaclet.wls is a script (it does not know by itself ;-) by entering the context menu with a right click for that file and selecting open with other... and Wolfram Script:

CLosing the dialog with Ok will already run the script and upon inspection of the paclet server directory we find:

From now on we should be able to deploy the paclet simply by selecting the script file deployPaclet.wls and pressing F3.

Note: If newer versions of a paclet are added to the paclet server, it may be necessary to remove the older versions before updating the index files. I will check this and append the script later on.

3.2 Using the paclet

If the PacletSite is registered, all one needs to do is to install the paclet once into $UserBasePacletsDirectory by

PacletInstall[ "MyFirstPaclet" ]

Note: There is currently no way to force PacletInstall or PacletInstallSubmit to install paclets into $BasePacletsDirectory, but paclets can be placed there by hand to become visible to all users on the system.

Any notebook that needs the paclet then can use it with Needs[ ]:

Needs[ "MyFirstPaclet`" ]
$\endgroup$
0

Your Answer

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

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