Esempio n. 1
0
    def test_valid_local_path(self):
        with tempfile.NamedTemporaryFile() as tfn:
            abspath = os.path.realpath(tfn.name)
            _, name, baseurl = resolve_path_or_url(abspath)
            self.assertEqual(name, os.path.basename(abspath))
            self.assertEqual("file://{}".format(os.path.dirname(abspath)), baseurl)

            cwd = os.getcwd()
            try:
                os.chdir(os.path.dirname(abspath))
                _, name, baseurl = resolve_path_or_url(os.path.basename(abspath))
                self.assertEqual(name, os.path.basename(abspath))
                self.assertEqual("file://{}".format(os.path.dirname(abspath)), baseurl)
            finally:
                os.chdir(cwd)
Esempio n. 2
0
def validate_sptx(experiment_json: str) -> None:
    """validate a spaceTx formatted experiment.
    Accepts local filepaths or files hosted at http links.
    """

    valid = True

    # use slicedimage to read the top-level experiment json file passed by the user
    backend, name, baseurl = resolve_path_or_url(experiment_json)
    with backend.read_file_handle(name) as fh:
        experiment = json.load(fh)

    # validate experiment.json
    experiment_validator = SpaceTxValidator(_get_absolute_schema_path('experiment.json'))
    valid &= experiment_validator.validate_object(experiment)

    # validate manifests that it links to.
    possible_manifests = []
    manifest_validator = SpaceTxValidator(_get_absolute_schema_path('fov_manifest.json'))
    with backend.read_file_handle(experiment['hybridization_images']) as fh:
        possible_manifests.append(json.load(fh))

    # loop over all the manifests that are stored in auxiliary images. Disallowed names will
    # have already been excluded by experiment validation.
    for manifest in experiment['auxiliary_images'].values():
        with backend.read_file_handle(manifest) as fh:
            possible_manifests.append(json.load(fh))

    # we allow the objects linked from hybridization_images and auxiliary images to either be
    # manifests OR field_of_view files. We distinguish these by checking if they have a `contents`
    # flag, which indicates it is a manifest.
    fovs = []
    for manifest in possible_manifests:
        if 'contents' in manifest:  # is a manifest; validate
            valid &= manifest_validator.validate_object(manifest)

            # contains fields of view
            for fov in manifest['contents']:
                with backend.read_file_handle(fov) as fh:
                    fovs.append(json.load(fh))

        else:  # manifest is a field of view
            fovs.append(manifest)

    # validate fovs
    assert len(fovs) != 0
    fov_validator = SpaceTxValidator(_get_absolute_schema_path('field_of_view/field_of_view.json'))
    for fov in fovs:
        valid &= fov_validator.validate_object(fov)

    # validate codebook
    codebook_validator = SpaceTxValidator(_get_absolute_schema_path('codebook/codebook.json'))
    with backend.read_file_handle(experiment['codebook']) as fh:
        codebook = json.load(fh)
    valid &= codebook_validator.validate_object(codebook)

    if valid:
        sys.exit(0)
    else:
        sys.exit(1)
Esempio n. 3
0
    def from_json(cls, url_or_path: str) -> "TransformsList":
        """
        Load a TransformsList from a json file or a url pointing to such a file
        Loads slicedimage version configuration from :py:class:`starfish.config.StarfishConfig`

        Parameters
        ----------
        url_or_path : str
            Either an absolute URL or a filesystem path to a transformsList.

        Returns
        -------
        TransformsList
        """
        config = StarfishConfig()
        transforms_list: List[Tuple[Mapping[Axes, int], TransformType, GeometricTransform]] = list()
        backend, name, _ = resolve_path_or_url(url_or_path, backend_config=config.slicedimage)
        with backend.read_contextmanager(name) as fh:
            transforms_array = json.load(fh)
        for selectors_str, transform_type_str, transforms_matrix in transforms_array:
            selectors = {Axes(k): v for k, v in selectors_str.items()}
            transform_type = TransformType(transform_type_str)
            transform_object = transformsTypeMapping[transform_type](np.array(transforms_matrix))
            transforms_list.append((selectors, transform_type, transform_object))
        return cls(transforms_list)
