Skip to main content

SciCD

WARNING: this package is in alpha, breaking changes are to be expected

What is it?

SciCD executes scientific workflows as CI/CD pipelines.

To do so, the package transpiles locally executable workflows to CI/CD pipelines

Supported workfow languages:

Supported CI/CD platforms:

Installation

Give the following a shot:

pip install scicd

Why would I want that?

Scalability

  • CI/CD schedulers can distribute jobs across computing environments, letting you preprocess on a Slurm cluster, analyze on a cloud Kubernetes cluster, and visualize on your laptop. Just deploy the open-source gitlab-runner in your computing environments of choice. SciCD syncs workflow outputs across environments by using an rclone-compatible remote store.

Reproducibility

  • CI/CD execution is containerized and tied to version control. Every exeucution is reproducible.

Portability

  • By abstracting at-scale execution to CI/CD, workflow repositories remain lightweight and locally executable.

How does it work?

Let's see a simple example. This is examples/luigi_examples/simple.

To get started, you'll have to register your computer as a Docker executor in your Gitlab instance. For instructions on how to do this, check out the Gitlab documentation.

Now consider the following Luigi workflow in a file called workflow.py. We've added some in-place configuration, but importantly this is still just Luigi and you can run it in all the ways Luigi is capable of.

However, taking advantage of CI/CD, we've indicated we want to run both tasks on a runner with the tag pc in the python:3.12 container image.

import os
import luigi

# Modified from: https://luigi.readthedocs.io/en/stable/tasks.html
PATH_OUTPUT = os.environ["PATH_OUTPUT"]


class GenerateWords(luigi.Task):
    # We added this
    scicd = {"image": "python:3.12", "tags": ["pc"]}

    words = luigi.ListParameter(default=("apple", "banana", "grapefruit"))

    def output(self):
        return luigi.LocalTarget(f"{PATH_OUTPUT}/words.txt")

    def run(self):
        # write a dummy list of words to output file
        self.output().makedirs()
        with self.output().open("w") as f:
            for word in self.words:
                f.write(f"{word}\n")


class CountLetters(luigi.Task):
    # We added this
    scicd = {"image": "python:3.12", "tags": ["pc"]}

    def requires(self):
        return GenerateWords()

    def output(self):
        return luigi.LocalTarget(f"{PATH_OUTPUT}/letter_counts.txt")

    def run(self):

        # read in file as list
        with self.input().open("r") as infile:
            words = infile.read().splitlines()

        # write each word to output file with its corresponding letter count
        self.output().makedirs()
        with self.output().open("w") as outfile:
            for word in words:
                outfile.write(
                    "{word} | {letter_count}\n".format(
                        word=word, letter_count=len(word)
                    )
                )

You'll also notice we use an environment variable as the base directory for our outputs. This is a desirable pattern so you can set different outputs paths depending on where the code is executing. We can set executor-specific environment variables with SciCD by adding a root file called scicd_executors.py. This file will be automatically detected by scicd, and gives you a chance to inject environment variables relevant for a specific execution environment. The method receives a TaskConfig object which stores information like the image, tags and resource requests (e.g. cpu). In Kubernetes or Slurm execution environments, you might want to translate these resources into relevant environment variables. See examples/luigi_examples/kubernetes for more. For now, we keep it simple and just inject our PATH_OUTPUT variable.

from typing import Dict

from scicd.config import TaskConfig
from scicd.executor import register_executor


@register_executor(tags=["pc"])
def pc(cfg: TaskConfig) -> Dict[str, str]:
    return {"PATH_OUTPUT": "/path/to/local/output"}

We also want to ensure that luigi is installed in the python:3.12 container. We can do that by configuring SciCD with a root scicd.yaml file. There's a lot you can do with this file. Here, we're using the workspace.cicd key to just inject arbtrary Gitlab CI/CD boilerplate, but you can also specify task configuration, remote syncing, and more with this file. See the examples!

workspace:
  cicd:
    # This is Gitlab syntax
    default:
      before_script:
        - pip install luigi

Now we're ready to convert this workflow to a .gitlab-ci.yml file!

scicd luigi build --module workflow --task CountLetters --backend gitlab

Out comes the following:

default:
  before_script:
  - pip install luigi
stages:
- stage_0
- stage_1
GenerateWords:words=["apple","banana","grapefruit"]:
  image: python:3.12
  tags:
  - pc
  stage: stage_0
  variables:
    PATH_OUTPUT: /path/to/local/output
  needs: []
  script:
  - PYTHONPATH=. luigi --module luigi_examples.simple.simple GenerateWords --GenerateWords-words='["apple", "banana", "grapefruit"]' --local-scheduler
CountLetters:
  image: python:3.12
  tags:
  - pc
  stage: stage_1
  variables:
    PATH_OUTPUT: /path/to/local/output
  needs:
  - GenerateWords:words=["apple","banana","grapefruit"]
  script:
  - PYTHONPATH=. luigi --module luigi_examples.simple.simple CountLetters --local-scheduler

For more guidance, please look at the examples!

Limitations

While we plan on supporting Github Actions compilation, this has not yet been implemented.

In addition, the transpiler is static and cannot detect dynamic aspects of workflows (like a Luigi task generating additional tasks at runtime). This means dynamic tasks will run in the same job as the discoverable static parent task, and that highly dynamic workflows will be less amenable to the sort of distributed computation unlocked by Ci/CD.

Metadata

Release files for scicd 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for scicd 0.0.1
File Size Uploaded Provenance Actions
scicd-0.0.1.tar.gz 25.8 kB Without provenance Details for scicd-0.0.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for scicd 0.0.1
File Interpreter ABI Platform Actions
scicd-0.0.1-py3-none-any.whl Python 3 none any Details for scicd-0.0.1-py3-none-any.whl

Total release size: 57.9 kB

Release files / scicd-0.0.1.tar.gz

Download URL scicd-0.0.1.tar.gz
Size 25.8 kB
Tags Source
SHA-256 checksum
How to use checksums
326812ec73245e61e254ff08ab9b753e8e5df652584e618a245630afce3b0893
BLAKE2b-256 checksum
How to use checksums
fc68336630d38ca78442eb48979c76501c075dd86cf36e4513c4fe5f9b820cf9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / scicd-0.0.1-py3-none-any.whl

Download URL scicd-0.0.1-py3-none-any.whl
Size 32.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
112df459c8c8b7e917c2e1b897ac8b15df3a97f8c7337b8d711f00416fa945d6
BLAKE2b-256 checksum
How to use checksums
e87b46e3d529d946c033d406b6b0cc7b9a64742a2aaf3ce69f8b2ee8df928c7d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for scicd 0.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page