DataDeps.jl

repository·master·Indexed 41 days ago

https://github.com/oxinabox/datadeps.jl

A Julia package for repeatable data setup, providing a mechanism to manage and fetch data dependencies reliably for reproducible research and science. It allows developers to register static data via a declarative block and access it using the `datadep"Name"` macro, handling automatic downloading and path resolution.

Tokens
4.4K
Snippets
12
Records
26
Agent score
100%

What's inside DataDeps.jl

  1. Overview of DataDeps.jl

    master
    DataDeps.jl is a package designed for repeatable data setup in Julia, facilitating reproducible data science by managing the downloading and fetching of data dependencies. It provides a standardized way to ensure that the data required by a project is fetched and available in a consistent manner.
  2. Register a data dependency as a ManualDataDep

    master
    If you have a data dependency that is directly included within a git repository (rather than being hosted at an external URL), you can register it using the ManualDataDep abstraction. This allows DataDeps.jl to manage and provide access to the data locally within the repository structure.
  3. Use recursive structures in DataDep registration

    master

    The fetch_method, post_fetch_method, and hash fields can match the structure of remote_path. If remote_path is a vector, these fields can be a single value applied to all elements, or a vector of the same length applied element-wise.

    This allows for granular control, such as providing different checksums per file or applying different extraction methods to different files in a list.

    # Example: Different post-fetch methods for different files
    register(DataDep("eg", "eg message",
        ["http://example.com/text.txt", "http://example.com/sub1.zip", "http://example.com/sub2.zip"]
        post_fetch_method = [identity, file->run(`unzip $file`), file->run(`unzip $file`)]
    ))
    
    # Example: Nested recursive structure
    register(DataDep("eg", "eg message",
        ["http://example.com/text.txt", ["http://example.com/sub1.zip", "http://example.com/sub2.zip"]]
        post_fetch_method = [identity, file->run(`unzip $file`)]
    ))
  4. Understand the DataDeps.jl Load Path

    master

    The Load Path is the ordered list of directories DataDeps.jl searches to resolve a data dependency. If the data is not found in any of these paths, DataDeps.jl will attempt to download it.

    The Load Path is composed of three sources:

    1. Package load path: Determined by the specific package where the datadep"NAME" was invoked.
    2. User defined load path: Determined by the DATADEPS_LOAD_PATH environment variable (a colon-separated list).
    3. Standard load path: System-specific locations (e.g., home directory, shared system folders). This can be disabled by setting DATADEPS_NO_STANDARD_LOAD_PATH=true.

    Behavioral differences:

    • Loading data: Searches the paths in order for a readable folder.
    • Saving data: Searches the paths in order (skipping the package load path) for a writable directory.

    You can move data between any folders in the load path without needing to redownload it.

  5. How to handle dynamic data with DataDeps.jl

    master

    DataDeps.jl is designed for static data and does not provide built-in versioning for the data itself. If your data changes, DataDeps.jl cannot force users to download new copies automatically.

    If you need to manage dynamic data, consider these workarounds:

    • Manual Refresh: Use a deps/build.jl script to run rm(datadep"MyData", recursive=true, force=true) during package updates to force a re-download.
    • Versioned Names: Treat each version of the data as a unique DataDep with a different name.
    • Git Integration: If the data is small and plain-text, store it in your repository's deps/data/ folder and use a ManualDataDep to reference it. This avoids the need for manual installation when the package is installed via Git.
  6. How to handle multiple DataDeps with the same name

    master

    If multiple packages use the same DataDep name, DataDeps.jl may load the wrong one. To prevent this, you can move a package's specific data dependency into its own package directory under deps/data/.

    For example, a dependency located at ~/.julia/v0.6/EXAMPLEPKG/deps/data/EXAMPLEDATADEP/ will be visible only to EXAMPLEPKG and will not conflict with other packages using the name EXAMPLEDATADEP.

    Note on file-level loading: If you use datadep"Name/subfolder/file.txt" and the file is not in the first folder found with that Name, DataDeps.jl will present a recovery dialog. The easiest fix is to select the option to delete the folder and retry, which forces DataDeps to check the next folder in the load path.

  7. Create custom AbstractDataDep types

    master

    While most use cases are covered by ManualDataDep or standard automatic DataDep types, you can extend DataDeps.jl by defining your own AbstractDataDep types. This is useful for complex workflows that require:

    1. Additional Validation: Performing checks after the download is complete and the post_fetch_method has run.
    2. Data Synthesis: Steps that require working with multiple files simultaneously (which exceeds the capabilities of the standard post_fetch_method).
    3. Hybrid Workflows: Implementing a SemiManualDataDep pattern where some steps are user-driven and others are automated.

    To implement a custom type, you can model it after the existing ManualDataDep implementation or encapsulate an existing DataDep as an element within your new type.

  8. Quickstart: Using DataDeps.jl to manage data

    master

    DataDeps.jl simplifies getting static files from a remote server onto a local machine and providing a consistent way for programs to locate them.

    To use data in your project:

    1. Host your data anywhere that provides an open HTTP/HTTPS link.
    2. Write a DataDep registration block in your package.
    3. Access the data using the datadep"Dataname/file.csv" syntax. DataDeps.jl handles the download and path resolution automatically.
    4. For Continuous Integration (CI) environments, set the DATADEPS_ALWAYS_ACCEPT environment variable to bypass interactive prompts.
    datadep"Dataname/file.csv"
  9. Install DataDeps lazily

    master

    To avoid downloading data unless it is actually needed, ensure the datadep"Name" macro is only evaluated when required. DataDeps only triggers a download when the macro is evaluated.

    Common patterns for lazy installation:

    1. Conditional assignment: Only evaluate the macro if a certain condition (like training_mode) is met.
    2. Function default arguments: Use the macro as a default value for a function parameter. The macro is only evaluated if the user calls the function without providing that argument.
    # Pattern 1: Conditional assignment
    data_folder = training_mode ? datadep"SecurityFootage" : "/srv/webcam/today"
    
    # Pattern 2: Function default arguments
    function predict(path=datadep"SecurityFootage")
        # ...
    end
  10. Migrate to DataDeps 1.0 fetch API

    master

    DataDeps 1.0 refactored the download/fetch API to use Downloads.download() instead of HTTP.jl. If you are upgrading from a version prior to 1.0, you must update your function calls as several wrappers were removed. The default fetch_method is now fetch.

    # Replace removed wrappers with the new fetch API:
    
    # 1. Replace fetch_default(remote, dir)
    fetch(remote, dir)
    
    # 2. Replace fetch_base(remote, dir)
    fetch(remote, dir; update_period=Inf)
    
    # 3. Replace fetch_http(remote, dir; update_period=...)
    fetch(remote, dir; update_period=...)
    
    # 4. If overloading download for custom types:
    # Overload Downloads.download(::YourType) instead of Base.download(::YourType)
  11. Install DataDeps eagerly

    master

    To ensure data is installed as soon as the package is loaded, place the datadep"Name" macro inside the package's __init__ function (immediately after the registration block).

    Warning: Do not place the macro at the global scope, as it will run before __init__ and cause an error.

    If you need to install data at Pkg.build time via deps/build.jl, you must set the environment variable ENV["DATADEPS_ALWAYS_ACCEPT"]="true" because user I/O (like download prompts) is not possible during the build process.

    function MyPackage.__init__()
        # Registration code goes here
        datadep"MyData" # Eagerly trigger download
    end