Esempio n. 4
0
def validate(experiment_json: str, fuzz: bool=False) -> bool:
    """validate a spaceTx formatted experiment.
    Accepts local filepaths or files hosted at http links.
    Loads configuration from StarfishConfig.

    Parameters
    ----------
    experiment_json : str
        path or URL to a target json object to be validated against the schema passed to this
        object's constructor
    fuzz : bool
        whether or not to perform element-by-element fuzzing.
        If true, will return true and will *not* use warnings.

    Returns
    -------
    bool :
        True, if object valid or fuzz=True, else False

    Examples
    --------
    The following will read the experiment json file provided, downloading it if necessary,
    and begin recursively validating it and all referenced json files (e.g. codebook.json):

        >>> from starfish.core.spacetx_format import validate_sptx
        >>> valid = validate_sptx.validate(json_url)
    """

    config = StarfishConfig()
    valid = True

    # use slicedimage to read the top-level experiment json file passed by the user
    try:
        backend, name, baseurl = resolve_path_or_url(
            experiment_json, backend_config=config.slicedimage)
    except ValueError as exception:
        raise Exception(f"could not load {experiment_json}:\n{exception}")

    with backend.read_contextmanager(name) as fh:
        experiment = json.load(fh)

    # validate experiment.json
    valid &= validate_file(name, "experiment.json", fuzz, backend)

    # loop over all the manifests that are stored in images. Disallowed names will have already been
    # excluded by experiment validation.
    for manifest in experiment['images'].values():
        obj: Dict = dict()
        if not validate_file(manifest, "fov_manifest.json", fuzz, backend, obj):
            valid = False
        else:
            for key, fov in obj['contents'].items():
                valid &= validate_file(fov, 'field_of_view/field_of_view.json', fuzz, backend)

    codebook_file = experiment.get('codebook')
    if codebook_file is not None:
        valid &= validate_file(codebook_file, "codebook/codebook.json", fuzz, backend)

    return valid
Esempio n. 5
0
    def run_command(cls, args):
        _, name, baseurl = resolve_path_or_url(args.in_url)
        slicedimage = Reader.parse_doc(name, baseurl)

        Writer.write_to_path(slicedimage,
                             args.out_path,
                             pretty=args.pretty,
                             tile_opener=fake_file_opener,
                             tile_writer=identity_writer)
Esempio n. 6
0
    def read(self, in_json_path_or_url):
        self.backend, name, self.baseurl = resolve_path_or_url(
            in_json_path_or_url)
        with self.backend.read_file_handle(name) as fh:
            self.org = json.load(fh)

        self.image = ImageStack.from_url(self.org['hybridization_images'],
                                         self.baseurl)
        self._read_aux()
Esempio n. 7
0
def run_recipe(ctx, recipe, input, output):
    """Runs a recipe with a given set of inputs and outputs."""
    config = StarfishConfig()

    backend, relativeurl, _ = resolve_path_or_url(
        recipe, backend_config=config.slicedimage)
    with backend.read_contextmanager(relativeurl) as fh:
        recipe_str = fh.read()

    recipe_obj = Recipe(recipe_str, input, output)
    recipe_obj.run_and_save()
Esempio n. 8
0
    def read(self, in_json_path_or_url):
        self.backend, name, self.baseurl = resolve_path_or_url(
            in_json_path_or_url)
        with self.backend.read_file_handle(name) as fh:
            self.org = json.load(fh)

        self.image = ImageStack.from_url(self.org['hybridization_images'],
                                         self.baseurl)
        for aux_key, aux_data in self.org['auxiliary_images'].items():
            self.auxiliary_images[aux_key] = ImageStack.from_url(
                aux_data, self.baseurl)
