m-labs / artiq

A leading-edge control system for quantum information experiments
https://m-labs.hk/artiq
GNU Lesser General Public License v3.0
434 stars 201 forks source link

Experiment package imports with git integration #1543

Open ljstephenson opened 4 years ago

ljstephenson commented 4 years ago

Question

Making the experiment repository a basic python package and trying to import from other files within it doesn't work in conjunction with git integration; I'm wondering what the canonical way of doing this is.

Category: setup

Description

To elucidate, consider the following example experiment repository:

experiments/
    foo/
        bar.py
    baz/
        qux.py
    __init__.py

qux.py:

from artiq.experiment import *

class Qux(HasEnvironment):
    def build(self):
        pass

    def frobnicate(self):
        print("hello from Qux!")

bar.py:

from artiq.experiment import *
from experiments.baz.qux import Qux

class Bar(EnvExperiment):
    def build(self):
         self.qux = Qux(self)

    def run(self):
         self.qux.frobnicate()

(The reason for having such a structure is that most experiments are composed of repetitive blocks of standard operations, for example state preparation, and these should obviously be reused throughout the more complex composite experiments.)

If this is just on the filesystem, then running artiq_master -r experiments works perfectly, Bar shows up in the dashboard explorer, and running it prints the expected message.

However, if I follow the git integration steps (initialize a bare repository in another directory, say experiments.git, initialise experiments as a repository, configure experiments.git as a remote and push to it), artiq_master -g -r experiments.git fails to load the experiment: the import fails because the module experiments does not exist (relative imports also fail). I understand that this is expected due to the nature of python -- what I don't understand is how one is supposed to make use of the git integration, while also having a sensible codebase that doesn't have unnecessarily duplicated code.

The obvious workaround is to maintain a library of the common functionality that is installed as a standard python package in the conda/nix environment; but then the "building block" type experiments are separate from the "composite" experiments, and composite experiments can easily be building blocks for yet more complicated experiments, so in fact everything may as well reside in this separate package (as we did in Oxford for the HOA2 experiment). At this point the git integration is useless, because all the functionality is no longer in the experiment repository itself, and so its git hash is irrelevant. One would have to look at the run time of the experiment, cross reference with commit times in the external package, and hope that it was in a clean unmodified state when the experiment was run - the exact problem that the git integration seeks to solve.

  1. I'm curious as to other people's experiences: do you use git integration? How are your experiments structured?
  2. Would it be difficult to load the repository as a python package? (I'll confess to not having dived into the source yet to investigate)
  3. EDIT: Have I missed something obvious?
sbourdeauducq commented 2 years ago

Adding a repository path in that situation adds complexity to the code (especially in the GUI)

I see that you basically avoided the difficult parts and just put a "todo" comment in your code for #1805. Better just remove that redundant and messy feature entirely.

b-bondurant commented 2 years ago

Ah, yeah, I forgot about that part. Sounds good.

charlesbaynham commented 2 years ago

Is that [removing the "Open experiment outside repository" feature] necessary?

Definitely. Not only is it redundant, but it is also broken as package imports would not work correctly when it it used. Adding a repository path in that situation adds complexity to the code (especially in the GUI) and does not improve UX compared to adding a file-backed repos

You could just not do anything to PYTHONPATH, and add nothing to the GUI. That way you don't remove a feature that presumably some people do use. You can't use "Open experiment outside repository" to test library-dependent code, but you can't do that currently either, so nothing lost. And we're adding the multiple repository sources test option, to test library-dependent code. I don't have strong feelings about it though.

Multiple repositories can be configured at the same time in the master and dashboard, including repositories backed by bare files, which replaces the "Open experiment outside repository" feature.

This should also support multiple branches / tags / commit ids from the same repository. That's probably the most common way you'd test a feature: by creating a feature branch, testing it out, then merging.

I think going the PYTHONPATH route sounds like the most pragmatic way to get this feature live, so +1 from me!