Lazily using packages

It is entirely likely that in the course of writing a package providing a custom data transformer, one would come across packages that may be needed.

Every possibly desired package could be shoved into the list of dependences, but this is a somewhat crude approach. A more granular approach is enabled with two macros, @addpkg and @require.

Letting DataToolkit know about extra packages

DataToolkitCore.@addpkgMacro
@addpkg name::Symbol uuid::String

Register the package identified by name with UUID uuid. This package may now be used with @require $name.

All @addpkg statements should lie within a module's __init__ function.

Example

@addpkg CSV "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"

See also: @require, addpkg.

source

Using extra packages

DataToolkitCore.@requireMacro
@require Package
@require Package = "UUID"

Require the package Package, either previously registered with @addpkg or by UUID.

This sets a variable Package to the module of the package.

If the package is not currently loaded, DataToolkit will attempt to lazy-load the package via an early return PkgRequiredRerunNeeded singleton. So long as this is seen by a calling invokepkglatest the package will be loaded and the function re-run.

See also: @addpkg, invokepkglatest.

source

Example

module DataToolkitExample

using DataToolkitCore
using DataFrame

function __init__()
    @addpkg CSV "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
    @addpkg DelimitedFiles "8bb1440f-4735-579b-a4ab-409b98df4dab"
end

function load(::DataLoader{:csv}, from::IOStream, ::Type{DataFrame})
    @require CSV
    result = CSV.read(from, DataFrame)
    close(from)
    result
end

function load(::DataLoader{:delimcsv}, from::IOStream, ::Type{DataFrame})
    @require DelimitedFiles
    result = DelimitedFiles.readdlm(from, ',', DataFrame)
    close(from)
    result
end

end

Packages that implement loaders with other packages are recommended to use Julia 1.9's Package Extensions, together with the @requires macro and invokelatest like so:

# CsvLoaderPkg/src/loader.jl
function load(::DataLoader{:csv}, from::IOStream, t::Type{DataFrame})
    @require CSV
    invokelatest(_load_csv, from, t)
end
# CsvLoaderPkg/ext/csv.jl
module csv

using CSV
import CsvLoaderPkg: _load_csv

function _load_csv(from::IOStream, ::Type{DataFrame})
    result = CSV.read(from, DataFrame)
    close(from)
    result
end

end