Esempio n. 9
0
def validate_file(file: str,
                  schema: str,
                  fuzz: bool = False,
                  backend: Backend = None,
                  output: Dict = None) -> bool:
    """validate a spaceTx formatted file with a given schema.
    Accepts local filepaths or files hosted at http links.

    Parameters
    ----------
    file : str
        path or URL to a target json object to be validated against the schema passed
    schema : str
        resource path to the schema
    backend : slicedimage.backends._base.Backend
        backend previously loaded from a file path or URL,
        or potentially None if a new backend should be loaded.
    fuzz : bool
        whether or not to perform element-by-element fuzzing.
        If true, will return true and will *not* use warnings.
    output : Dict
        dictionary into which the output object can be stored

    Returns
    -------
    bool :
        True, if object valid or fuzz=True, else False

    Examples
    --------
    The following will read the codebook json file provided, downloading it if necessary:

        >>> from starfish.spacetx_format.validate_sptx import validate_file
        >>> valid = validate_sptx.validate_file(json_url, "codebook/codebook.json")
    """

    validator = SpaceTxValidator(_get_absolute_schema_path(schema))

    if backend is None:
        backend, name, baseurl = resolve_path_or_url(file)
    else:
        name = file

    with backend.read_contextmanager(name) as fh:
        obj = json.load(fh)
        if output is not None:
            output.update(obj)

    if fuzz:
        validator.fuzz_object(obj, file)
        return True
    else:
        return validator.validate_object(obj, file)
Esempio n. 10
0
    def from_path_or_url(cls, url_or_path: str) -> "ImageStack":
        """
        Constructs an ImageStack object from an absolute URL or a filesystem path.

        The following examples will all load from the same location:
          1. url_or_path: file:///Users/starfish-user/images/hybridization.json
          2. url_or_path: /Users/starfish-user/images/hybridization.json

        Parameters
        ----------
        url_or_path : str
            Either an absolute URL or a filesystem path to an imagestack.
        """
        _, relativeurl, baseurl = resolve_path_or_url(url_or_path)
        return cls.from_url(relativeurl, baseurl)
Esempio n. 11
0
    def from_path_or_url(cls, url_or_path: str, aligned_group: int = 0) -> "ImageStack":
        """
        Constructs an ImageStack object from an absolute URL or a filesystem path.

        The following examples will all load from the same location:
          1. url_or_path: file:///Users/starfish-user/images/primary_images.json
          2. url_or_path: /Users/starfish-user/images/primary_images.json

        Parameters
        ----------
        url_or_path : str
            Either an absolute URL or a filesystem path to an imagestack.
        aligned_group: int
            Which aligned tile group to load into the Imagestack, only applies if the
            tileset is unaligned. Default 0 (the first group)
        """
        config = StarfishConfig()
        _, relativeurl, baseurl = resolve_path_or_url(url_or_path,
                                                      backend_config=config.slicedimage)
        return cls.from_url(relativeurl, baseurl, aligned_group)
Esempio n. 12
0
    def from_json(cls, url_or_path: str) -> "TransformsList":
        """
        Load a TransformsList from a json file or a url pointing to such a file
        Loads slicedimage version configuration from :py:class:`starfish.config.StarfishConfig`

        Parameters
        ----------
        url_or_path : str
            Either an absolute URL or a filesystem path to a transformsList.

        Returns
        -------
        TransformsList
        """
        config = StarfishConfig()
        backend, name, _ = resolve_path_or_url(
            url_or_path, backend_config=config.slicedimage)
        with backend.read_contextmanager(name) as fh:
            transforms_document = json.load(fh)
        return cls.from_dict(transforms_document=transforms_document)
Esempio n. 13
0
 def test_invalid_local_path(self):
     with self.assertRaises(ValueError):
         resolve_path_or_url(str(uuid.uuid4()))
