Packages in Julia

When experimenting and writing new code a package structure seems to be an overkill, but as a project matures the package structure provides some advantages (imho).

First let us look how a package MyPackage looks like in Julia

> ls MyPackage
.git
.github/workflows
docs
src
test
.gitignore
LICENSE
Project.toml
Manifest.toml
README.md

/src

ls /src
MyPackage.jl

its the folder where your code will live. In a newly initiallized package there will be always the file MyPackage.jl. This is the base file where the code lives or you import the code that lives in different files.

/docs

the folder where the documentation will be generated automatically from the docstrings written in your code.

/test

ls /test
runtests.jl

folder containing the tests of your code. Tests are snippets of code meant to test your functions. The basic file here is called runtests.jl, this is the file that will be executed by the CI. For example, say you have the following function in your package

function f(a, b)
    return a + b
end

then in /test/runtests.jl

using Test
using MyPackage

@test f(1, 1) == 2
@test f(1.0, 1.0) == 2.0

Tests are very important when you develop code. You can run them locally once you have activated your package environment with ]test.

/.github/workflows

this file will be generated for you automatically from PkgTemplates.jl. This will instruct GitHub (or any other git website) to run your tests in /test everytime you push a new version of your code.

Project.toml & Manifest.toml

This project file together with Manifest.toml are central for the package manager of Julia (Pkg.jl). Project.toml describes your package on a high level, such as the author, the name, the version of the package, its depencencies and compatibility constraints. Moreover, it uses uuid’s (universally unique identifiers) for the project and dependencies.

With this file the package dependencies are fully covered and whoever has this can run your code in a new environment without a problem (compare this to the package-hell of python). when you add a new package dependency with ]add NewPackage, Julia updates these two files automatically. Read more on these two files here.

Activating your Package

Having all your code under a common roof enables you to use julia’s builtin virtual environments which will allow julia to take care of package dependencies for you automatically. You can activate the environmet by doing in the REPL

> cd MyPackage
> julia

(push "]")

(@v1.10) pkg> activate .
 Activating project at `path`
(MyPackage) pkg>

(push backspace)

>

(when you push the button “]” the Julia REPL changes into Pkg mode)

Creating a Package

Usually the workflow of creating a package would be very tedious if you had to write the CI files yourself yadayada. But! There exists a package that does everything for you, PkgTemplates.jl. Add it in your Julia REPL and then do

using PkgTemplates
t=Template(;
           user="svretina", #username
           dir="/home/svretina/Codes/PhD/", # directory where your package will be
           authors="Stamatis Vretinaris", # your name
           julia=v"1.10", # julia version
           plugins=[
               !CompatHelper,
               License(; name="GPL-3.0+"), # choose a License you like
               Git(; manifest=true, ssh=true), # This choise is for Github
               GitHubActions(; # this will enable CI
                   destination="CI.yml", 
                   linux=true,
                   osx=false,
                   windows=false,
                   x64=true,
                   x86=false,
                   coverage=true,
                   extra_versions=["1.10", "nightly"]),
               Codecov(), # coverage of your code for tests
               Documenter{GitHubActions}(),
               Develop(),
           ],
       )
t("MyPackage")

Now in your dir you should have a folder named MyPackage

> ls dir/MyPackage
drwxr-xr-x. 24 svretina svretina 4.0K May 25 19:43 ..
-rw-r--r--.  1 svretina svretina   62 May 25 19:43 .gitignore
drwxr-xr-x.  3 svretina svretina 4.0K May 25 19:43 .github
-rw-r--r--.  1 svretina svretina  35K May 25 19:43 LICENSE
-rw-r--r--.  1 svretina svretina  574 May 25 19:43 README.md
drwxr-xr-x.  2 svretina svretina 4.0K May 25 19:43 src
drwxr-xr-x.  2 svretina svretina 4.0K May 25 19:43 test
-rw-r--r--.  1 svretina svretina  231 May 25 19:43 Project.toml
-rw-r--r--.  1 svretina svretina  186 May 25 19:44 Manifest.toml
drwxr-xr-x.  7 svretina svretina 4.0K May 25 19:44 .
drwxr-xr-x.  3 svretina svretina 4.0K May 25 19:44 docs
drwxr-xr-x.  7 svretina svretina 4.0K May 25 19:44 .git

Great success! (preferably read in Borat voice)

> cat src/MyPackage.jl
module MyPackage

# Write your package code here.

end

> cat Project.toml
name = "MyPackage"
uuid = "d8d250fd-c730-497c-b513-464b22078937"
authors = ["Stamatis Vretinaris"]
version = "1.0.0-DEV"

[compat]
julia = "1.10"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test"]

Connecting your Package to GitHub

You need to create a new repo in GitHub online. Make sure to not forget to add .jl to the name of your package, or make sure you have the same name in your local folder and in your git repo online.

Usually you would have to do

> git init
> git commit -m "first commit"
> git branch -M master
> git remote add origin git@github.com:svretina/MyPackage.git

but this has been taken care for you by PkgTemplates.jl.

> git config --get remote.origin.url
git@github.com:svretina/MyPackage.jl.git

It’s already configured! You only need to push your files to the repo@GitHub!

> git push -u origin master
Enumerating objects: 23, done.
Counting objects: 100% (23/23), done.
Delta compression using up to 8 threads
Compressing objects: 100% (19/19), done.
Writing objects: 100% (23/23), 15.73 KiB | 2.25 MiB/s, done.
Total 23 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To github.com:svretina/MyPackage.jl.git
 * [new branch]      master -> master
branch 'master' set up to track 'origin/master'.

Some Git shugah

When you browse all of these cool libraries they have these nice colorfull buttons saying docs|stable or docs|dev or CI|passing etc. PkgTemplates.jl gots your back and you automatically have these nice thingies in your README.md file that was generated.

MyPackage

Stable Dev Build Status Coverage

More on namespaces and code tips for julia and packages in the next post.