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.addpkg
— Functionaddpkg(mod::Module, name::Symbol, uuid::Union{UUID, String})
Register the package identified by name
with UUID uuid
, as known by mod
.
DataToolkitCore.@addpkg
— Macro@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"
Using extra packages
DataToolkitCore.@require
— Macro@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
.
DataToolkitCore.invokepkglatest
— Functioninvokepkglatest(f, args...; kwargs...)
Call f(args...; kwargs...)
via invokelatest
, and re-run if PkgRequiredRerunNeeded
is returned.
See also: @require
.
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