Esempio n. 14
0
def validate(experiment_json: str, fuzz: bool = False) -> bool:
    """validate a spaceTx formatted experiment.
    Accepts local filepaths or files hosted at http links.

    Parameters
    ----------
    experiment_json : str
        path or URL to a target json object to be validated against the schema passed to this
        object's constructor
    fuzz : bool
        whether or not to perform element-by-element fuzzing.
        If true, will return true and will *not* use warnings.

    Returns
    -------
    bool :
        True, if object valid or fuzz=True, else False
    """

    valid = True

    # use slicedimage to read the top-level experiment json file passed by the user
    backend, name, baseurl = resolve_path_or_url(experiment_json)
    with backend.read_contextmanager(name) as fh:
        experiment = json.load(fh)

    # validate experiment.json
    experiment_validator = SpaceTxValidator(
        _get_absolute_schema_path('experiment.json'))
    if fuzz:
        experiment_validator.fuzz_object(experiment, name)
    else:
        valid &= experiment_validator.validate_object(experiment, name)

    # loop over all the manifests that are stored in images. Disallowed names will have already been
    # excluded by experiment validation.
    manifests = []
    for manifest in experiment['images'].values():
        with backend.read_contextmanager(manifest) as fh:
            manifests.append((json.load(fh), manifest))

    fovs = []
    manifest_validator = SpaceTxValidator(
        _get_absolute_schema_path('fov_manifest.json'))
    for manifest, filename in manifests:
        if fuzz:
            manifest_validator.fuzz_object(manifest, filename)
        else:
            if not manifest_validator.validate_object(manifest, filename):
                valid = False
            else:
                for key, fov in manifest['contents'].items():
                    with backend.read_contextmanager(fov) as fh:
                        fovs.append((json.load(fh), fov))

    # fovs may be empty if the manifests were not valid
    if fovs:
        fov_schema = _get_absolute_schema_path(
            'field_of_view/field_of_view.json')
        fov_validator = SpaceTxValidator(fov_schema)
        for fov, filename in fovs:
            if fuzz:
                fov_validator.fuzz_object(fov, filename)
            else:
                valid &= fov_validator.validate_object(fov, filename)

    # validate codebook
    codebook_validator = SpaceTxValidator(
        _get_absolute_schema_path('codebook/codebook.json'))
    codebook_file = experiment.get('codebook')
    codebook: Dict = {}
    if codebook_file is not None:
        with backend.read_contextmanager(codebook_file) as fh:
            codebook = json.load(fh)
    if fuzz:
        codebook_validator.fuzz_object(codebook, codebook_file)
    else:
        valid &= codebook_validator.validate_object(codebook, codebook_file)

    return valid
Esempio n. 15
0
    def from_json(cls,
                  json_codebook: str,
                  n_round: Optional[int] = None,
                  n_ch: Optional[int] = None) -> "Codebook":
        """Load a codebook from a spaceTx spec-compliant json file or a url pointing to such a file

        Parameters
        ----------
        json_codebook : str
            path or url to json file containing a spaceTx codebook
        n_round : Optional[int]
            The number of imaging rounds used in the codes. Will be inferred if not provided
        n_ch : Optional[int]
            The number of channels used in the codes. Will be inferred if not provided

        Examples
        --------
        Create a codebook from in-memory data::

            >>> from starfish.types import Indices
            >>> from starfish import Codebook
            >>> import tempfile
            >>> import json
            >>> import os
            >>> dir_ = tempfile.mkdtemp()
            >>> codebook = [
            >>>     {
            >>>         Features.CODEWORD: [
            >>>             {Indices.ROUND.value: 0, Indices.CH.value: 3, Features.CODE_VALUE: 1},
            >>>             {Indices.ROUND.value: 1, Indices.CH.value: 3, Features.CODE_VALUE: 1},
            >>>         ],
            >>>         Features.TARGET: "ACTB_human"
            >>>     },
            >>>     {
            >>>         Features.CODEWORD: [
            >>>             {Indices.ROUND.value: 0, Indices.CH.value: 3, Features.CODE_VALUE: 1},
            >>>             {Indices.ROUND.value: 1, Indices.CH.value: 1, Features.CODE_VALUE: 1},
            >>>         ],
            >>>         Features.TARGET: "ACTB_mouse"
            >>>     },
            >>> ]
            >>> # make a fake file
            >>> json_codebook = os.path.join(dir_, 'codebook.json')
            >>> with open(json_codebook, 'w') as f:
            >>>     json.dump(codebook, f)
            >>> # read codebook from file
            >>> Codebook.from_json(json_codebook)
           <xarray.Codebook (target: 2, c: 4, h: 2)>
            array([[[0, 0],
                    [0, 0],
                    [0, 0],
                    [1, 1]],

                   [[0, 0],
                    [0, 1],
                    [0, 0],
                    [1, 0]]], dtype=uint8)
            Coordinates:
              * target     (target) object 'ACTB_human' 'ACTB_mouse'
              * c          (c) int64 0 1 2 3
              * h          (h) int64 0 1

        Returns
        -------
        Codebook :
            Codebook with shape (targets, channels, imaging_rounds)

        """
        backend, name, _ = resolve_path_or_url(json_codebook)
        with backend.read_contextmanager(name) as fh:
            code_array = json.load(fh)
        return cls.from_code_array(code_array, n_round, n_ch)
