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)
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)
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)
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
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)
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()
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()
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)
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)
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)
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)
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)
def test_invalid_local_path(self): with self.assertRaises(ValueError): resolve_path_or_url(str(uuid.uuid4()))
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
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)
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)
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)
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)
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
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)
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")