diff --git a/.github/devops/generate_public_api.py b/.github/devops/generate_public_api.py new file mode 100644 index 000000000..44e3a4010 --- /dev/null +++ b/.github/devops/generate_public_api.py @@ -0,0 +1,55 @@ +import difflib +import sys +from pathlib import Path + +from bsb import _get_public_api_map + + +def public_annotations(): + annotations = [] + for api, module in _get_public_api_map().items(): + annotation = f'"bsb.{module}.{api}"' + if api[0].isupper(): + annotation = f"typing.Type[{annotation}]" + annotations.append(f"{api}: {annotation}") + + lines = [ + "if typing.TYPE_CHECKING:", + *sorted(f" import bsb.{module}" for module in {*_get_public_api_map().values()}), + "", + *sorted(annotations), + "", + ] + + return lines + + +if __name__ == "__main__": + import bsb + + path = Path(bsb.__path__[0]) / "__init__.py" + text = path.read_text() + find = ( + "# Do not modify: autogenerated public API type annotations of the `bsb` module\n" + "# fmt: off\n" + "# isort: off\n" + ) + idx = text.find(find) + annotation_lines = public_annotations() + if idx == -1: + print("__init__.py file is missing the replacement tag", file=sys.stderr) + exit(1) + if "--check" in sys.argv: + diff = "\n".join( + l + for l in difflib.ndiff( + text[idx + len(find) :].split("\n"), + annotation_lines, + ) + if l[0] != " " + ) + print(diff, file=sys.stderr, end="") + exit(bool(diff)) + else: + text = text[:idx] + find + "\n".join(annotation_lines) + path.write_text(text) diff --git a/.github/workflows/api.yml b/.github/workflows/api.yml new file mode 100644 index 000000000..2b912bd30 --- /dev/null +++ b/.github/workflows/api.yml @@ -0,0 +1,21 @@ +name: Check public API + +on: [push, pull_request] + +jobs: + check-documentation: + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v1 + with: + python-version: 3.11 + - name: Setup Python environment + run: | + python -m pip install --upgrade pip + pip install -e . + - name: Check public API + run: python .github/devops/generate_public_api.py --check diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 495dad7c3..3d6832c84 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -9,10 +9,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up Python 3.9 + - name: Set up Python 3.11 uses: actions/setup-python@v1 with: - python-version: 3.9 + python-version: 3.11 - name: Setup software environment run: | sudo apt update diff --git a/bsb/__init__.py b/bsb/__init__.py index 1cacafd2e..dc64497d6 100644 --- a/bsb/__init__.py +++ b/bsb/__init__.py @@ -9,7 +9,12 @@ __version__ = "4.0.0b9" +import ast import functools +import importlib +import sys +import typing +from pathlib import Path # Patch functools on 3.8 try: @@ -43,3 +48,451 @@ def _register(self, cls, method=None): # pragma: nocover if _pr: meter.stop() + + +def _assign_targets(assign: ast.Assign, id_: str): + return any( + target.id == id_ for target in assign.targets if isinstance(target, ast.Name) + ) + + +@functools.cache +def _get_public_api_map(): + root = Path(__file__).parent + + public_api_map = {} + for file in root.rglob("*.py"): + module_parts = file.relative_to(root).parts + module = ".".join( + module_parts[:-1] + + ((module_parts[-1][:-3],) if module_parts[-1] != "__init__.py" else tuple()) + ) + module_api = [] + for assign in ast.parse(file.read_text()).body: + if isinstance(assign, ast.Assign): + is_api = _assign_targets(assign, "__api__") + is_either = is_api or _assign_targets(assign, "__all__") + if ((is_either and not module_api) or is_api) and isinstance( + assign.value, ast.List + ): + module_api = [ + el.value + for el in assign.value.elts + if isinstance(el, ast.Constant) + ] + for api in module_api: + public_api_map[api] = module + + return public_api_map + + +@functools.cache +def __getattr__(name): + if name == "config": + return object.__getattribute__(sys.modules[__name__], name) + api = _get_public_api_map() + module = api.get(name, None) + if module is None: + return object.__getattribute__(sys.modules[__name__], name) + else: + return getattr(importlib.import_module("." + module, package="bsb"), name) + + +def __dir__(): + return [*_get_public_api_map().keys()] + + +# Do not modify: autogenerated public API type annotations of the `bsb` module +# fmt: off +# isort: off +if typing.TYPE_CHECKING: + import bsb.cell_types + import bsb.cli + import bsb.cli.commands + import bsb.config + import bsb.config.parsers + import bsb.config.refs + import bsb.config.types + import bsb.connectivity.detailed.fiber_intersection + import bsb.connectivity.detailed.shared + import bsb.connectivity.detailed.touch_detection + import bsb.connectivity.detailed.voxel_intersection + import bsb.connectivity.general + import bsb.connectivity.import_ + import bsb.connectivity.strategy + import bsb.core + import bsb.exceptions + import bsb.mixins + import bsb.morphologies + import bsb.morphologies.parsers + import bsb.morphologies.parsers.parser + import bsb.morphologies.selector + import bsb.option + import bsb.options + import bsb.placement.arrays + import bsb.placement.distributor + import bsb.placement.import_ + import bsb.placement.indicator + import bsb.placement.particle + import bsb.placement.satellite + import bsb.placement.strategy + import bsb.plugins + import bsb.postprocessing + import bsb.profiling + import bsb.reporting + import bsb.services + import bsb.simulation + import bsb.simulation.adapter + import bsb.simulation.cell + import bsb.simulation.component + import bsb.simulation.connection + import bsb.simulation.device + import bsb.simulation.parameter + import bsb.simulation.results + import bsb.simulation.simulation + import bsb.simulation.targetting + import bsb.storage + import bsb.storage._files + import bsb.storage.decorators + import bsb.storage.interfaces + import bsb.topology + import bsb.topology.partition + import bsb.topology.region + import bsb.trees + import bsb.voxels + +AdapterError: typing.Type["bsb.exceptions.AdapterError"] +AdapterProgress: typing.Type["bsb.simulation.adapter.AdapterProgress"] +AdaptiveNeighbourhood: typing.Type["bsb.placement.particle.AdaptiveNeighbourhood"] +AllToAll: typing.Type["bsb.connectivity.general.AllToAll"] +AllenApiError: typing.Type["bsb.exceptions.AllenApiError"] +AllenStructure: typing.Type["bsb.topology.partition.AllenStructure"] +ArborError: typing.Type["bsb.exceptions.ArborError"] +AttributeMissingError: typing.Type["bsb.exceptions.AttributeMissingError"] +BaseCommand: typing.Type["bsb.cli.commands.BaseCommand"] +BaseParser: typing.Type["bsb.cli.commands.BaseParser"] +BidirectionalContact: typing.Type["bsb.postprocessing.BidirectionalContact"] +BootError: typing.Type["bsb.exceptions.BootError"] +BoxTree: typing.Type["bsb.voxels.BoxTree"] +BoxTreeInterface: typing.Type["bsb.trees.BoxTreeInterface"] +Branch: typing.Type["bsb.morphologies.Branch"] +BranchLocTargetting: typing.Type["bsb.simulation.targetting.BranchLocTargetting"] +BsbCommand: typing.Type["bsb.cli.commands.BsbCommand"] +BsbOption: typing.Type["bsb.option.BsbOption"] +BsbParser: typing.Type["bsb.morphologies.parsers.parser.BsbParser"] +ByIdTargetting: typing.Type["bsb.simulation.targetting.ByIdTargetting"] +ByLabelTargetting: typing.Type["bsb.simulation.targetting.ByLabelTargetting"] +CLIError: typing.Type["bsb.exceptions.CLIError"] +CLIOptionDescriptor: typing.Type["bsb.option.CLIOptionDescriptor"] +CastConfigurationError: typing.Type["bsb.exceptions.CastConfigurationError"] +CastError: typing.Type["bsb.exceptions.CastError"] +CellModel: typing.Type["bsb.simulation.cell.CellModel"] +CellModelFilter: typing.Type["bsb.simulation.targetting.CellModelFilter"] +CellModelTargetting: typing.Type["bsb.simulation.targetting.CellModelTargetting"] +CellTargetting: typing.Type["bsb.simulation.targetting.CellTargetting"] +CellType: typing.Type["bsb.cell_types.CellType"] +CfgReferenceError: typing.Type["bsb.exceptions.CfgReferenceError"] +Chunk: typing.Type["bsb.storage.Chunk"] +ChunkError: typing.Type["bsb.exceptions.ChunkError"] +CircularMorphologyError: typing.Type["bsb.exceptions.CircularMorphologyError"] +ClassError: typing.Type["bsb.exceptions.ClassError"] +ClassMapMissingError: typing.Type["bsb.exceptions.ClassMapMissingError"] +CodeDependencyNode: typing.Type["bsb.storage.CodeDependencyNode"] +CodeImportError: typing.Type["bsb.exceptions.CodeImportError"] +CommandError: typing.Type["bsb.exceptions.CommandError"] +CompartmentError: typing.Type["bsb.exceptions.CompartmentError"] +CompilationError: typing.Type["bsb.exceptions.CompilationError"] +ConfigTemplateNotFoundError: typing.Type["bsb.exceptions.ConfigTemplateNotFoundError"] +Configuration: typing.Type["bsb.config.Configuration"] +ConfigurationAttribute: typing.Type["bsb.config.ConfigurationAttribute"] +ConfigurationError: typing.Type["bsb.exceptions.ConfigurationError"] +ConfigurationFormatError: typing.Type["bsb.exceptions.ConfigurationFormatError"] +ConfigurationWarning: typing.Type["bsb.exceptions.ConfigurationWarning"] +ConnectionModel: typing.Type["bsb.simulation.connection.ConnectionModel"] +ConnectionStrategy: typing.Type["bsb.connectivity.strategy.ConnectionStrategy"] +ConnectionTargetting: typing.Type["bsb.simulation.targetting.ConnectionTargetting"] +ConnectivityError: typing.Type["bsb.exceptions.ConnectivityError"] +ConnectivityIterator: typing.Type["bsb.storage.interfaces.ConnectivityIterator"] +ConnectivitySet: typing.Type["bsb.storage.interfaces.ConnectivitySet"] +ConnectivityWarning: typing.Type["bsb.exceptions.ConnectivityWarning"] +ContinuityError: typing.Type["bsb.exceptions.ContinuityError"] +Convergence: typing.Type["bsb.connectivity.general.Convergence"] +CsvImportConnectivity: typing.Type["bsb.connectivity.import_.CsvImportConnectivity"] +CsvImportPlacement: typing.Type["bsb.placement.import_.CsvImportPlacement"] +CylindricalTargetting: typing.Type["bsb.simulation.targetting.CylindricalTargetting"] +DataNotFoundError: typing.Type["bsb.exceptions.DataNotFoundError"] +DataNotProvidedError: typing.Type["bsb.exceptions.DataNotProvidedError"] +DatasetExistsError: typing.Type["bsb.exceptions.DatasetExistsError"] +DatasetNotFoundError: typing.Type["bsb.exceptions.DatasetNotFoundError"] +DependencyError: typing.Type["bsb.exceptions.DependencyError"] +DeviceConnectionError: typing.Type["bsb.exceptions.DeviceConnectionError"] +DeviceModel: typing.Type["bsb.simulation.device.DeviceModel"] +Distribution: typing.Type["bsb.config.Distribution"] +DistributionCastError: typing.Type["bsb.exceptions.DistributionCastError"] +DistributionContext: typing.Type["bsb.placement.distributor.DistributionContext"] +Distributor: typing.Type["bsb.placement.distributor.Distributor"] +DistributorError: typing.Type["bsb.exceptions.DistributorError"] +DistributorsNode: typing.Type["bsb.placement.distributor.DistributorsNode"] +DryrunError: typing.Type["bsb.exceptions.DryrunError"] +DynamicClassError: typing.Type["bsb.exceptions.DynamicClassError"] +DynamicClassInheritanceError: typing.Type["bsb.exceptions.DynamicClassInheritanceError"] +DynamicObjectNotFoundError: typing.Type["bsb.exceptions.DynamicObjectNotFoundError"] +EmptyBranchError: typing.Type["bsb.exceptions.EmptyBranchError"] +EmptySelectionError: typing.Type["bsb.exceptions.EmptySelectionError"] +EmptyVoxelSetError: typing.Type["bsb.exceptions.EmptyVoxelSetError"] +Engine: typing.Type["bsb.storage.interfaces.Engine"] +Entities: typing.Type["bsb.placement.strategy.Entities"] +EnvOptionDescriptor: typing.Type["bsb.option.EnvOptionDescriptor"] +ExplicitNoRotations: typing.Type["bsb.placement.distributor.ExplicitNoRotations"] +ExternalSourceError: typing.Type["bsb.exceptions.ExternalSourceError"] +FiberIntersection: typing.Type["bsb.connectivity.detailed.fiber_intersection.FiberIntersection"] +FiberTransform: typing.Type["bsb.connectivity.detailed.fiber_intersection.FiberTransform"] +FileDependency: typing.Type["bsb.storage.FileDependency"] +FileDependencyNode: typing.Type["bsb.storage.FileDependencyNode"] +FileScheme: typing.Type["bsb.storage._files.FileScheme"] +FileStore: typing.Type["bsb.storage.interfaces.FileStore"] +FixedIndegree: typing.Type["bsb.connectivity.general.FixedIndegree"] +FixedPositions: typing.Type["bsb.placement.strategy.FixedPositions"] +FractionFilter: typing.Type["bsb.simulation.targetting.FractionFilter"] +GatewayError: typing.Type["bsb.exceptions.GatewayError"] +GeneratedMorphology: typing.Type["bsb.storage.interfaces.GeneratedMorphology"] +HasDependencies: typing.Type["bsb.mixins.HasDependencies"] +Hemitype: typing.Type["bsb.connectivity.strategy.Hemitype"] +HemitypeCollection: typing.Type["bsb.connectivity.strategy.HemitypeCollection"] +Implicit: typing.Type["bsb.placement.distributor.Implicit"] +ImplicitNoRotations: typing.Type["bsb.placement.distributor.ImplicitNoRotations"] +ImportConnectivity: typing.Type["bsb.connectivity.import_.ImportConnectivity"] +ImportPlacement: typing.Type["bsb.placement.import_.ImportPlacement"] +IncompleteExternalMapError: typing.Type["bsb.exceptions.IncompleteExternalMapError"] +IncompleteMorphologyError: typing.Type["bsb.exceptions.IncompleteMorphologyError"] +IndicatorError: typing.Type["bsb.exceptions.IndicatorError"] +InputError: typing.Type["bsb.exceptions.InputError"] +Interface: typing.Type["bsb.storage.interfaces.Interface"] +IntersectionDataNotFoundError: typing.Type["bsb.exceptions.IntersectionDataNotFoundError"] +Intersectional: typing.Type["bsb.connectivity.detailed.shared.Intersectional"] +InvalidReferenceError: typing.Type["bsb.exceptions.InvalidReferenceError"] +InvertedRoI: typing.Type["bsb.mixins.InvertedRoI"] +JobCancelledError: typing.Type["bsb.exceptions.JobCancelledError"] +JobPool: typing.Type["bsb.services.JobPool"] +JobPoolError: typing.Type["bsb.exceptions.JobPoolError"] +JsonImportError: typing.Type["bsb.exceptions.JsonImportError"] +JsonParseError: typing.Type["bsb.exceptions.JsonParseError"] +JsonReferenceError: typing.Type["bsb.exceptions.JsonReferenceError"] +LabelTargetting: typing.Type["bsb.simulation.targetting.LabelTargetting"] +LargeParticleSystem: typing.Type["bsb.placement.particle.LargeParticleSystem"] +Layer: typing.Type["bsb.topology.partition.Layer"] +LayoutError: typing.Type["bsb.exceptions.LayoutError"] +LocationTargetting: typing.Type["bsb.simulation.targetting.LocationTargetting"] +MPI: typing.Type["bsb.services.MPI"] +MPILock: typing.Type["bsb.services.MPILock"] +Meter: typing.Type["bsb.profiling.Meter"] +MissingActiveConfigError: typing.Type["bsb.exceptions.MissingActiveConfigError"] +MissingAxon: typing.Type["bsb.postprocessing.MissingAxon"] +MissingMorphologyError: typing.Type["bsb.exceptions.MissingMorphologyError"] +MissingSourceError: typing.Type["bsb.exceptions.MissingSourceError"] +MorphIOParser: typing.Type["bsb.morphologies.parsers.parser.MorphIOParser"] +Morphology: typing.Type["bsb.morphologies.Morphology"] +MorphologyDataError: typing.Type["bsb.exceptions.MorphologyDataError"] +MorphologyDependencyNode: typing.Type["bsb.storage.MorphologyDependencyNode"] +MorphologyDistributor: typing.Type["bsb.placement.distributor.MorphologyDistributor"] +MorphologyError: typing.Type["bsb.exceptions.MorphologyError"] +MorphologyGenerator: typing.Type["bsb.placement.distributor.MorphologyGenerator"] +MorphologyOperation: typing.Type["bsb.storage.MorphologyOperation"] +MorphologyParser: typing.Type["bsb.morphologies.parsers.parser.MorphologyParser"] +MorphologyRepository: typing.Type["bsb.storage.interfaces.MorphologyRepository"] +MorphologyRepositoryError: typing.Type["bsb.exceptions.MorphologyRepositoryError"] +MorphologySelector: typing.Type["bsb.morphologies.selector.MorphologySelector"] +MorphologySet: typing.Type["bsb.morphologies.MorphologySet"] +MorphologyWarning: typing.Type["bsb.exceptions.MorphologyWarning"] +NameSelector: typing.Type["bsb.morphologies.selector.NameSelector"] +Neighbourhood: typing.Type["bsb.placement.particle.Neighbourhood"] +NestConnectError: typing.Type["bsb.exceptions.NestConnectError"] +NestError: typing.Type["bsb.exceptions.NestError"] +NestKernelError: typing.Type["bsb.exceptions.NestKernelError"] +NestModelError: typing.Type["bsb.exceptions.NestModelError"] +NestModuleError: typing.Type["bsb.exceptions.NestModuleError"] +NetworkDescription: typing.Type["bsb.storage.interfaces.NetworkDescription"] +NeuroMorphoScheme: typing.Type["bsb.storage._files.NeuroMorphoScheme"] +NeuroMorphoSelector: typing.Type["bsb.morphologies.selector.NeuroMorphoSelector"] +NeuronError: typing.Type["bsb.exceptions.NeuronError"] +NoReferenceAttributeSignal: typing.Type["bsb.exceptions.NoReferenceAttributeSignal"] +NodeNotFoundError: typing.Type["bsb.exceptions.NodeNotFoundError"] +NoneReferenceError: typing.Type["bsb.exceptions.NoneReferenceError"] +NoopLock: typing.Type["bsb.storage.interfaces.NoopLock"] +NotParallel: typing.Type["bsb.mixins.NotParallel"] +NotSupported: typing.Type["bsb.storage.NotSupported"] +NrrdDependencyNode: typing.Type["bsb.storage.NrrdDependencyNode"] +NrrdVoxels: typing.Type["bsb.topology.partition.NrrdVoxels"] +Operation: typing.Type["bsb.storage.Operation"] +OptionDescriptor: typing.Type["bsb.option.OptionDescriptor"] +OptionError: typing.Type["bsb.exceptions.OptionError"] +PackageRequirement: typing.Type["bsb.config.types.PackageRequirement"] +PackageRequirementWarning: typing.Type["bsb.exceptions.PackageRequirementWarning"] +PackingError: typing.Type["bsb.exceptions.PackingError"] +PackingWarning: typing.Type["bsb.exceptions.PackingWarning"] +ParallelArrayPlacement: typing.Type["bsb.placement.arrays.ParallelArrayPlacement"] +ParallelIntegrityError: typing.Type["bsb.exceptions.ParallelIntegrityError"] +Parameter: typing.Type["bsb.simulation.parameter.Parameter"] +ParameterError: typing.Type["bsb.exceptions.ParameterError"] +ParameterValue: typing.Type["bsb.simulation.parameter.ParameterValue"] +Parser: typing.Type["bsb.config.parsers.Parser"] +ParserError: typing.Type["bsb.exceptions.ParserError"] +Particle: typing.Type["bsb.placement.particle.Particle"] +ParticlePlacement: typing.Type["bsb.placement.particle.ParticlePlacement"] +ParticleSystem: typing.Type["bsb.placement.particle.ParticleSystem"] +ParticleVoxel: typing.Type["bsb.placement.particle.ParticleVoxel"] +Partition: typing.Type["bsb.topology.partition.Partition"] +PlacementError: typing.Type["bsb.exceptions.PlacementError"] +PlacementIndications: typing.Type["bsb.cell_types.PlacementIndications"] +PlacementIndicator: typing.Type["bsb.placement.indicator.PlacementIndicator"] +PlacementRelationError: typing.Type["bsb.exceptions.PlacementRelationError"] +PlacementSet: typing.Type["bsb.storage.interfaces.PlacementSet"] +PlacementStrategy: typing.Type["bsb.placement.strategy.PlacementStrategy"] +PlacementWarning: typing.Type["bsb.exceptions.PlacementWarning"] +Plotting: typing.Type["bsb.cell_types.Plotting"] +PluginError: typing.Type["bsb.exceptions.PluginError"] +PostProcessingHook: typing.Type["bsb.postprocessing.PostProcessingHook"] +ProfilingSession: typing.Type["bsb.profiling.ProfilingSession"] +ProgressEvent: typing.Type["bsb.simulation.simulation.ProgressEvent"] +ProjectOptionDescriptor: typing.Type["bsb.option.ProjectOptionDescriptor"] +QuiverFieldWarning: typing.Type["bsb.exceptions.QuiverFieldWarning"] +QuiverTransform: typing.Type["bsb.connectivity.detailed.fiber_intersection.QuiverTransform"] +RandomMorphologies: typing.Type["bsb.placement.distributor.RandomMorphologies"] +RandomPlacement: typing.Type["bsb.placement.particle.RandomPlacement"] +RandomRotations: typing.Type["bsb.placement.distributor.RandomRotations"] +ReadOnlyManager: typing.Type["bsb.storage.interfaces.ReadOnlyManager"] +ReadOnlyOptionError: typing.Type["bsb.exceptions.ReadOnlyOptionError"] +RedoError: typing.Type["bsb.exceptions.RedoError"] +Reference: typing.Type["bsb.config.refs.Reference"] +Region: typing.Type["bsb.topology.region.Region"] +RegionGroup: typing.Type["bsb.topology.region.RegionGroup"] +ReificationError: typing.Type["bsb.exceptions.ReificationError"] +Relay: typing.Type["bsb.postprocessing.Relay"] +ReportListener: typing.Type["bsb.core.ReportListener"] +RepresentativesTargetting: typing.Type["bsb.simulation.targetting.RepresentativesTargetting"] +RequirementError: typing.Type["bsb.exceptions.RequirementError"] +Rhomboid: typing.Type["bsb.topology.partition.Rhomboid"] +RootCommand: typing.Type["bsb.cli.commands.RootCommand"] +RotationDistributor: typing.Type["bsb.placement.distributor.RotationDistributor"] +RotationSet: typing.Type["bsb.morphologies.RotationSet"] +RoundRobinMorphologies: typing.Type["bsb.placement.distributor.RoundRobinMorphologies"] +Satellite: typing.Type["bsb.placement.satellite.Satellite"] +SatelliteIndicator: typing.Type["bsb.placement.satellite.SatelliteIndicator"] +Scaffold: typing.Type["bsb.core.Scaffold"] +ScaffoldError: typing.Type["bsb.exceptions.ScaffoldError"] +ScaffoldWarning: typing.Type["bsb.exceptions.ScaffoldWarning"] +ScriptOptionDescriptor: typing.Type["bsb.option.ScriptOptionDescriptor"] +SelectorError: typing.Type["bsb.exceptions.SelectorError"] +Simulation: typing.Type["bsb.simulation.simulation.Simulation"] +SimulationBackendPlugin: typing.Type["bsb.simulation.SimulationBackendPlugin"] +SimulationComponent: typing.Type["bsb.simulation.component.SimulationComponent"] +SimulationData: typing.Type["bsb.simulation.adapter.SimulationData"] +SimulationError: typing.Type["bsb.exceptions.SimulationError"] +SimulationRecorder: typing.Type["bsb.simulation.results.SimulationRecorder"] +SimulationResult: typing.Type["bsb.simulation.results.SimulationResult"] +SimulatorAdapter: typing.Type["bsb.simulation.adapter.SimulatorAdapter"] +SmallestNeighbourhood: typing.Type["bsb.placement.particle.SmallestNeighbourhood"] +SomaTargetting: typing.Type["bsb.simulation.targetting.SomaTargetting"] +SourceQualityError: typing.Type["bsb.exceptions.SourceQualityError"] +SphericalTargetting: typing.Type["bsb.simulation.targetting.SphericalTargetting"] +SpoofDetails: typing.Type["bsb.postprocessing.SpoofDetails"] +Stack: typing.Type["bsb.topology.region.Stack"] +Storage: typing.Type["bsb.storage.Storage"] +StorageError: typing.Type["bsb.exceptions.StorageError"] +StorageNode: typing.Type["bsb.storage.interfaces.StorageNode"] +StoredFile: typing.Type["bsb.storage.interfaces.StoredFile"] +StoredMorphology: typing.Type["bsb.storage.interfaces.StoredMorphology"] +SubTree: typing.Type["bsb.morphologies.SubTree"] +Targetting: typing.Type["bsb.simulation.targetting.Targetting"] +TopologyError: typing.Type["bsb.exceptions.TopologyError"] +TouchDetector: typing.Type["bsb.connectivity.detailed.touch_detection.TouchDetector"] +TouchInformation: typing.Type["bsb.connectivity.detailed.touch_detection.TouchInformation"] +TransmitterError: typing.Type["bsb.exceptions.TransmitterError"] +TreeError: typing.Type["bsb.exceptions.TreeError"] +TypeHandler: typing.Type["bsb.config.types.TypeHandler"] +TypeHandlingError: typing.Type["bsb.exceptions.TypeHandlingError"] +UnfitClassCastError: typing.Type["bsb.exceptions.UnfitClassCastError"] +UnknownConfigAttrError: typing.Type["bsb.exceptions.UnknownConfigAttrError"] +UnknownGIDError: typing.Type["bsb.exceptions.UnknownGIDError"] +UnknownStorageEngineError: typing.Type["bsb.exceptions.UnknownStorageEngineError"] +UnmanagedPartitionError: typing.Type["bsb.exceptions.UnmanagedPartitionError"] +UnresolvedClassCastError: typing.Type["bsb.exceptions.UnresolvedClassCastError"] +UriScheme: typing.Type["bsb.storage._files.UriScheme"] +UrlScheme: typing.Type["bsb.storage._files.UrlScheme"] +VolumetricRotations: typing.Type["bsb.placement.distributor.VolumetricRotations"] +VoxelData: typing.Type["bsb.voxels.VoxelData"] +VoxelIntersection: typing.Type["bsb.connectivity.detailed.voxel_intersection.VoxelIntersection"] +VoxelSet: typing.Type["bsb.voxels.VoxelSet"] +VoxelSetError: typing.Type["bsb.exceptions.VoxelSetError"] +Voxels: typing.Type["bsb.topology.partition.Voxels"] +WeakInverter: typing.Type["bsb.config.types.WeakInverter"] +WorkflowError: typing.Type["bsb.services.WorkflowError"] +activate_session: "bsb.profiling.activate_session" +box_layout: "bsb.topology.box_layout" +branch_iter: "bsb.morphologies.branch_iter" +chunklist: "bsb.storage.chunklist" +compose_nodes: "bsb.config.compose_nodes" +copy_template: "bsb.config.copy_template" +create_engine: "bsb.storage.create_engine" +create_topology: "bsb.topology.create_topology" +discover: "bsb.plugins.discover" +discover_engines: "bsb.storage.discover_engines" +format_content: "bsb.config.format_content" +from_content: "bsb.config.from_content" +from_file: "bsb.config.from_file" +from_json: "bsb.config.from_json" +from_storage: "bsb.core.from_storage" +get: "bsb.options.get" +get_active_session: "bsb.profiling.get_active_session" +get_config_attributes: "bsb.config.get_config_attributes" +get_config_path: "bsb.config.get_config_path" +get_engine_node: "bsb.storage.get_engine_node" +get_engines: "bsb.storage.get_engines" +get_module_option: "bsb.options.get_module_option" +get_option: "bsb.options.get_option" +get_option_classes: "bsb.options.get_option_classes" +get_options: "bsb.options.get_options" +get_parser: "bsb.config.parsers.get_parser" +get_parser_classes: "bsb.config.parsers.get_parser_classes" +get_partitions: "bsb.topology.get_partitions" +get_project_option: "bsb.options.get_project_option" +get_report_file: "bsb.reporting.get_report_file" +get_root_regions: "bsb.topology.get_root_regions" +get_simulation_adapter: "bsb.simulation.get_simulation_adapter" +handle_cli: "bsb.cli.handle_cli" +handle_command: "bsb.cli.handle_command" +in_notebook: "bsb.reporting.in_notebook" +in_pytest: "bsb.reporting.in_pytest" +init_engines: "bsb.storage.init_engines" +is_module_option_set: "bsb.options.is_module_option_set" +is_partition: "bsb.topology.is_partition" +is_region: "bsb.topology.is_region" +load_root_command: "bsb.cli.commands.load_root_command" +make_config_diagram: "bsb.config.make_config_diagram" +meter: "bsb.profiling.meter" +node_meter: "bsb.profiling.node_meter" +on_main: "bsb.storage.decorators.on_main" +on_main_until: "bsb.storage.decorators.on_main_until" +open_storage: "bsb.storage.open_storage" +parse_morphology_content: "bsb.morphologies.parsers.parse_morphology_content" +parse_morphology_file: "bsb.morphologies.parsers.parse_morphology_file" +parsers: "bsb.config.parsers" +read: "bsb.options.read" +read_report_file: "bsb.reporting.read_report_file" +refs: "bsb.config.refs" +register_engine: "bsb.storage.register_engine" +register_option: "bsb.options.register_option" +register_service: "bsb.services.register_service" +report: "bsb.reporting.report" +reset_module_option: "bsb.options.reset_module_option" +set_module_option: "bsb.options.set_module_option" +set_report_file: "bsb.reporting.set_report_file" +setup_reporting: "bsb.reporting.setup_reporting" +store: "bsb.options.store" +types: "bsb.config.types" +unregister_option: "bsb.options.unregister_option" +view_profile: "bsb.profiling.view_profile" +view_support: "bsb.storage.view_support" +walk_node_attributes: "bsb.config.walk_node_attributes" +walk_nodes: "bsb.config.walk_nodes" +warn: "bsb.reporting.warn" diff --git a/bsb/_package_spec.py b/bsb/_package_spec.py index 19b124f63..1b7153aac 100644 --- a/bsb/_package_spec.py +++ b/bsb/_package_spec.py @@ -1,7 +1,7 @@ from exceptiongroup import ExceptionGroup -from bsb.exceptions import PackageRequirementWarning -from bsb.reporting import warn +from .exceptions import PackageRequirementWarning +from .reporting import warn class MissingRequirementErrors(ExceptionGroup): diff --git a/bsb/cell_types.py b/bsb/cell_types.py index 85ef511da..7db2d9836 100644 --- a/bsb/cell_types.py +++ b/bsb/cell_types.py @@ -148,3 +148,6 @@ def morphologies(self, value): "`cell_type.morphologies` is a readonly attribute. Did you mean" " `cell_type.spatial.morphologies`?" ) + + +__all__ = ["CellType", "PlacementIndications", "Plotting"] diff --git a/bsb/cli/__init__.py b/bsb/cli/__init__.py index beb8966c6..d3d5aa0b8 100644 --- a/bsb/cli/__init__.py +++ b/bsb/cli/__init__.py @@ -3,7 +3,7 @@ import sys from .._contexts import get_cli_context, reset_cli_context -from ..exceptions import * +from ..exceptions import CommandError, DryrunError from .commands import load_root_command @@ -39,3 +39,6 @@ def _can_dryrun(handler, namespace): return bool(inspect.signature(handler).bind(namespace, dryrun=True)) except TypeError: return False + + +__all__ = ["handle_cli", "handle_command"] diff --git a/bsb/cli/commands/__init__.py b/bsb/cli/commands/__init__.py index f3d6f9c33..ed8034f48 100644 --- a/bsb/cli/commands/__init__.py +++ b/bsb/cli/commands/__init__.py @@ -149,3 +149,6 @@ def load_root_command(): # class using the `__init_subclass__` function. discover("commands") return RootCommand() + + +__all__ = ["BaseCommand", "BaseParser", "BsbCommand", "RootCommand", "load_root_command"] diff --git a/bsb/cli/commands/_commands.py b/bsb/cli/commands/_commands.py index cbbbbea7e..92d3bba2a 100644 --- a/bsb/cli/commands/_commands.py +++ b/bsb/cli/commands/_commands.py @@ -56,12 +56,6 @@ class Output(BsbOption, name="output", cli=("output", "o"), env=("BSB_OUTPUT_FIL pass -class Plot( - BsbOption, name="plot", cli=("plot", "p"), env=("BSB_PLOT_NETWORK",), flag=True -): - pass - - class SkipPlacement( BsbOption, name="skip_placement", @@ -102,6 +96,16 @@ class SkipAfterConnectivity( pass +class IgnoreErrors( + BsbOption, + name="ignore_errors", + cli=("ignore", "ignore-errors"), + env=("BSB_IGNORE_ERRORS",), + flag=True, +): + pass + + def _flatten_arr_args(arr): if arr is None: return arr @@ -147,13 +151,9 @@ def handler(self, context): force=context.force, append=context.append, redo=context.redo, + fail_fast=not context.ignore_errors, ) - if context.plot: - from bsb.plotting import plot_network - - plot_network(network) - def get_options(self): return { "x": XScale(), @@ -169,8 +169,8 @@ def get_options(self): "append": Append(), "redo": Redo(), "clear": Clear(), - "plot": Plot(), "output": Output(), + "ignore_errors": IgnoreErrors(), } def add_parser_arguments(self, parser): diff --git a/bsb/cli/commands/_projects.py b/bsb/cli/commands/_projects.py index 416e41e74..bcec867f0 100644 --- a/bsb/cli/commands/_projects.py +++ b/bsb/cli/commands/_projects.py @@ -67,9 +67,9 @@ def handler(self, context): conn_path = root / "connectome.py" if not place_path.exists(): with open(place_path, "w") as f: - f.write("from bsb.placement import PlacementStrategy\n") + f.write("from bsb import PlacementStrategy\n") if not conn_path.exists(): with open(conn_path, "w") as f: - f.write("from bsb.connectivity import ConnectionStrategy\n") + f.write("from bsb import ConnectionStrategy\n") report(f"Created '{name}' project structure.", level=1) diff --git a/bsb/config/__init__.py b/bsb/config/__init__.py index 9e44bfeda..567f9d3ef 100644 --- a/bsb/config/__init__.py +++ b/bsb/config/__init__.py @@ -291,3 +291,64 @@ def parser_method(self, file=None, data=None, path=None): ConfigurationModule.__all__ = sorted(ConfigurationModule.__all__) sys.modules[__name__] = ConfigurationModule(__name__) + +# Static public API +__all__ = [ + "Configuration", + "ConfigurationAttribute", + "Distribution", + "after", + "attr", + "before", + "catch_all", + "compose_nodes", + "copy_template", + "dict", + "dynamic", + "file", + "format_content", + "from_content", + "from_file", + "from_json", + "get_config_attributes", + "get_config_path", + "get_parser", + "has_hook", + "list", + "make_config_diagram", + "node", + "on", + "parsers", + "pluggable", + "property", + "provide", + "ref", + "reflist", + "root", + "run_hook", + "slot", + "types", + "unset", + "walk_node_attributes", + "walk_nodes", +] +__api__ = [ + "Configuration", + "ConfigurationAttribute", + "Distribution", + "compose_nodes", + "copy_template", + "format_content", + "from_content", + "from_file", + "from_json", + "get_config_attributes", + "get_config_path", + "get_parser", + "make_config_diagram", + "parsers", + "refs", + "types", + "walk_node_attributes", + "walk_nodes", +] diff --git a/bsb/config/_make.py b/bsb/config/_make.py index 70f6883da..9fb94fa13 100644 --- a/bsb/config/_make.py +++ b/bsb/config/_make.py @@ -364,7 +364,7 @@ def _bubble_up_warnings(log): def _bootstrap_components(components, file_store=None): - from bsb.storage._files import CodeDependencyNode + from ..storage._files import CodeDependencyNode for component in components: component_node = CodeDependencyNode(component) diff --git a/bsb/config/parsers/__init__.py b/bsb/config/parsers/__init__.py index aa93946f4..2f891da8f 100644 --- a/bsb/config/parsers/__init__.py +++ b/bsb/config/parsers/__init__.py @@ -9,3 +9,6 @@ def get_parser_classes(): def get_parser(parser): return get_parser_classes()[parser]() + + +__all__ = ["Parser", "get_parser", "get_parser_classes"] diff --git a/bsb/config/refs.py b/bsb/config/refs.py index 9a6647b76..7f9f00d8a 100644 --- a/bsb/config/refs.py +++ b/bsb/config/refs.py @@ -101,7 +101,7 @@ def is_ref(self, value): class SimCellModelReference(Reference): def __call__(self, root, here): - from bsb.simulation.simulation import Simulation + from ..simulation.simulation import Simulation sim = self.up(here, Simulation) return sim.cell_models @@ -121,4 +121,15 @@ def is_ref(self, value): region_ref = RegionReference() sim_cell_model_ref = SimCellModelReference() -__all__ = [k for k in vars().keys() if k.endswith("_ref") or k.endswith("__")] +__all__ = [ + "Reference", + "cell_type_ref", + "conn_type_ref", + "partition_ref", + "placement_ref", + "connectivity_ref", + "regional_ref", + "region_ref", + "sim_cell_model_ref", +] +__api__ = ["Reference"] diff --git a/bsb/config/types.py b/bsb/config/types.py index 6c38798a2..4696002fe 100644 --- a/bsb/config/types.py +++ b/bsb/config/types.py @@ -781,3 +781,37 @@ def __inv__(self, value): def __hint__(self): return "numpy==1.24.0" + + +__all__ = [ + "PackageRequirement", + "TypeHandler", + "WeakInverter", + "any_", + "class_", + "deg_to_radian", + "dict", + "distribution", + "evaluation", + "float", + "fraction", + "function_", + "in_", + "in_classmap", + "int", + "key", + "list", + "list_or_scalar", + "method", + "method_shortcut", + "mut_excl", + "ndarray", + "number", + "object_", + "or_", + "scalar_expand", + "shortform", + "str", + "voxel_size", +] +__api__ = ["PackageRequirement", "TypeHandler", "WeakInverter"] diff --git a/bsb/connectivity/__init__.py b/bsb/connectivity/__init__.py index d0eac7e85..8ded576c3 100644 --- a/bsb/connectivity/__init__.py +++ b/bsb/connectivity/__init__.py @@ -1,5 +1,9 @@ +# isort: off +# Load module before others to prevent partially initialized modules +from .strategy import ConnectionStrategy + +# isort: on from .detailed import * from .detailed.fiber_intersection import FiberTransform, QuiverTransform from .general import * from .import_ import CsvImportConnectivity -from .strategy import ConnectionStrategy diff --git a/bsb/connectivity/detailed/__init__.py b/bsb/connectivity/detailed/__init__.py index e5d1c831e..38776bfb6 100644 --- a/bsb/connectivity/detailed/__init__.py +++ b/bsb/connectivity/detailed/__init__.py @@ -1,19 +1,3 @@ -import inspect -import os -from glob import glob -from importlib import import_module - -from ..strategy import ConnectionStrategy - -# Scan the whole directory for python files, then import any ConnectionStrategies into -# this module. -src_files = glob(os.path.join(os.path.dirname(__file__), "*.py")) -exclude_src = ["__init__"] -for src_file in src_files: - module_name = os.path.basename(src_file).split(".")[0] - if module_name in exclude_src: - continue - module = import_module("." + module_name, __package__) - for name, obj in module.__dict__.items(): - if inspect.isclass(obj) and issubclass(obj, ConnectionStrategy): - globals()[name] = obj +from .fiber_intersection import FiberIntersection +from .touch_detection import TouchDetector +from .voxel_intersection import VoxelIntersection diff --git a/bsb/connectivity/detailed/fiber_intersection.py b/bsb/connectivity/detailed/fiber_intersection.py index 7ccc329a9..8958de2d3 100644 --- a/bsb/connectivity/detailed/fiber_intersection.py +++ b/bsb/connectivity/detailed/fiber_intersection.py @@ -5,7 +5,11 @@ from ... import config from ...config import types -from ...exceptions import * +from ...exceptions import ( + ConfigurationError, + IncompleteMorphologyError, + QuiverFieldWarning, +) from ...reporting import warn from ..strategy import ConnectionStrategy from .shared import Intersectional @@ -426,3 +430,6 @@ def get_branch_direction(self, branch): # Normalize branch_dir vector branch_dir = branch_dir / np.linalg.norm(branch_dir) return branch_dir + + +__all__ = ["FiberIntersection", "FiberTransform", "QuiverTransform"] diff --git a/bsb/connectivity/detailed/shared.py b/bsb/connectivity/detailed/shared.py index 9cdd89492..dfdae42b1 100644 --- a/bsb/connectivity/detailed/shared.py +++ b/bsb/connectivity/detailed/shared.py @@ -83,3 +83,6 @@ def sizemod(q): return int(np.floor(ln * aff) + (np.random.rand() < ((ln * aff) % 1))) return (np.random.choice(q, sizemod(q), replace=False) for q in query) + + +__all__ = ["Intersectional"] diff --git a/bsb/connectivity/detailed/touch_detection.py b/bsb/connectivity/detailed/touch_detection.py index f73a164d5..62aaa9e8b 100644 --- a/bsb/connectivity/detailed/touch_detection.py +++ b/bsb/connectivity/detailed/touch_detection.py @@ -4,7 +4,7 @@ from ... import config from ...config import types -from ...reporting import report, warn +from ...reporting import report from ..strategy import ConnectionStrategy from .shared import Intersectional @@ -216,3 +216,6 @@ def get_search_radius(self, cell_type): ), ) return max_radius + + +__all__ = ["TouchDetector", "TouchInformation"] diff --git a/bsb/connectivity/detailed/voxel_intersection.py b/bsb/connectivity/detailed/voxel_intersection.py index aeeb41453..2c1f8c2a2 100644 --- a/bsb/connectivity/detailed/voxel_intersection.py +++ b/bsb/connectivity/detailed/voxel_intersection.py @@ -156,3 +156,6 @@ def _pairs_with_zero(iterable): pass else: yield from zip(a, b) + + +__all__ = ["VoxelIntersection"] diff --git a/bsb/connectivity/general.py b/bsb/connectivity/general.py index 30d2b7440..d15ab054d 100644 --- a/bsb/connectivity/general.py +++ b/bsb/connectivity/general.py @@ -1,5 +1,3 @@ -import itertools -import os import typing import numpy as np @@ -74,3 +72,6 @@ def connect(self, pre, post): demuxed[:, 0] -= lowmux self.connect_cells(pre_ps, ps, demuxed, post_targets[demux_idx]) lowmux = highmux + + +__all__ = ["AllToAll", "Convergence", "FixedIndegree"] diff --git a/bsb/connectivity/import_.py b/bsb/connectivity/import_.py index b41014275..27fe893a2 100644 --- a/bsb/connectivity/import_.py +++ b/bsb/connectivity/import_.py @@ -161,3 +161,6 @@ def _safe_int(value: typing.Any) -> int: return int(float(value)) except ValueError: return -1 + + +__all__ = ["CsvImportConnectivity", "ImportConnectivity"] diff --git a/bsb/connectivity/strategy.py b/bsb/connectivity/strategy.py index 329fafa91..39742ccd7 100644 --- a/bsb/connectivity/strategy.py +++ b/bsb/connectivity/strategy.py @@ -164,3 +164,6 @@ def get_all_post_chunks(self): all_ps = (ct.get_placement_set() for ct in self.postsynaptic.cell_types) chunks = set(ichain(ps.get_all_chunks() for ps in all_ps)) return list(chunks) + + +__all__ = ["ConnectionStrategy", "Hemitype", "HemitypeCollection"] diff --git a/bsb/core.py b/bsb/core.py index f7aac8f1e..338225a61 100644 --- a/bsb/core.py +++ b/bsb/core.py @@ -818,3 +818,6 @@ def __call__(self, progress): + str(progress.time), token="simulation_progress", ) + + +__all__ = ["ReportListener", "Scaffold", "from_storage"] diff --git a/bsb/exceptions.py b/bsb/exceptions.py index e653ceb39..a45d988b0 100644 --- a/bsb/exceptions.py +++ b/bsb/exceptions.py @@ -163,3 +163,109 @@ class QuiverFieldWarning(ScaffoldWarning): class PackageRequirementWarning(ScaffoldWarning): pass + + +__all__ = [ + "AdapterError", + "AllenApiError", + "ArborError", + "AttributeMissingError", + "BootError", + "CLIError", + "CastConfigurationError", + "CastError", + "CfgReferenceError", + "ChunkError", + "CircularMorphologyError", + "ClassError", + "ClassMapMissingError", + "CodeImportError", + "CommandError", + "CompartmentError", + "CompilationError", + "ConfigTemplateNotFoundError", + "ConfigurationError", + "ConfigurationFormatError", + "ConfigurationWarning", + "ConnectivityError", + "ConnectivityWarning", + "ContinuityError", + "DataNotFoundError", + "DataNotProvidedError", + "DatasetExistsError", + "DatasetNotFoundError", + "DependencyError", + "DeviceConnectionError", + "DistributionCastError", + "DistributorError", + "DryrunError", + "DynamicClassError", + "DynamicClassInheritanceError", + "DynamicObjectNotFoundError", + "EmptyBranchError", + "EmptySelectionError", + "EmptyVoxelSetError", + "ExternalSourceError", + "GatewayError", + "IncompleteExternalMapError", + "IncompleteMorphologyError", + "IndicatorError", + "InputError", + "IntersectionDataNotFoundError", + "InvalidReferenceError", + "JobCancelledError", + "JobPoolError", + "JsonImportError", + "JsonParseError", + "JsonReferenceError", + "LayoutError", + "MissingActiveConfigError", + "MissingMorphologyError", + "MissingSourceError", + "MorphologyDataError", + "MorphologyError", + "MorphologyRepositoryError", + "MorphologyWarning", + "NestConnectError", + "NestError", + "NestKernelError", + "NestModelError", + "NestModuleError", + "NeuronError", + "NoReferenceAttributeSignal", + "NodeNotFoundError", + "NoneReferenceError", + "OptionError", + "PackageRequirementWarning", + "PackingError", + "PackingWarning", + "ParallelIntegrityError", + "ParameterError", + "ParserError", + "PlacementError", + "PlacementRelationError", + "PlacementWarning", + "PluginError", + "QuiverFieldWarning", + "ReadOnlyOptionError", + "RedoError", + "ReificationError", + "RequirementError", + "ScaffoldError", + "ScaffoldWarning", + "SelectorError", + "SimulationError", + "SourceQualityError", + "StorageError", + "TopologyError", + "TransmitterError", + "TreeError", + "TypeHandlingError", + "UnfitClassCastError", + "UnknownConfigAttrError", + "UnknownGIDError", + "UnknownStorageEngineError", + "UnmanagedPartitionError", + "UnresolvedClassCastError", + "VoxelSetError", +] diff --git a/bsb/mixins.py b/bsb/mixins.py index 0e7b1199d..5e0e9cb37 100644 --- a/bsb/mixins.py +++ b/bsb/mixins.py @@ -143,3 +143,6 @@ def queue(self, pool): job = pool.queue_connectivity(self, roi, [chunk], deps=deps) self._queued_jobs.append(job) report(f"Queued {len(self._queued_jobs)} jobs for {self.name}", level=2) + + +__all__ = ["HasDependencies", "InvertedRoI", "NotParallel"] diff --git a/bsb/morphologies/__init__.py b/bsb/morphologies/__init__.py index 4a6f8ec20..4835f56f9 100644 --- a/bsb/morphologies/__init__.py +++ b/bsb/morphologies/__init__.py @@ -1701,3 +1701,14 @@ def _morpho_to_swc(morpho): data[ids[0], 6] = -1 if b.parent is None else bmap[b.parent] + 1 return data[data != np.array(None)].reshape(-1, 7) + + +__all__ = [ + "Branch", + "Morphology", + "MorphologySet", + "RotationSet", + "SubTree", + "branch_iter", + "parse_morphology_file", +] diff --git a/bsb/morphologies/parsers/__init__.py b/bsb/morphologies/parsers/__init__.py index 3fa619c52..989c0202d 100644 --- a/bsb/morphologies/parsers/__init__.py +++ b/bsb/morphologies/parsers/__init__.py @@ -10,3 +10,6 @@ def parse_morphology_content(content: typing.Union[str, bytes], parser="bsb", ** def parse_morphology_file(file: typing.Union[str, PathLike], parser="bsb", **kwargs): return MorphologyParser(parser=parser, **kwargs).parse(file) + + +__all__ = ["parse_morphology_content", "parse_morphology_file"] diff --git a/bsb/morphologies/parsers/parser.py b/bsb/morphologies/parsers/parser.py index eb2b79b0c..87c87f39c 100644 --- a/bsb/morphologies/parsers/parser.py +++ b/bsb/morphologies/parsers/parser.py @@ -264,3 +264,6 @@ def parse(self, file: typing.Union["FileDependency", str]) -> Morphology: morpho._check_shared() ), "MorphIO import didn't result in shareable buffers." return morpho + + +__all__ = ["BsbParser", "MorphIOParser", "MorphologyParser"] diff --git a/bsb/morphologies/selector.py b/bsb/morphologies/selector.py index 2cfebaccb..8954246eb 100644 --- a/bsb/morphologies/selector.py +++ b/bsb/morphologies/selector.py @@ -153,3 +153,6 @@ def _scrape_nm(cls, names): + "." ) return morphos + + +__all__ = ["MorphologySelector", "NameSelector", "NeuroMorphoSelector"] diff --git a/bsb/option.py b/bsb/option.py index 019baad62..860e7c8ce 100644 --- a/bsb/option.py +++ b/bsb/option.py @@ -398,3 +398,13 @@ def _save_pyproject_bsb(project): content.setdefault("tools", {})["bsb"] = project with open(path, "w") as f: toml.dump(content, f) + + +__all__ = [ + "BsbOption", + "CLIOptionDescriptor", + "EnvOptionDescriptor", + "OptionDescriptor", + "ProjectOptionDescriptor", + "ScriptOptionDescriptor", +] diff --git a/bsb/options.py b/bsb/options.py index 05dfa7576..07aefcdb2 100644 --- a/bsb/options.py +++ b/bsb/options.py @@ -7,7 +7,7 @@ .. code-block:: import bsb.options - from bsb.option import BsbOption + from bsb import BsbOption class MyOption(BsbOption, cli=("my_setting",), env=("MY_SETTING",), script=("my_setting", "my_alias")): def get_default(self): @@ -369,3 +369,20 @@ def __delattr__(self, attr): _om.register_option(option.name, option) sys.modules[__name__] = _om + +# Static public API +__all__ = [ + "get", + "get_module_option", + "get_option", + "get_option_classes", + "get_options", + "get_project_option", + "is_module_option_set", + "read", + "register_option", + "reset_module_option", + "set_module_option", + "store", + "unregister_option", +] diff --git a/bsb/placement/__init__.py b/bsb/placement/__init__.py index 1fba47471..79ca71378 100644 --- a/bsb/placement/__init__.py +++ b/bsb/placement/__init__.py @@ -1,5 +1,8 @@ -# The strategy module needs to be imported before any module that uses the `NotParallel` mixin. -from .strategy import PlacementStrategy # isort: skip +# isort: off +# Load module before others to prevent partially initialized modules +from .strategy import PlacementStrategy + +# isort: on from .arrays import ParallelArrayPlacement from .import_ import CsvImportPlacement, ImportPlacement from .particle import ParticlePlacement, RandomPlacement diff --git a/bsb/placement/arrays.py b/bsb/placement/arrays.py index 4ff319f43..d7a20317b 100644 --- a/bsb/placement/arrays.py +++ b/bsb/placement/arrays.py @@ -5,8 +5,7 @@ from .. import config from ..config import types from ..mixins import NotParallel -from ..reporting import report, warn -from ..storage import Chunk +from ..reporting import report from .strategy import PlacementStrategy @@ -99,3 +98,6 @@ def place(self, chunk, indicators): pos_current_chunk = positions[idx] self.place_cells(indicator, pos_current_chunk, chunk=c) report(f"Placed {len(positions)} {cell_type.name} in {prt.name}", level=3) + + +__all__ = ["ParallelArrayPlacement"] diff --git a/bsb/placement/distributor.py b/bsb/placement/distributor.py index b00709f54..7f3a2cc5d 100644 --- a/bsb/placement/distributor.py +++ b/bsb/placement/distributor.py @@ -345,3 +345,20 @@ def _has_mdistr(self): def _has_rdistr(self): # This function checks if this distributor node has specified a rotation distributor return self.__class__.rotations.is_dirty(self) + + +__all__ = [ + "DistributionContext", + "Distributor", + "DistributorsNode", + "ExplicitNoRotations", + "Implicit", + "ImplicitNoRotations", + "MorphologyDistributor", + "MorphologyGenerator", + "RandomMorphologies", + "RandomRotations", + "RotationDistributor", + "RoundRobinMorphologies", + "VolumetricRotations", +] diff --git a/bsb/placement/import_.py b/bsb/placement/import_.py index 6de81e857..30b949033 100644 --- a/bsb/placement/import_.py +++ b/bsb/placement/import_.py @@ -143,3 +143,6 @@ def _safe_float(value: typing.Any) -> float: return float(value) except ValueError: return float("nan") + + +__all__ = ["CsvImportPlacement", "ImportPlacement"] diff --git a/bsb/placement/indicator.py b/bsb/placement/indicator.py index 19c023e93..eb495aa61 100644 --- a/bsb/placement/indicator.py +++ b/bsb/placement/indicator.py @@ -192,3 +192,6 @@ def _estim_for_voxels(self, voxels, key): return voxels.get_data(key).ravel().astype(float) * np.prod( voxels.get_size_matrix(copy=False), axis=1 ) + + +__all__ = ["PlacementIndicator"] diff --git a/bsb/placement/particle.py b/bsb/placement/particle.py index 3f32fcdca..6de855b0a 100644 --- a/bsb/placement/particle.py +++ b/bsb/placement/particle.py @@ -530,93 +530,6 @@ def solve_collisions(self): super().solve_collisions() -def plot_particle_system(system): - nc_particles = list(filter(lambda p: not p.colliding, system.particles)) - c_particles = list(filter(lambda p: p.colliding, system.particles)) - nc_trace = get_particles_trace(nc_particles) - c_trace = get_particles_trace( - c_particles, marker=dict(color="rgba(200, 100, 0, 1)", size=2) - ) - fig = go.Figure(data=[c_trace, nc_trace]) - if system.dimensions == 3: - fig.update_layout(scene_aspectmode="cube") - fig.layout.scene.xaxis.range = [0.0, system.size[0]] - fig.layout.scene.yaxis.range = [0.0, system.size[1]] - fig.layout.scene.zaxis.range = [0.0, system.size[2]] - fig.show() - - -def get_particles_trace(particles, dimensions=3, axes={"x": 0, "y": 1, "z": 2}, **kwargs): - trace_kwargs = { - "mode": "markers", - "marker": {"color": "rgba(100, 100, 100, 0.7)", "size": 1}, - } - trace_kwargs.update(kwargs) - if dimensions > 3: - raise ValueError("Maximum 3 dimensional plots. Unless you have mutant eyes.") - elif dimensions == 3: - return go.Scatter3d( - x=list(map(lambda p: p.position[axes["x"]], particles)), - y=list(map(lambda p: p.position[axes["y"]], particles)), - z=list(map(lambda p: p.position[axes["z"]], particles)), - **trace_kwargs, - ) - elif dimensions == 2: - return go.Scatter( - x=list(map(lambda p: p.position[axes["x"]], particles)), - y=list(map(lambda p: p.position[axes["y"]], particles)), - **trace_kwargs, - ) - elif dimensions == 1: - return go.Scatter( - x=list(map(lambda p: p.position[axes["x"]], particles)), **trace_kwargs - ) - - -def plot_detailed_system(system): - fig = go.Figure() - fig.update_layout(showlegend=False) - for particle in system.particles: - trace = get_particle_trace(particle) - fig.add_trace(trace) - fig.update_layout(scene_aspectmode="data") - fig.update_layout( - scene=dict( - xaxis=dict( - tick0=0, - dtick=system.voxels[0].size[0], - ), # Use the size of the first voxel to set ticks of axes - yaxis=dict( - tick0=650, - dtick=system.voxels[0].size[1], - ), - zaxis=dict( - tick0=800, - dtick=system.voxels[0].size[2], - ), - ) - ) - fig.show() - return fig - - -def get_particle_trace(particle): - theta = np.linspace(0, 2 * np.pi, 10) - phi = np.linspace(0, np.pi, 10) - x = np.outer(np.cos(theta), np.sin(phi)) * particle.radius + particle.position[0] - y = np.outer(np.sin(theta), np.sin(phi)) * particle.radius + particle.position[1] - z = np.outer(np.ones(10), np.cos(phi)) * particle.radius + particle.position[2] - return go.Surface( - x=x, - y=y, - z=z, - surfacecolor=np.zeros(10) + int(particle.colliding), - colorscale=[[0, "rgb(100, 100, 100)"], [1, "rgb(200, 100, 0)"]], - opacity=0.5 + 0.5 * int(particle.colliding), - showscale=False, - ) - - def sphere_volume(radius): return 4 / 3 * np.pi * radius**3 @@ -716,3 +629,16 @@ def find_neighbourhood(self, particle): return Neighbourhood( epicenter, neighbours, neighbourhood_radius, partners, partner_radius ) + + +__all__ = [ + "AdaptiveNeighbourhood", + "LargeParticleSystem", + "Neighbourhood", + "Particle", + "ParticlePlacement", + "ParticleSystem", + "ParticleVoxel", + "RandomPlacement", + "SmallestNeighbourhood", +] diff --git a/bsb/placement/satellite.py b/bsb/placement/satellite.py index 4211e1c9e..41af846c9 100644 --- a/bsb/placement/satellite.py +++ b/bsb/placement/satellite.py @@ -5,8 +5,8 @@ import numpy as np from .. import config -from ..config import refs, types -from ..exceptions import * +from ..config import refs +from ..exceptions import PlacementWarning from ..reporting import report, warn from .indicator import PlacementIndicator from .strategy import PlacementStrategy @@ -101,9 +101,7 @@ def place_type(self, chunk, indicator): # Initialise satellite position array self.satellites_pos = np.empty([len(planet_cells), 3]) report( - "Checking overlap and bounds of satellite {} cells...".format( - cell_type.name, - ), + f"Checking overlap and bounds of satellite {cell_type.name} cells...", level=3, ) # To keep track of not placed particles that are not respecting the bounds or distances. @@ -183,3 +181,6 @@ def place_type(self, chunk, indicator): scaffold._planets[cell_type.name].extend(planet_ids) self.place_cells(indicator, satellites_pos, chunk=chunk) + + +__all__ = ["Satellite", "SatelliteIndicator"] diff --git a/bsb/placement/strategy.py b/bsb/placement/strategy.py index 9efb4779c..636f5f092 100644 --- a/bsb/placement/strategy.py +++ b/bsb/placement/strategy.py @@ -195,14 +195,13 @@ def queue(self, pool, chunk_size): report(f"Queued {len(self._queued_jobs)} jobs for {self.name}", level=2) +@config.node class Entities(PlacementStrategy): """ Implementation of the placement of entities that do not have a 3D position, but that need to be connected with other cells of the network. """ - entities = True - def queue(self, pool, chunk_size): # Entities ignore chunks since they don't intrinsically store any data. pool.queue_placement(self, Chunk([0, 0, 0], chunk_size)) @@ -217,3 +216,6 @@ def place(self, chunk, indicators): for p in self.partitions ) self.scaffold.create_entities(cell_type, n) + + +__all__ = ["Entities", "FixedPositions", "PlacementStrategy"] diff --git a/bsb/plugins.py b/bsb/plugins.py index 56707fb17..9ecd31d07 100644 --- a/bsb/plugins.py +++ b/bsb/plugins.py @@ -74,3 +74,5 @@ def _decorate_advert(advert, entry): # Registry to insert plugins without having to install them, intended for testing purposes. _unittest_plugins = defaultdict(list) + +__all__ = ["discover"] diff --git a/bsb/postprocessing.py b/bsb/postprocessing.py index 5f14e1f9c..9b8451508 100644 --- a/bsb/postprocessing.py +++ b/bsb/postprocessing.py @@ -174,3 +174,12 @@ def after_connectivity(self): def _invert_append(self, old): return np.concatenate((old, np.stack((old[:, 1], old[:, 0]), axis=1)), axis=0) + + +__all__ = [ + "BidirectionalContact", + "MissingAxon", + "PostProcessingHook", + "Relay", + "SpoofDetails", +] diff --git a/bsb/profiling.py b/bsb/profiling.py index d6c683740..c53a7e8e1 100644 --- a/bsb/profiling.py +++ b/bsb/profiling.py @@ -10,7 +10,8 @@ from uuid import uuid4 import bsb.options -from bsb.services import MPI + +from .services import MPI class Meter: @@ -171,3 +172,14 @@ def decorator(g): def view_profile(fstem): ProfilingSession.load(fstem).view() + + +__all__ = [ + "Meter", + "ProfilingSession", + "activate_session", + "get_active_session", + "meter", + "node_meter", + "view_profile", +] diff --git a/bsb/reporting.py b/bsb/reporting.py index 52d790169..3e140c10b 100644 --- a/bsb/reporting.py +++ b/bsb/reporting.py @@ -169,3 +169,15 @@ def setup_reporting(): "Unable to create unbuffered wrapper around `sys.stdout`" + f" ({sys.stdout.__class__.__name__})." ) + + +__all__ = [ + "get_report_file", + "in_notebook", + "in_pytest", + "read_report_file", + "report", + "set_report_file", + "setup_reporting", + "warn", +] diff --git a/bsb/services/__init__.py b/bsb/services/__init__.py index eacfce0a5..22ed9130a 100644 --- a/bsb/services/__init__.py +++ b/bsb/services/__init__.py @@ -17,6 +17,7 @@ """ from .pool import JobPool as _JobPool # noqa +from .pool import WorkflowError JobPool = _JobPool """ @@ -32,4 +33,4 @@ def register_service(attr, provider): globals()[attr] = provider -__all__ = ["MPI", "MPILock", "JobPool", "register_service"] +__all__ = ["MPI", "MPILock", "JobPool", "register_service", "WorkflowError"] diff --git a/bsb/services/_pool_listeners.py b/bsb/services/_pool_listeners.py index 595cf86d2..c3196c2d8 100644 --- a/bsb/services/_pool_listeners.py +++ b/bsb/services/_pool_listeners.py @@ -2,11 +2,10 @@ import datetime from typing import cast -from bsb.services.pool import PoolJobUpdateProgress, PoolProgress, PoolProgressReason +from .pool import PoolJobUpdateProgress, PoolProgress, PoolProgressReason class Listener(abc.ABC): - @abc.abstractmethod def __call__(self, progress: PoolProgress): pass diff --git a/bsb/services/pool.py b/bsb/services/pool.py index c3a16ca78..7ffebc77b 100644 --- a/bsb/services/pool.py +++ b/bsb/services/pool.py @@ -366,7 +366,7 @@ class ConnectivityJob(Job): """ def __init__(self, pool, strategy, pre_roi, post_roi, deps=None): - from bsb.storage import chunklist + from ..storage import chunklist args = (strategy.name, pre_roi, post_roi) context = SubmissionContext( diff --git a/bsb/simulation/__init__.py b/bsb/simulation/__init__.py index 24a9e30db..2cdc6adbd 100644 --- a/bsb/simulation/__init__.py +++ b/bsb/simulation/__init__.py @@ -14,3 +14,6 @@ def get_simulation_adapter(name: str): from ._backends import get_simulation_adapters return get_simulation_adapters()[name] + + +__all__ = ["SimulationBackendPlugin", "get_simulation_adapter"] diff --git a/bsb/simulation/adapter.py b/bsb/simulation/adapter.py index 256ee839b..892e27dcb 100644 --- a/bsb/simulation/adapter.py +++ b/bsb/simulation/adapter.py @@ -113,3 +113,6 @@ def collect(self, simulation, simdata, simresult, comm=None): def add_progress_listener(self, listener): self._progress_listeners.append(listener) + + +__all__ = ["AdapterProgress", "SimulationData", "SimulatorAdapter"] diff --git a/bsb/simulation/cell.py b/bsb/simulation/cell.py index 5ea759b0f..977ed0d15 100644 --- a/bsb/simulation/cell.py +++ b/bsb/simulation/cell.py @@ -33,3 +33,6 @@ def __lt__(self, other): def get_placement_set(self, chunks=None): return self.cell_type.get_placement_set(chunks=chunks) + + +__all__ = ["CellModel"] diff --git a/bsb/simulation/component.py b/bsb/simulation/component.py index 98aa36c42..8b5d82921 100644 --- a/bsb/simulation/component.py +++ b/bsb/simulation/component.py @@ -15,3 +15,6 @@ def simulation(self): @obj_str_insert def __str__(self): return f"'{self.name}'" + + +__all__ = ["SimulationComponent"] diff --git a/bsb/simulation/connection.py b/bsb/simulation/connection.py index 58955229a..544103eaa 100644 --- a/bsb/simulation/connection.py +++ b/bsb/simulation/connection.py @@ -1,11 +1,6 @@ -import typing - from .. import config from .component import SimulationComponent -if typing.TYPE_CHECKING: - from ..connectivity import ConnectionStrategy - @config.node class ConnectionModel(SimulationComponent): @@ -13,3 +8,6 @@ class ConnectionModel(SimulationComponent): def get_connectivity_set(self): return self.scaffold.get_connectivity_set(self.tag) + + +__all__ = ["ConnectionModel"] diff --git a/bsb/simulation/device.py b/bsb/simulation/device.py index f45d50c2d..dfcce51e4 100644 --- a/bsb/simulation/device.py +++ b/bsb/simulation/device.py @@ -10,3 +10,6 @@ def implement(self, adapter, simulation, simdata): + self.__class__.__name__ + " device does not implement any `implement` function." ) + + +__all__ = ["DeviceModel"] diff --git a/bsb/simulation/parameter.py b/bsb/simulation/parameter.py index 41fd21ef8..b1354efc9 100644 --- a/bsb/simulation/parameter.py +++ b/bsb/simulation/parameter.py @@ -10,3 +10,6 @@ def __init__(self, value=None, /, **kwargs): @config.dynamic(attr_name="type", auto_classmap=True, required=False) class Parameter: value: ParameterValue = config.attr(type=ParameterValue) + + +__all__ = ["Parameter", "ParameterValue"] diff --git a/bsb/simulation/results.py b/bsb/simulation/results.py index d0cdd8c52..d7c2c51d3 100644 --- a/bsb/simulation/results.py +++ b/bsb/simulation/results.py @@ -57,3 +57,6 @@ def write(self, filename, mode): class SimulationRecorder: def flush(self, segment: "neo.core.Segment"): raise NotImplementedError("Recorders need to implement the `flush` function.") + + +__all__ = ["SimulationResult", "SimulationRecorder"] diff --git a/bsb/simulation/simulation.py b/bsb/simulation/simulation.py index 998c39efb..da14673ba 100644 --- a/bsb/simulation/simulation.py +++ b/bsb/simulation/simulation.py @@ -1,10 +1,6 @@ -import itertools -import types import typing from time import time -import numpy as np - from .. import config from ..config import types as cfgtypes from ..config._attrs import cfgdict, cfglist @@ -65,3 +61,6 @@ def get_connectivity_sets( model: self.scaffold.get_connectivity_set(model.name) for model in sorted(self.connection_models.values()) } + + +__all__ = ["ProgressEvent", "Simulation"] diff --git a/bsb/simulation/targetting.py b/bsb/simulation/targetting.py index c04100a46..84148ae30 100755 --- a/bsb/simulation/targetting.py +++ b/bsb/simulation/targetting.py @@ -1,7 +1,5 @@ -import copy import functools import math -import random import typing import numpy as np @@ -285,3 +283,22 @@ def get_locations(self, cell): selected.append(loc) branches.add(loc._loc[0]) return selected + + +__all__ = [ + "BranchLocTargetting", + "ByIdTargetting", + "ByLabelTargetting", + "CellModelFilter", + "CellModelTargetting", + "CellTargetting", + "ConnectionTargetting", + "CylindricalTargetting", + "FractionFilter", + "LabelTargetting", + "LocationTargetting", + "RepresentativesTargetting", + "SomaTargetting", + "SphericalTargetting", + "Targetting", +] diff --git a/bsb/storage/__init__.py b/bsb/storage/__init__.py index 410198eb3..0ae031e00 100644 --- a/bsb/storage/__init__.py +++ b/bsb/storage/__init__.py @@ -19,7 +19,15 @@ from ..exceptions import UnknownStorageEngineError from ..services import MPI from ._chunks import Chunk, chunklist -from ._files import FileDependency, FileDependencyNode, NrrdDependencyNode +from ._files import ( + CodeDependencyNode, + FileDependency, + FileDependencyNode, + MorphologyDependencyNode, + MorphologyOperation, + NrrdDependencyNode, + Operation, +) from .interfaces import ConnectivitySet, FileStore, MorphologyRepository, PlacementSet # Pretend `Chunk` is defined here, for UX. It's only defined in `_chunks` to avoid @@ -445,3 +453,26 @@ def view_support(engine=None): # and replaced with its return value. _engines = {} _available_engines = discover_engines() + + +__all__ = [ + "Chunk", + "CodeDependencyNode", + "FileDependency", + "FileDependencyNode", + "NotSupported", + "MorphologyDependencyNode", + "MorphologyOperation", + "NrrdDependencyNode", + "Operation", + "Storage", + "chunklist", + "create_engine", + "discover_engines", + "get_engine_node", + "get_engines", + "init_engines", + "open_storage", + "register_engine", + "view_support", +] diff --git a/bsb/storage/_files.py b/bsb/storage/_files.py index 95bcf3553..fa545f26a 100644 --- a/bsb/storage/_files.py +++ b/bsb/storage/_files.py @@ -576,7 +576,7 @@ def queue(self, pool): Add the loading of the current morphology to a job queue. :param pool: Queue of jobs. - :type pool:bsb.services.pool.JobPool + :type pool: bsb.services.pool.JobPool """ def create_morphology(scaffold, i): @@ -613,3 +613,6 @@ def job(scaffold, i, j): for k in range(len(self.files)): # The lambda serves to bind the closure arguments pool.queue(job, (self._config_index, k)) + + +__all__ = ["UriScheme", "UrlScheme", "FileScheme", "NeuroMorphoScheme"] diff --git a/bsb/storage/_util.py b/bsb/storage/_util.py index 1e2fa92e7..b482dee18 100644 --- a/bsb/storage/_util.py +++ b/bsb/storage/_util.py @@ -24,7 +24,7 @@ def __getattr__(name): @functools.cache def _get_cache_storage(): - from bsb.storage import Storage + from ..storage import Storage return Storage("fs", _cache_path) diff --git a/bsb/storage/decorators.py b/bsb/storage/decorators.py index c6124c281..6d36ab449 100644 --- a/bsb/storage/decorators.py +++ b/bsb/storage/decorators.py @@ -39,3 +39,6 @@ def wrapper(self, *args, **kwargs): return wrapper return decorator + + +__all__ = ["on_main", "on_main_until"] diff --git a/bsb/storage/fs/file_store.py b/bsb/storage/fs/file_store.py index d3857c233..07ad9eb8c 100644 --- a/bsb/storage/fs/file_store.py +++ b/bsb/storage/fs/file_store.py @@ -102,7 +102,7 @@ def load_active_config(self): :rtype: :class:`~.config.Configuration` :raises Exception: When there's no active configuration in the file store. """ - from bsb.config import Configuration + from ...config import Configuration stored = self.find_meta("active_config", True) if stored is None: diff --git a/bsb/storage/interfaces.py b/bsb/storage/interfaces.py index c03e54515..d59827744 100644 --- a/bsb/storage/interfaces.py +++ b/bsb/storage/interfaces.py @@ -7,7 +7,6 @@ from .. import config, plugins from .._util import immutable, obj_str_insert -from ..morphologies import Morphology from ..trees import BoxTree from ._chunks import Chunk @@ -1190,3 +1189,21 @@ def _cached_load(self, labels): class GeneratedMorphology(StoredMorphology): def __init__(self, name, generated, meta): super().__init__(name, lambda: generated, meta) + + +__all__ = [ + "ConnectivityIterator", + "ConnectivitySet", + "Engine", + "FileStore", + "GeneratedMorphology", + "Interface", + "MorphologyRepository", + "NetworkDescription", + "NoopLock", + "PlacementSet", + "ReadOnlyManager", + "StorageNode", + "StoredFile", + "StoredMorphology", +] diff --git a/bsb/topology/__init__.py b/bsb/topology/__init__.py index e401a4f2f..4cee1df3c 100644 --- a/bsb/topology/__init__.py +++ b/bsb/topology/__init__.py @@ -2,8 +2,6 @@ Topology module """ -import numpy as np - from ._layout import box_layout from .partition import AllenStructure, Layer, NrrdVoxels, Partition from .region import Region, RegionGroup, Stack @@ -104,3 +102,13 @@ def collect_deps(region, ignore): collect_deps(region, managed) return list(set(list(regions)) - managed) + + +__all__ = [ + "box_layout", + "create_topology", + "get_partitions", + "get_root_regions", + "is_partition", + "is_region", +] diff --git a/bsb/topology/partition.py b/bsb/topology/partition.py index d8a6367a1..b81fada2d 100644 --- a/bsb/topology/partition.py +++ b/bsb/topology/partition.py @@ -14,13 +14,11 @@ from .. import config from ..config import types from ..exceptions import ( - AllenApiError, ConfigurationError, LayoutError, NodeNotFoundError, RequirementError, ) -from ..reporting import report from ..storage import Chunk from ..storage._files import NrrdDependencyNode from ..storage._util import _cached_file @@ -675,3 +673,6 @@ def repeater(val): return first return repeater + + +__all__ = ["AllenStructure", "Layer", "NrrdVoxels", "Partition", "Rhomboid", "Voxels"] diff --git a/bsb/topology/region.py b/bsb/topology/region.py index 7432b1080..e305cfc06 100644 --- a/bsb/topology/region.py +++ b/bsb/topology/region.py @@ -125,3 +125,6 @@ def translate(self, offset): def scale(self, factors): for child in self.children: child.scale(factors) + + +__all__ = ["Region", "RegionGroup", "Stack"] diff --git a/bsb/voxels.py b/bsb/voxels.py index 8a453f6b9..bc46326ff 100644 --- a/bsb/voxels.py +++ b/bsb/voxels.py @@ -635,3 +635,6 @@ def _is_broadcastable(shape1, shape2): def _squash_zero(arr): return np.where(np.isclose(arr, 0), np.finfo(float).max, arr) + + +__all__ = ["BoxTree", "VoxelData", "VoxelSet"] diff --git a/docs/bsb/bsb.rst b/docs/bsb/bsb.rst index e21c193ec..868722e41 100644 --- a/docs/bsb/bsb.rst +++ b/docs/bsb/bsb.rst @@ -97,6 +97,8 @@ bsb.trees module .. automodule:: bsb.trees :members: +.. autoclass:: bsb.trees._BoxRTree + bsb.voxels module ----------------- diff --git a/docs/bsb/bsb.services.rst b/docs/bsb/bsb.services.rst index 79b0c85dd..df86646e8 100644 --- a/docs/bsb/bsb.services.rst +++ b/docs/bsb/bsb.services.rst @@ -1,5 +1,5 @@ -bsb.simulation package -====================== +bsb.services package +==================== Submodules ---------- diff --git a/docs/bsb/bsb.storage.rst b/docs/bsb/bsb.storage.rst index 2a352411b..dc5acf740 100644 --- a/docs/bsb/bsb.storage.rst +++ b/docs/bsb/bsb.storage.rst @@ -22,14 +22,13 @@ Module contents :members: :undoc-members: :show-inheritance: + :exclude-members: chunklist Dev --- -.. autoclass:: bsb.storage._files.FileDependency +.. autoclass:: bsb.storage._files.FilePipelineMixin -.. autoclass:: bsb.storage._files.CodeDependencyNode +.. autoclass:: bsb.storage._files.MorphologyOperationCallable -.. autoclass:: bsb.storage._files.MorphologyDependencyNode - -.. autoclass:: bsb.storage._files.NrrdDependencyNode \ No newline at end of file +.. autoclass:: bsb.storage._files.OperationCallable \ No newline at end of file diff --git a/docs/cli/intro.rst b/docs/cli/intro.rst index f047f257d..bec9600f1 100644 --- a/docs/cli/intro.rst +++ b/docs/cli/intro.rst @@ -31,7 +31,7 @@ If no parent is given the command is added under the root ``bsb`` command: # BaseCommand inherits from BsbCommand too but contains the default CLI command # functions already implemented. - from bsb.commands import BaseCommand + from bsb import BaseCommand class MyCommand(BaseCommand, name="test"): def handler(self, namespace): diff --git a/docs/cli/options.rst b/docs/cli/options.rst index 301cc1638..9a1950590 100644 --- a/docs/cli/options.rst +++ b/docs/cli/options.rst @@ -152,8 +152,7 @@ inherits from :class:`~.option.BsbOption`: .. code-block:: python - from bsb.options import BsbOption - from bsb.reporting import report + from bsb import BsbOption, report class GreetingsOption( BsbOption, diff --git a/docs/config/files.rst b/docs/config/files.rst index 9b657f761..0ced215eb 100644 --- a/docs/config/files.rst +++ b/docs/config/files.rst @@ -51,8 +51,7 @@ and handle the values: .. code-block:: python - from bsb import config - from bsb.connectivity import ConnectionStrategy + from bsb import config, ConnectionStrategy @config.node class MySpecialConnection(ConnectionStrategy): diff --git a/docs/config/nodes.rst b/docs/config/nodes.rst index b6fa107fe..55c6d584b 100644 --- a/docs/config/nodes.rst +++ b/docs/config/nodes.rst @@ -221,8 +221,7 @@ conflict. To solve it, use :func:`.config.compose_nodes`: .. code-block:: python - from bsb import config - from bsb.config import compose_nodes + from bsb import config, compose_nodes @config.node class NodeA: diff --git a/docs/config/types.rst b/docs/config/types.rst index dc2e258a8..5d48bed0c 100644 --- a/docs/config/types.rst +++ b/docs/config/types.rst @@ -20,8 +20,7 @@ Examples .. code-block:: python - from bsb import config - from bsb.config import types + from bsb import config, types @config.node class TestNode diff --git a/docs/connectivity/component.rst b/docs/connectivity/component.rst index 344a92d86..063ae36d7 100644 --- a/docs/connectivity/component.rst +++ b/docs/connectivity/component.rst @@ -102,9 +102,7 @@ The example connects cells that are near each other, between a :guilabel:`min` a .. code-block:: python - from bsb.connectivity import ConnectionStrategy - from bsb.exceptions import ConfigurationError - from bsb import config + from bsb import ConnectionStrategy, ConfigurationError, config import numpy as np import scipy.spatial.distance as dist diff --git a/docs/dev/hooks.rst b/docs/dev/hooks.rst index 79681950f..f3ad18433 100644 --- a/docs/dev/hooks.rst +++ b/docs/dev/hooks.rst @@ -36,9 +36,7 @@ hooked onto the given class: .. code-block:: python - from bsb import config - from bsb.core import Scaffold - from bsb.simulation import Simulation + from bsb import config, Scaffold, Simulation @config.on(Simulation, "boot") def print_something(self): diff --git a/docs/getting-started/getting_started.py b/docs/getting-started/getting_started.py index 852554e56..ec8bdac57 100644 --- a/docs/getting-started/getting_started.py +++ b/docs/getting-started/getting_started.py @@ -1,7 +1,7 @@ +from bsb_plot import plot_network + import bsb.options -from bsb.config import from_json -from bsb.core import Scaffold -from bsb.plotting import plot_network +from bsb import Scaffold, from_json bsb.options.verbosity = 3 config = from_json("network_configuration.json") diff --git a/docs/getting-started/include_morphos.py b/docs/getting-started/include_morphos.py index 0809cb0cd..7fbd72d69 100644 --- a/docs/getting-started/include_morphos.py +++ b/docs/getting-started/include_morphos.py @@ -1,9 +1,7 @@ -from bsb_plotting import plot_network +from bsb_plot import plot_network import bsb.options -from bsb.config import from_json -from bsb.core import Scaffold -from bsb.topology import Stack +from bsb import Scaffold, Stack, from_json bsb.options.verbosity = 3 config = from_json("network_configuration.json") diff --git a/docs/getting-started/installation.rst b/docs/getting-started/installation.rst index 7d6caabd4..2e3c857a1 100644 --- a/docs/getting-started/installation.rst +++ b/docs/getting-started/installation.rst @@ -17,7 +17,7 @@ You can verify that the installation works with: .. code-block:: python - from bsb.core import Scaffold + from bsb import Scaffold # Create an empty scaffold network with the default configuration. scaffold = Scaffold() diff --git a/docs/getting-started/labels.rst b/docs/getting-started/labels.rst index 9fa3e6a6f..ed11fb467 100644 --- a/docs/getting-started/labels.rst +++ b/docs/getting-started/labels.rst @@ -40,7 +40,7 @@ Example of a Python class for labeling neurons. .. code-block:: python - from bsb.postprocessing import PostProcessingHook + from bsb import PostProcessingHook class LabelCellA(PostProcessingHook): diff --git a/docs/getting-started/layer.rst b/docs/getting-started/layer.rst index 2267bd127..5bd1b6dad 100644 --- a/docs/getting-started/layer.rst +++ b/docs/getting-started/layer.rst @@ -126,35 +126,19 @@ Scripting The value of layers in scripting is usually limited because they only contain spatial information. -Retrieving layers -================= - -Layers can be retrieved from a :class:`ScaffoldConfig <.config.ScaffoldConfig>`: +Retrieving partitions +===================== .. code-block:: python - from bsb.config import JSONConfig + from bsb import from_json - config = JSONConfig("mouse_cerebellum") - layer = config.get_layer(name="granular_layer") + config = from_json("mouse_cerebellum.json") + layer = config.partitions.granular_layer A :class:`Scaffold <.core.Scaffold>` also stores its configuration: .. code-block:: python - layer = scaffold.configuration.get_layer(name="granular_layer") - -All :class:`Layered <.placement.Layered>` placement strategies store a reference to their layer -instance: - -.. code-block:: python - - placement = scaffold.get_cell_type("granule_cell").placement - layer_name = placement.layer - layer = placement.layer_instance - -.. note:: - - The instance of a placement strategy's layer is added only after initialisation of the - placement strategy, which occurs only after the scaffold is bootstrapped (so after - ``scaffold = Scaffold(config)``) + scaffold = from_storage("network.hdf5") + layer = scaffold.partitions.granular_layer diff --git a/docs/guides/components.rst b/docs/guides/components.rst index 27ef7c304..df0ee145c 100644 --- a/docs/guides/components.rst +++ b/docs/guides/components.rst @@ -63,8 +63,7 @@ cells: .. code-block:: python - from bsb.cell_types import MorphologySelector - from bsb import config + from bsb import config, MorphologySelector @config.node class MySizeSelector(MorphologySelector): diff --git a/docs/morphologies/intro.rst b/docs/morphologies/intro.rst index 2f895d97d..50c2abd08 100644 --- a/docs/morphologies/intro.rst +++ b/docs/morphologies/intro.rst @@ -37,7 +37,7 @@ if you already have the content of a file you can pass that directly into .. code-block:: python - from bsb.morphologies import parse_morphology_file + from bsb import parse_morphology_file morpho = parse_morphology_file("./my_file.swc") @@ -51,7 +51,7 @@ morphologies. To support these diverse approaches the framework provides configu .. code-block:: python - from bsb.morphologies import parse_morphology_file + from bsb import parse_morphology_file morpho = parse_morphology_file("./my_file.swc", parser="morphio", flags=["no_duplicates"]) @@ -72,7 +72,7 @@ the :class:`~.morphologies.Morphology` constructor: .. code-block:: python - from bsb.morphologies import Branch, Morphology + from bsb import Branch, Morphology import numpy as np root = Branch( @@ -415,8 +415,7 @@ presence of a user defined metadata ``"size"``: .. code-block:: python - from bsb.cell_types import MorphologySelector - from bsb import config + from bsb import config, MorphologySelector @config.node class MySizeSelector(MorphologySelector, classmap_entry="by_size"): @@ -508,7 +507,7 @@ rotation distributors, and any other property distributor: .. code-block:: python - from bsb.placement.distributor import RoundRobinMorphologies + from bsb import RoundRobinMorphologies network.placement.placement_A.distribute.morphologies = RoundRobinMorphologies() diff --git a/docs/morphologies/morphology-set.rst b/docs/morphologies/morphology-set.rst index 603101d31..5da63b57a 100644 --- a/docs/morphologies/morphology-set.rst +++ b/docs/morphologies/morphology-set.rst @@ -18,7 +18,7 @@ stops. Soft caching is available by passing ``cache=True`` to .. code-block:: python - from bsb.core import from_storage + from bsb import from_storage network = from_storage ps = network.get_placement_set("my_cell") diff --git a/docs/morphologies/repository.rst b/docs/morphologies/repository.rst index 5fd9e73c8..a99dc3bad 100644 --- a/docs/morphologies/repository.rst +++ b/docs/morphologies/repository.rst @@ -10,7 +10,7 @@ To access an MR, a :class:`~.storage.Storage` object is required: .. code-block:: python - from bsb.storage import Storage + from bsb import Storage store = Storage("hdf5", "morphologies.hdf5") mr = store.morphologies @@ -20,7 +20,7 @@ Similarly, the built-in MR of a network is accessible as ``network.morphologies` .. code-block:: python - from bsb.core import from_storage + from bsb import from_storage network = from_hdf("my_existing_model.hdf5") mr = network.morphologies diff --git a/docs/placement/placement-set.rst b/docs/placement/placement-set.rst index 8dcf76d9d..9049e9772 100644 --- a/docs/placement/placement-set.rst +++ b/docs/placement/placement-set.rst @@ -20,7 +20,7 @@ same :class:`~.storage.interfaces.PlacementSet`. If the placement set does not e .. code-block:: python - from bsb.core import from_storage + from bsb import from_storage network = from_storage("my_network.hdf5") ps = network.get_placement_set("my_cell") diff --git a/docs/topology/partitions.rst b/docs/topology/partitions.rst index e86d0ae56..54e8e9a4e 100644 --- a/docs/topology/partitions.rst +++ b/docs/topology/partitions.rst @@ -37,7 +37,7 @@ default it will load all the nonzero values in a source file: .. code-block:: python - from bsb.topology.partition import NrrdVoxels + from bsb import NrrdVoxels my_voxel_partition = NrrdVoxels(source="data/my_nrrd_data.nrrd", voxel_size=25) @@ -81,7 +81,7 @@ structure, and other files contain cell population density values, gene expressi .. code-block:: python - from bsb.topology.partition import NrrdVoxels + from bsb import NrrdVoxels partition = NrrdVoxels( mask_value=55, @@ -123,7 +123,7 @@ appear in the :guilabel:`sources` attribute: .. code-block:: python - from bsb.topology.partition import NrrdVoxels + from bsb import NrrdVoxels partition = NrrdVoxels( mask_value=55, @@ -170,7 +170,7 @@ a name with each column. Data columns can then be indexed as strings: .. code-block:: python - from bsb.topology.partition import NrrdVoxels + from bsb import NrrdVoxels partition = NrrdVoxels( mask_value=55, @@ -243,7 +243,7 @@ files. Each source file will be converted into a data column on the voxelset: .. code-block:: python - from bsb.topology.partition import AllenStructure + from bsb import AllenStructure partition = AllenStructure( # Loads the "ventroanterolateral thalamic nucleus" from the diff --git a/examples/atlas/allen_structures.py b/examples/atlas/allen_structures.py index 833dded71..684a2a39b 100644 --- a/examples/atlas/allen_structures.py +++ b/examples/atlas/allen_structures.py @@ -1,7 +1,7 @@ import nrrd import numpy as np -from bsb.topology import AllenStructure +from bsb import AllenStructure # For this example, we'll be looking into the declive: struct = "DEC" diff --git a/examples/distributors/morphology_generator.py b/examples/distributors/morphology_generator.py index 0b4101a5c..dd8a6c304 100644 --- a/examples/distributors/morphology_generator.py +++ b/examples/distributors/morphology_generator.py @@ -1,7 +1,6 @@ import numpy as np -from bsb.morphologies import Branch, Morphology -from bsb.placement.distributor import MorphologyGenerator +from bsb import Branch, Morphology, MorphologyGenerator class TouchTheBottomMorphologies(MorphologyGenerator, classmap_entry="touchdown"): diff --git a/examples/distributors/space_aware_morphology_distributor.py b/examples/distributors/space_aware_morphology_distributor.py index 153900daf..0715f83be 100644 --- a/examples/distributors/space_aware_morphology_distributor.py +++ b/examples/distributors/space_aware_morphology_distributor.py @@ -1,7 +1,7 @@ import numpy as np from scipy.stats.distributions import norm -from bsb.placement.distributor import MorphologyDistributor +from bsb import MorphologyDistributor class SmallerTopMorphologies(MorphologyDistributor, classmap_entry="small_top"): diff --git a/examples/morphologies/import.py b/examples/morphologies/import.py index ea8bc30c7..f9d23e81f 100644 --- a/examples/morphologies/import.py +++ b/examples/morphologies/import.py @@ -1,11 +1,11 @@ # Import a morphology from a file -from bsb.morphologies import parse_morphology_file +from bsb import parse_morphology_file morpho = parse_morphology_file("my_file.swc") print(f"My morphology has {len(morpho)} points and {len(morpho.branches)} branches.") # Store it in a MorphologyRepository to use it later. -from bsb.storage import Storage +from bsb import Storage store = Storage("hdf5", "morphologies.hdf5") store.morphologies.save("MyCell", morpho) diff --git a/examples/morphologies/labels.py b/examples/morphologies/labels.py index de34001fa..2a357d99c 100644 --- a/examples/morphologies/labels.py +++ b/examples/morphologies/labels.py @@ -1,6 +1,6 @@ import numpy as np -from bsb.core import from_storage +from bsb import from_storage # Load the morphology network = from_storage("network.hdf5") diff --git a/examples/morphologies/neuromorpho.py b/examples/morphologies/neuromorpho.py index 52d3bc15f..b8f61cfc7 100644 --- a/examples/morphologies/neuromorpho.py +++ b/examples/morphologies/neuromorpho.py @@ -1,5 +1,4 @@ -from bsb.config import from_json -from bsb.core import Scaffold +from bsb import Scaffold, from_json cfg = from_json("network_configuration.json") network = Scaffold(cfg) diff --git a/examples/morphologies/usage.py b/examples/morphologies/usage.py index 012a578fd..8b1d93c06 100644 --- a/examples/morphologies/usage.py +++ b/examples/morphologies/usage.py @@ -1,4 +1,4 @@ -from bsb.core import from_storage +from bsb import from_storage # Load the morphology network = from_storage("network.hdf5") diff --git a/examples/networks/access_config.py b/examples/networks/access_config.py index 86b4f9501..595287570 100644 --- a/examples/networks/access_config.py +++ b/examples/networks/access_config.py @@ -1,5 +1,5 @@ # How to access the configuration of a network -from bsb.core import from_storage +from bsb import from_storage network = from_storage("network.hdf5") print("My network was configured with", network.configuration) diff --git a/examples/networks/access_placement.py b/examples/networks/access_placement.py index b93f463e5..59983700b 100644 --- a/examples/networks/access_placement.py +++ b/examples/networks/access_placement.py @@ -1,7 +1,7 @@ # How to access and work with the placement data of a network import numpy as np -from bsb.core import from_storage +from bsb import from_storage network = from_storage("network.hdf5") for cell_type in network.cell_types: diff --git a/examples/networks/create_default.py b/examples/networks/create_default.py index 9350258e5..934ad8776 100644 --- a/examples/networks/create_default.py +++ b/examples/networks/create_default.py @@ -1,5 +1,5 @@ # Create a network with the default configuration. -from bsb.core import Scaffold +from bsb import Scaffold network = Scaffold() network.compile() diff --git a/examples/networks/create_from_cfg.py b/examples/networks/create_from_cfg.py index aaeb418f1..18f849ade 100644 --- a/examples/networks/create_from_cfg.py +++ b/examples/networks/create_from_cfg.py @@ -1,6 +1,5 @@ # Create a network from a custom configuration object. -from bsb.config import Configuration -from bsb.core import Scaffold +from bsb import Configuration, Scaffold cfg = Configuration() # Let's set a file name for the network diff --git a/examples/networks/load.py b/examples/networks/load.py index fed46b4cd..04fb87a9c 100644 --- a/examples/networks/load.py +++ b/examples/networks/load.py @@ -1,4 +1,4 @@ # Example that shows how to load a network that was previously created -from bsb.core import from_storage +from bsb import from_storage network = from_storage("my_network.hdf5") diff --git a/examples/networks/reconfiguring.py b/examples/networks/reconfiguring.py index 4edacfbfe..a6cfc05a0 100644 --- a/examples/networks/reconfiguring.py +++ b/examples/networks/reconfiguring.py @@ -1,6 +1,6 @@ # Example that shows how to overwrite the configuration inside of an existing network -from bsb.config import JSONConfig -from bsb.output import HDF5Formatter +from bsb import Configuration, from_storage -config = JSONConfig("new_config.json") -HDF5Formatter.reconfigure("my_network.hdf5", config) +network = from_storage("network.hdf5") +new_config = Configuration.default() +network.storage.store_active_config(new_config) diff --git a/examples/plotting/plotting_with_branch_colors.py b/examples/plotting/plotting_with_branch_colors.py index 21778e122..379763c90 100644 --- a/examples/plotting/plotting_with_branch_colors.py +++ b/examples/plotting/plotting_with_branch_colors.py @@ -1,6 +1,6 @@ -from bsb.output import MorphologyRepository as MR -from bsb.plotting import plot_morphology +from bsb_plot import plot_morphology -mr = MR("morphologies.hdf5") -pc = mr.load("PurkinjeCellNew") -plot_morphology(pc, color={"soma": "red", "dendrites": "blue", "axon": "green"}) +from bsb import parse_morphology_file + +morphology = parse_morphology_file("cell.swc") +plot_morphology(morphology, color={"soma": "red", "dendrites": "blue", "axon": "green"}) diff --git a/examples/simulation/nest/repeated_simulations.py b/examples/simulation/nest/repeated_simulations.py index 38a554096..1d76ce849 100644 --- a/examples/simulation/nest/repeated_simulations.py +++ b/examples/simulation/nest/repeated_simulations.py @@ -1,6 +1,6 @@ import os -from bsb.core import from_storage +from bsb import from_storage network = from_storage("my_network.hdf5") simulation = network.create_adapter("my_simulation") diff --git a/examples/simulation/parameter_sweep.py b/examples/simulation/parameter_sweep.py index 6cb829eed..f7afd7dae 100644 --- a/examples/simulation/parameter_sweep.py +++ b/examples/simulation/parameter_sweep.py @@ -1,10 +1,9 @@ # A module to read HDF5 data -import h5py # A module to run NEURON simulations in isolation import nrnsub -from bsb.core import from_storage +from bsb import from_storage # This decorator runs each call to the function in isolation diff --git a/tests/test_chunks.py b/tests/test_chunks.py index 78a883227..4280aeac6 100644 --- a/tests/test_chunks.py +++ b/tests/test_chunks.py @@ -10,7 +10,7 @@ timeout, ) -from bsb.storage import Chunk +from bsb import Chunk class TestChunks(unittest.TestCase, NumpyTestCase): diff --git a/tests/test_cli.py b/tests/test_cli.py index 5d6510f4b..cf01d7107 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -23,7 +23,6 @@ def test_availability(self): self.assertEqual(our_version, cli_version, "Could not access the BSB through CLI") def test_defaults(self): - import bsb.exceptions import bsb.options # Test the default verbosity @@ -36,7 +35,7 @@ def test_env_descriptor(self): import os import bsb.options - from bsb.option import BsbOption + from bsb import BsbOption class TestOption(BsbOption, name="_test_", env=("GRZLGRK",), script=("GRZLGRK",)): pass @@ -62,7 +61,7 @@ class TestOption(BsbOption, name="_test_", env=("GRZLGRK",), script=("GRZLGRK",) class TestOptions(unittest.TestCase): def test_get_cli_tags(self): - from bsb.option import BsbOption + from bsb import BsbOption class t1(BsbOption, name="t1", cli=("a",)): pass @@ -88,7 +87,7 @@ def test_plugins(self): def test_register(self): import bsb.exceptions import bsb.options - from bsb.option import BsbOption + from bsb import BsbOption # Test that registering an option into the module works class t1(BsbOption, name="testTTTT", script=("aaa",)): diff --git a/tests/test_compilation.py b/tests/test_compilation.py index dc72d10b7..40cd94b32 100644 --- a/tests/test_compilation.py +++ b/tests/test_compilation.py @@ -2,8 +2,7 @@ from bsb_test import NetworkFixture, RandomStorageFixture, get_test_config -from bsb.config import Configuration -from bsb.exceptions import InputError +from bsb import Configuration, InputError class TestSingleTypeCompilation( diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 66c2bc23c..6c1c23742 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -12,12 +12,7 @@ ) import bsb -from bsb import config -from bsb._package_spec import get_missing_requirement_reason -from bsb.config import Configuration, _attrs, compose_nodes, types -from bsb.config.refs import Reference -from bsb.core import Scaffold -from bsb.exceptions import ( +from bsb import ( CastError, CfgReferenceError, ClassMapMissingError, @@ -25,13 +20,18 @@ ConfigurationWarning, DynamicClassInheritanceError, DynamicObjectNotFoundError, + NrrdDependencyNode, PackageRequirementWarning, + RegionGroup, RequirementError, + Scaffold, UnfitClassCastError, UnresolvedClassCastError, + config, ) -from bsb.storage import NrrdDependencyNode -from bsb.topology.region import RegionGroup +from bsb._package_spec import get_missing_requirement_reason +from bsb.config import Configuration, _attrs, compose_nodes, types +from bsb.config.refs import Reference @config.root diff --git a/tests/test_connectivity.py b/tests/test_connectivity.py index 679463d3a..46e9faffb 100644 --- a/tests/test_connectivity.py +++ b/tests/test_connectivity.py @@ -12,10 +12,7 @@ skip_parallel, ) -from bsb.config import Configuration -from bsb.core import Scaffold -from bsb.morphologies import Branch, Morphology -from bsb.services import MPI +from bsb import MPI, Branch, Configuration, Morphology, Scaffold class TestAllToAll( diff --git a/tests/test_core.py b/tests/test_core.py index 0226c8f93..11b724832 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -2,9 +2,7 @@ from bsb_test import NetworkFixture, RandomStorageFixture -from bsb import core -from bsb.config import Configuration -from bsb.storage.interfaces import PlacementSet +from bsb import Configuration, PlacementSet, core class TestCore( diff --git a/tests/test_distributors.py b/tests/test_distributors.py index 23ddf8d62..88f39a02d 100644 --- a/tests/test_distributors.py +++ b/tests/test_distributors.py @@ -3,16 +3,17 @@ import numpy as np from bsb_test import NetworkFixture, RandomStorageFixture, get_data_path -from bsb.config import Configuration -from bsb.exceptions import DatasetNotFoundError, DistributorError -from bsb.morphologies import Morphology -from bsb.placement.distributor import ( +from bsb import ( + MPI, + Configuration, + DatasetNotFoundError, + DistributorError, + Morphology, MorphologyDistributor, MorphologyGenerator, VolumetricRotations, + WorkflowError, ) -from bsb.services import MPI -from bsb.services.pool import WorkflowError class OneNoneDistributor(MorphologyDistributor): diff --git a/tests/test_issues.py b/tests/test_issues.py index 857afbc4a..ee4b2a3a1 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -1,13 +1,15 @@ import os import unittest -from bsb import config -from bsb.cell_types import CellType -from bsb.config.refs import Reference -from bsb.exceptions import CfgReferenceError -from bsb.placement import FixedPositions -from bsb.placement.indicator import PlacementIndications -from bsb.storage import Chunk +from bsb import ( + CellType, + CfgReferenceError, + Chunk, + FixedPositions, + PlacementIndications, + Reference, + config, +) def relative_to_tests_folder(path): diff --git a/tests/test_jobs.py b/tests/test_jobs.py index aba74531c..9cbf545c2 100644 --- a/tests/test_jobs.py +++ b/tests/test_jobs.py @@ -11,14 +11,21 @@ timeout, ) -from bsb import config -from bsb.cell_types import CellType -from bsb.config import Configuration -from bsb.connectivity import ConnectionStrategy -from bsb.exceptions import JobCancelledError, JobPoolError -from bsb.mixins import NotParallel -from bsb.placement import FixedPositions, PlacementStrategy, RandomPlacement -from bsb.services import MPI +from bsb import ( + MPI, + CellType, + Chunk, + Configuration, + ConnectionStrategy, + FixedPositions, + JobCancelledError, + JobPoolError, + NotParallel, + Partition, + PlacementStrategy, + RandomPlacement, + config, +) from bsb.services.pool import ( Job, JobStatus, @@ -27,8 +34,6 @@ PoolStatus, WorkflowError, ) -from bsb.storage import Chunk -from bsb.topology import Partition def sleep_y(scaffold, x, y): diff --git a/tests/test_morphologies.py b/tests/test_morphologies.py index 99e0fe413..db97b404c 100644 --- a/tests/test_morphologies.py +++ b/tests/test_morphologies.py @@ -10,24 +10,24 @@ ) from scipy.spatial.transform import Rotation -from bsb._encoding import EncodedLabels -from bsb.config._config import Configuration -from bsb.core import Scaffold -from bsb.exceptions import CastError, EmptyBranchError, MorphologyError -from bsb.morphologies import ( +from bsb import ( Branch, + BsbParser, + CastError, + Configuration, + EmptyBranchError, Morphology, - MorphologySet, - RotationSet, - parse_morphology_file, -) -from bsb.morphologies.parsers.parser import BsbParser -from bsb.storage._files import ( MorphologyDependencyNode, + MorphologyError, MorphologyOperation, + MorphologySet, NeuroMorphoScheme, + RotationSet, + Scaffold, + StoredMorphology, + parse_morphology_file, ) -from bsb.storage.interfaces import StoredMorphology +from bsb._encoding import EncodedLabels class TestIO(NumpyTestCase, unittest.TestCase): diff --git a/tests/test_options.py b/tests/test_options.py index 1178c680e..99a9db1aa 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -1,21 +1,13 @@ import os import pathlib -import sys import tempfile import unittest import toml -from bsb import options -from bsb._contexts import get_cli_context +from bsb import OptionError, ReadOnlyOptionError, options from bsb.cli import handle_command -from bsb.exceptions import * -from bsb.option import ( - _pyproject_bsb, - _pyproject_content, - _pyproject_path, - _save_pyproject_bsb, -) +from bsb.option import _pyproject_content, _pyproject_path class TestCLIOption(unittest.TestCase): diff --git a/tests/test_placement.py b/tests/test_placement.py index 307eb5b08..e2ddd7879 100644 --- a/tests/test_placement.py +++ b/tests/test_placement.py @@ -10,16 +10,20 @@ skip_parallel, ) -from bsb.cell_types import CellType -from bsb.config import Configuration -from bsb.core import Scaffold -from bsb.exceptions import IndicatorError, PackingWarning -from bsb.placement import PlacementStrategy -from bsb.services import MPI -from bsb.services.pool import WorkflowError -from bsb.storage import Chunk -from bsb.topology import Partition -from bsb.voxels import VoxelData, VoxelSet +from bsb import ( + MPI, + CellType, + Chunk, + Configuration, + IndicatorError, + PackingWarning, + Partition, + PlacementStrategy, + Scaffold, + VoxelData, + VoxelSet, + WorkflowError, +) def dud_tester(scaffold, x, y): diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 840431646..75f2fa478 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -2,7 +2,7 @@ from bsb_test import spoof_plugin -from bsb.placement import PlacementStrategy +from bsb import PlacementStrategy class A(PlacementStrategy): diff --git a/tests/test_selectors.py b/tests/test_selectors.py index c4d3e19cd..24eac7beb 100644 --- a/tests/test_selectors.py +++ b/tests/test_selectors.py @@ -2,14 +2,18 @@ from bsb_test import RandomStorageFixture, skip_nointernet, skip_parallel -from bsb.cell_types import CellType -from bsb.config import Configuration -from bsb.core import Scaffold -from bsb.exceptions import MissingMorphologyError, SelectorError -from bsb.morphologies import Branch, Morphology -from bsb.morphologies.selector import NameSelector -from bsb.services import MPI -from bsb.storage.interfaces import StoredMorphology +from bsb import ( + MPI, + Branch, + CellType, + Configuration, + MissingMorphologyError, + Morphology, + NameSelector, + Scaffold, + SelectorError, + StoredMorphology, +) def spoof(*names): diff --git a/tests/test_simulation.py b/tests/test_simulation.py index c9bf804cf..d55bb5e9a 100644 --- a/tests/test_simulation.py +++ b/tests/test_simulation.py @@ -2,7 +2,7 @@ from bsb_test import FixedPosConfigFixture, NumpyTestCase, RandomStorageFixture -from bsb.core import Scaffold +from bsb import Scaffold class TestSimulate( diff --git a/tests/test_storage.py b/tests/test_storage.py index 97edbe34c..a143b8b2c 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -1,7 +1,7 @@ import pathlib import unittest -from bsb.storage import FileDependency +from bsb import FileDependency class TestUtil(unittest.TestCase): diff --git a/tests/test_topology.py b/tests/test_topology.py index c98602e68..c02702783 100644 --- a/tests/test_topology.py +++ b/tests/test_topology.py @@ -3,9 +3,7 @@ import numpy as np from bsb_test import get_data_path -from bsb import topology -from bsb.config import Configuration -from bsb.exceptions import * +from bsb import Configuration, LayoutError, topology def single_layer(): diff --git a/tests/test_trees.py b/tests/test_trees.py index a3e742e53..52c54ad01 100644 --- a/tests/test_trees.py +++ b/tests/test_trees.py @@ -1,11 +1,9 @@ import inspect -import os -import sys import unittest import bsb_test -from bsb.voxels import VoxelSet +from bsb import VoxelSet class TestVoxelSet(bsb_test.NumpyTestCase, unittest.TestCase): diff --git a/tests/test_util.py b/tests/test_util.py index 52869a440..7dae64301 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -9,10 +9,8 @@ ) from scipy.spatial.transform import Rotation +from bsb import FileDependency, NeuroMorphoScheme, Scaffold from bsb._util import rotation_matrix_from_vectors -from bsb.core import Scaffold -from bsb.storage import FileDependency -from bsb.storage._files import NeuroMorphoScheme class TestNetworkUtil( diff --git a/tests/test_voxels.py b/tests/test_voxels.py index 5f6a36006..5015fec14 100644 --- a/tests/test_voxels.py +++ b/tests/test_voxels.py @@ -6,10 +6,7 @@ import bsb_test import numpy as np -from bsb.exceptions import EmptyVoxelSetError -from bsb.morphologies import Branch, Morphology -from bsb.storage import Chunk -from bsb.voxels import VoxelData, VoxelSet +from bsb import Branch, Chunk, EmptyVoxelSetError, Morphology, VoxelData, VoxelSet class TestVoxelSet(bsb_test.NumpyTestCase, unittest.TestCase):