Esempio n. 16
0
    def from_json(cls, json_url: str, strict: bool=None) -> "Experiment":
        """
        Construct an `Experiment` from an experiment.json file format specifier

        Parameters
        ----------
        json_url : str
            file path or web link to an experiment.json file
        strict : bool
            if true, then all JSON loaded by this method will be
            passed to the appropriate validator

        Returns
        -------
        Experiment :
            Experiment object serving the requested experiment data

        Environment variables
        ---------------------
        STARFISH_STRICT_LOADING :
             If set, then all JSON loaded by this method will be
             passed to the appropriate validator. The `strict`
             parameter to this method has priority over the
             environment variable.

        """
        if strict is None:
            strict = "STARFISH_STRICT_LOADING" in os.environ
        if strict:
            valid = validate_sptx.validate(json_url)
            if not valid:
                raise Exception("validation failed")

        backend, name, baseurl = resolve_path_or_url(json_url)
        with backend.read_contextmanager(name) as fh:
            experiment_document = json.load(fh)

        cls.verify_version(experiment_document['version'])

        _, codebook_name, codebook_baseurl = resolve_url(experiment_document['codebook'], baseurl)
        codebook_absolute_url = pathjoin(codebook_baseurl, codebook_name)
        codebook = Codebook.from_json(codebook_absolute_url)

        extras = experiment_document['extras']

        primary_image: Collection = Reader.parse_doc(experiment_document['primary_images'], baseurl)
        auxiliary_images: MutableMapping[str, Collection] = dict()
        for aux_image_type, aux_image_url in experiment_document['auxiliary_images'].items():
            auxiliary_images[aux_image_type] = Reader.parse_doc(aux_image_url, baseurl)

        fovs: MutableSequence[FieldOfView] = list()
        for fov_name, primary_tileset in primary_image.all_tilesets():
            aux_image_tilesets_for_fov: MutableMapping[str, TileSet] = dict()
            for aux_image_type, aux_image_collection in auxiliary_images.items():
                aux_image_tileset = aux_image_collection.find_tileset(fov_name)
                if aux_image_tileset is not None:
                    aux_image_tilesets_for_fov[aux_image_type] = aux_image_tileset

            fov = FieldOfView(
                fov_name,
                primary_image_tileset=primary_tileset,
                auxiliary_image_tilesets=aux_image_tilesets_for_fov,
            )
            fovs.append(fov)

        return Experiment(fovs, codebook, extras, src_doc=experiment_document)
Esempio n. 17
0
    def open_json(
        cls,
        json_codebook: str,
        n_round: Optional[int] = None,
        n_channel: Optional[int] = None,
    ) -> "Codebook":
        """
        Load a codebook from a SpaceTx Format json file or a url pointing to such a file.

        Parameters
        ----------
        json_codebook : str
            Path or url to json file containing a spaceTx codebook.
        n_round : Optional[int]
            The number of imaging rounds used in the codes. Will be inferred if not provided.
        n_channel : Optional[int]
            The number of channels used in the codes. Will be inferred if not provided.

        Examples
        --------
        Create a codebook from in-memory data
        ::

            >>> from starfish.types import Axes
            >>> from starfish import Codebook
            >>> import tempfile
            >>> import json
            >>> import os
            >>> dir_ = tempfile.mkdtemp()
            >>> codebook = [
            >>>     {
            >>>         Features.CODEWORD: [
            >>>             {Axes.ROUND.value: 0, Axes.CH.value: 3, Features.CODE_VALUE: 1},
            >>>             {Axes.ROUND.value: 1, Axes.CH.value: 3, Features.CODE_VALUE: 1},
            >>>         ],
            >>>         Features.TARGET: "ACTB_human"
            >>>     },
            >>>     {
            >>>         Features.CODEWORD: [
            >>>             {Axes.ROUND.value: 0, Axes.CH.value: 3, Features.CODE_VALUE: 1},
            >>>             {Axes.ROUND.value: 1, Axes.CH.value: 1, Features.CODE_VALUE: 1},
            >>>         ],
            >>>         Features.TARGET: "ACTB_mouse"
            >>>     },
            >>> ]
            >>> # make a fake file
            >>> json_codebook = os.path.join(dir_, 'codebook.json')
            >>> with open(json_codebook, 'w') as f:
            >>>     json.dump(codebook, f)
            >>> # read codebook from file
            >>> Codebook.open_json(json_codebook)
           <xarray.Codebook (target: 2, c: 4, r: 2)>
            array([[[0, 0],
                    [0, 0],
                    [0, 0],
                    [1, 1]],

                   [[0, 0],
                    [0, 1],
                    [0, 0],
                    [1, 0]]], dtype=uint8)
            Coordinates:
              * target     (target) object 'ACTB_human' 'ACTB_mouse'
              * c          (c) int64 0 1 2 3
              * r          (r) int64 0 1

        Returns
        -------
        Codebook :
            Codebook with shape (targets, channels, imaging_rounds)

        """

        config = StarfishConfig()

        backend, name, _ = resolve_path_or_url(
            json_codebook, backend_config=config.slicedimage)
        with backend.read_contextmanager(name) as fh:
            codebook_doc = json.load(fh)

            if config.strict:
                codebook_validator = CodebookValidator(codebook_doc)
                if not codebook_validator.validate_object(codebook_doc):
                    raise Exception("validation failed")

        if isinstance(codebook_doc, list):
            raise ValueError(
                f"codebook is a list and not an dictionary.  It is highly likely that you are using"
                f"a codebook formatted for a previous version of starfish.")

        version_str = codebook_doc[DocumentKeys.VERSION_KEY]
        cls._verify_version(version_str)

        return cls.from_code_array(codebook_doc[DocumentKeys.MAPPINGS_KEY],
                                   n_round, n_channel)
Esempio n. 18
0
    def from_json(cls,
                  json_url: str,
                  strict: bool = None,
                  config: Optional[Union[str, Dict]] = None) -> "Experiment":
        """
        Construct an `Experiment` from an experiment.json file format specifier

        Parameters
        ----------
        json_url : str
            file path or web link to an experiment.json file
        strict : bool
            if true, then all JSON loaded by this method will be
            passed to the appropriate validator
        config : str or dict
            configuration property that will be passed to
            starfish.util.config.Config
        STARISH_CONFIG :
            This parameter is read from the environment to permit setting configuration
            values either directly or via a file. Keys read include:
             - cache.allow_caching
        STARFISH_STRICT_LOADING :
             This parameter is read from the environment. If set, then all JSON loaded by this
             method will be passed to the appropriate validator. The `strict` parameter to this
             method has priority over the environment variable.

        Returns
        -------
        Experiment :
            Experiment object serving the requested experiment data

        """
        if strict is None:
            strict = "STARFISH_STRICT_LOADING" in os.environ
        if strict:
            valid = validate_sptx.validate(json_url)
            if not valid:
                raise Exception("validation failed")

        config_obj = Config(config)  # STARFISH_CONFIG is assumed
        allow_caching = config_obj.lookup(["cache", "allow_caching"], True)

        backend, name, baseurl = resolve_path_or_url(json_url, allow_caching)
        with backend.read_contextmanager(name) as fh:
            experiment_document = json.load(fh)

        version = cls.verify_version(experiment_document['version'])

        _, codebook_name, codebook_baseurl = resolve_url(
            experiment_document['codebook'], baseurl, allow_caching)
        codebook_absolute_url = pathjoin(codebook_baseurl, codebook_name)
        codebook = Codebook.from_json(codebook_absolute_url)

        extras = experiment_document['extras']

        fovs: MutableSequence[FieldOfView] = list()
        fov_tilesets: MutableMapping[str, TileSet] = dict()
        if version < Version("5.0.0"):
            primary_image: Collection = Reader.parse_doc(
                experiment_document['primary_images'], baseurl)
            auxiliary_images: MutableMapping[str, Collection] = dict()
            for aux_image_type, aux_image_url in experiment_document[
                    'auxiliary_images'].items():
                auxiliary_images[aux_image_type] = Reader.parse_doc(
                    aux_image_url, baseurl)

            for fov_name, primary_tileset in primary_image.all_tilesets():
                fov_tilesets[FieldOfView.PRIMARY_IMAGES] = primary_tileset
                for aux_image_type, aux_image_collection in auxiliary_images.items(
                ):
                    aux_image_tileset = aux_image_collection.find_tileset(
                        fov_name)
                    if aux_image_tileset is not None:
                        fov_tilesets[aux_image_type] = aux_image_tileset

                fov = FieldOfView(fov_name, image_tilesets=fov_tilesets)
                fovs.append(fov)
        else:
            images: MutableMapping[str, Collection] = dict()
            all_fov_names: MutableSet[str] = set()
            for image_type, image_url in experiment_document['images'].items():
                image = Reader.parse_doc(image_url, baseurl)
                images[image_type] = image
                for fov_name, _ in image.all_tilesets():
                    all_fov_names.add(fov_name)

            for fov_name in all_fov_names:
                for image_type, image_collection in images.items():
                    image_tileset = image_collection.find_tileset(fov_name)
                    if image_tileset is not None:
                        fov_tilesets[image_type] = image_tileset

                fov = FieldOfView(fov_name, image_tilesets=fov_tilesets)
                fovs.append(fov)

        return Experiment(fovs, codebook, extras, src_doc=experiment_document)
Esempio n. 19
0
def validate(experiment_json: str, fuzz: bool=False) -> bool:
    """validate a spaceTx formatted experiment.
    Accepts local filepaths or files hosted at http links.

    Parameters
    ----------
    experiment_json : str
        path or URL to a target json object to be validated against the schema passed to this
        object's constructor
    fuzz : bool
        whether or not to perform element-by-element fuzzing.
        If true, will return true and will *not* use warnings.

    Returns
    -------
    bool :
        True, if object valid or fuzz=True, else False
    """

    valid = True

    # use slicedimage to read the top-level experiment json file passed by the user
    backend, name, baseurl = resolve_path_or_url(experiment_json)
    with backend.read_contextmanager(name) as fh:
        experiment = json.load(fh)

    # validate experiment.json
    experiment_validator = SpaceTxValidator(_get_absolute_schema_path('experiment.json'))
    if fuzz:
        experiment_validator.fuzz_object(experiment, name)
    else:
        valid &= experiment_validator.validate_object(experiment, name)

    # validate manifests that it links to.
    possible_manifests = []
    manifest_validator = SpaceTxValidator(_get_absolute_schema_path('fov_manifest.json'))
    with backend.read_contextmanager(experiment['primary_images']) as fh:
        possible_manifests.append((json.load(fh), experiment['primary_images']))

    # loop over all the manifests that are stored in auxiliary images. Disallowed names will
    # have already been excluded by experiment validation.
    for manifest in experiment['auxiliary_images'].values():
        with backend.read_contextmanager(manifest) as fh:
            possible_manifests.append((json.load(fh), manifest))

    # we allow the objects linked from primary_images and auxiliary images to either be
    # manifests OR field_of_view files. We distinguish these by checking if they have a `contents`
    # flag, which indicates it is a manifest.
    fovs = []
    for manifest, filename in possible_manifests:
        if 'contents' in manifest:  # is a manifest; validate
            if fuzz:
                manifest_validator.fuzz_object(manifest, filename)
            else:
                valid &= manifest_validator.validate_object(manifest, filename)

            # contains fields of view
            for key, fov in manifest['contents'].items():
                with backend.read_contextmanager(fov) as fh:
                    fovs.append((json.load(fh), fov))

        else:  # manifest is a field of view
            fovs.append((manifest, None))

    # validate fovs
    assert len(fovs) != 0
    fov_validator = SpaceTxValidator(_get_absolute_schema_path('field_of_view/field_of_view.json'))
    for fov, filename in fovs:
        if fuzz:
            fov_validator.fuzz_object(fov, filename)
        else:
            valid &= fov_validator.validate_object(fov, filename)

    # validate codebook
    codebook_validator = SpaceTxValidator(_get_absolute_schema_path('codebook/codebook.json'))
    codebook_file = experiment.get('codebook')
    codebook: Dict = {}
    if codebook_file is not None:
        with backend.read_contextmanager(codebook_file) as fh:
            codebook = json.load(fh)
    if fuzz:
        codebook_validator.fuzz_object(codebook, codebook_file)
    else:
        valid &= codebook_validator.validate_object(codebook, codebook_file)

    return valid
Esempio n. 20
0
    def from_json(cls, json_url: str) -> "Experiment":
        """
        Construct an Experiment from an experiment.json file format specifier.
        Loads configuration from StarfishConfig.

        Parameters
        ----------
        json_url : str
            file path or web link to an experiment.json file

        Returns
        -------
        Experiment :
            Experiment object serving the requested experiment data

        """

        config = StarfishConfig()

        if config.strict:
            valid = validate_sptx.validate(json_url)
            if not valid:
                raise Exception("validation failed")

        backend, name, baseurl = resolve_path_or_url(json_url, config.slicedimage)
        with backend.read_contextmanager(name) as fh:
            experiment_document = json.load(fh)

        version = cls.verify_version(experiment_document['version'])

        _, codebook_name, codebook_baseurl = resolve_url(experiment_document['codebook'],
                                                         baseurl, config.slicedimage)
        codebook_absolute_url = pathjoin(codebook_baseurl, codebook_name)
        codebook = Codebook.open_json(codebook_absolute_url)

        extras = experiment_document['extras']

        fovs: MutableSequence[FieldOfView] = list()
        fov_tilesets: MutableMapping[str, TileSet]
        if version < Version("5.0.0"):
            primary_image: Collection = Reader.parse_doc(experiment_document['primary_images'],
                                                         baseurl, config.slicedimage)
            auxiliary_images: MutableMapping[str, Collection] = dict()
            for aux_image_type, aux_image_url in experiment_document['auxiliary_images'].items():
                auxiliary_images[aux_image_type] = Reader.parse_doc(
                    aux_image_url, baseurl, config.slicedimage)

            for fov_name, primary_tileset in primary_image.all_tilesets():
                fov_tilesets = dict()
                fov_tilesets[FieldOfView.PRIMARY_IMAGES] = primary_tileset
                for aux_image_type, aux_image_collection in auxiliary_images.items():
                    aux_image_tileset = aux_image_collection.find_tileset(fov_name)
                    if aux_image_tileset is not None:
                        fov_tilesets[aux_image_type] = aux_image_tileset

                fov = FieldOfView(fov_name, image_tilesets=fov_tilesets)
                fovs.append(fov)
        else:
            images: MutableMapping[str, Collection] = dict()
            all_fov_names: MutableSet[str] = set()
            for image_type, image_url in experiment_document['images'].items():
                image = Reader.parse_doc(image_url, baseurl, config.slicedimage)
                images[image_type] = image
                for fov_name, _ in image.all_tilesets():
                    all_fov_names.add(fov_name)

            for fov_name in all_fov_names:
                fov_tilesets = dict()
                for image_type, image_collection in images.items():
                    image_tileset = image_collection.find_tileset(fov_name)
                    if image_tileset is not None:
                        fov_tilesets[image_type] = image_tileset

                fov = FieldOfView(fov_name, image_tilesets=fov_tilesets)
                fovs.append(fov)

        return Experiment(fovs, codebook, extras, src_doc=experiment_document)
Esempio n. 21
0
 def test_url(self):
     _, name, baseurl = resolve_path_or_url("https://github.com/abc/def")
     self.assertEqual(name, "def")
     self.assertEqual(baseurl, "https://github.com/abc")