diff --git a/.gitexternals b/.gitexternals index 16fad18..c372733 100644 --- a/.gitexternals +++ b/.gitexternals @@ -1,2 +1,3 @@ # -*- mode: cmake -*- # CMake/common https://github.com/Eyescale/CMake.git 11ee9c1 +# Pydoxine https://github.com/BlueBrain/Pydoxine 69eec7a diff --git a/CMakeLists.txt b/CMakeLists.txt index 173c70d..08c4ea1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ project(Brion VERSION 1.9.0) set(Brion_VERSION_ABI 7) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake - ${CMAKE_SOURCE_DIR}/CMake/common) + ${CMAKE_SOURCE_DIR}/CMake/common ${CMAKE_SOURCE_DIR}/Pydoxine/CMake) include(GitExternal) @@ -36,6 +36,7 @@ common_find_package(OpenMP) common_find_package(PythonInterp) common_find_package(PythonLibs) common_find_package(Servus REQUIRED) +common_find_package(Sphinx 1.3) common_find_package(vmmlib REQUIRED) common_find_package_post() @@ -55,3 +56,5 @@ set(DOXYGEN_EXPAND_AS_DEFINED "BRAIN_API BRION_API") set(DOXYGEN_EXTRA_INPUT "${PROJECT_SOURCE_DIR}/README.md ${CMAKE_INSTALL_PREFIX}/include/brain") set(DOXYGEN_PREDEFINED_MACROS "BRAIN_API:=") include(DoxygenRule) + +add_subdirectory(doc/python) diff --git a/README.md b/README.md index 38bcff1..8b61bcf 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ Brion can be retrieved by cloning the The [latest API documentation] (http://bluebrain.github.io/Brion-1.9/index.html) can be found on [bluebrain.github.io](http://bluebrain.github.io). +Additional documentation exists for the [Python wrapping of Brain] +(python/index.html). To keep track of the changes between releases check the [changelog](@ref Changelog). diff --git a/brain/circuit.h b/brain/circuit.h index ca950be..4430b90 100644 --- a/brain/circuit.h +++ b/brain/circuit.h @@ -48,6 +48,7 @@ class Circuit /** * Opens a circuit for read access. + * * @param source the URI to the CircuitConfig or BlueConfig file. */ BRAIN_API explicit Circuit( const URI& source ); @@ -66,7 +67,7 @@ class Circuit */ BRAIN_API GIDSet getGIDs( const std::string& target ) const; - /** @return All GIDs held by the circuit */ + /** @return The set of all GIDs held by the circuit */ BRAIN_API GIDSet getGIDs() const; /** @@ -118,10 +119,14 @@ class Circuit */ BRAIN_API Strings getElectrophysiologyNames() const; - /** @return The local to world transformations of the given cells. */ + /** @return \if pybind A Nx4 numpy array with the \else The \endif + * local to world transformations of the given cells. + */ BRAIN_API Matrix4fs getTransforms( const GIDSet& gids ) const; - /** @return The local to world rotation of the given cells. */ + /** @return \if pybind A Nx4 numpy array with the \else The \endif + * local to world rotation of the given cells. + */ BRAIN_API Quaternionfs getRotations( const GIDSet& gids ) const; /** @return The number of neurons in the circuit. */ @@ -131,8 +136,12 @@ class Circuit * Access all afferent synapses of the given GIDs. * * @param gids the gids to load afferent synapses for + * \if pybind + * @param prefetch which synapse data to preload + * \else * @param prefetch which synapse data to load on SynapsesStream.read() * @return synapse data stream + * \endif */ BRAIN_API SynapsesStream getAfferentSynapses( const GIDSet& gids, @@ -142,8 +151,12 @@ class Circuit * Access all efferent synapses of the given GIDs. * * @param gids the gids to load efferent synapses for + * \if pybind + * @param prefetch which synapse data to preload + * \else * @param prefetch which synapse data to load on SynapsesStream.read() * @return synapse data stream + * \endif */ BRAIN_API SynapsesStream getEfferentSynapses( const GIDSet& gids, @@ -154,8 +167,12 @@ class Circuit * * @param preGIDs the gids to load the efferent synapses for * @param postGIDs the gids to load the afferent synapses for + * \if pybind + * @param prefetch which synapse data to preload + * \else * @param prefetch which synapse data to load on SynapsesStream.read() * @return synapse data stream + * \endif */ BRAIN_API SynapsesStream getProjectedSynapses( const GIDSet& preGIDs, const GIDSet& postGIDs, diff --git a/brain/neuron/morphology.h b/brain/neuron/morphology.h index 137be68..5d1dcb7 100644 --- a/brain/neuron/morphology.h +++ b/brain/neuron/morphology.h @@ -55,6 +55,7 @@ class Morphology : public boost::noncopyable /** * Create a morphology from a URI, load all the data and transform * the points. + * * @param source URI of the morphology data source. * @param transform the transformation matrix to apply to the points. * Radii will not be affected by this transformation. @@ -65,6 +66,7 @@ class Morphology : public boost::noncopyable /** * Create a morphology from a brion::Morphology, load all the data * and transform the points. + * * @param morphology the brion::Morphology to load from. * @param transform the transformation matrix to apply to the points. * Radii will not be affected by this transformation. @@ -75,6 +77,7 @@ class Morphology : public boost::noncopyable /** * Create a morphology from a URI and load all the data. + * * @param source URI of the morphology data source. * @throw runtime_error if an inconsistency is detected in the input file. */ @@ -82,6 +85,7 @@ class Morphology : public boost::noncopyable /** * Create a morphology from a brion::Morphology and load all the data. + * * @param morphology the brion::Morphology to load from. * @throw runtime_error if an inconsistency is detected in the input file. */ @@ -120,6 +124,7 @@ class Morphology : public boost::noncopyable /** * Return the Section with the given id. + * * @throw runtime_error if the id is out of range or the given id refers to * a soma section. */ @@ -128,8 +133,10 @@ class Morphology : public boost::noncopyable /** Return the object with the information about the neuron soma */ BRAIN_API Soma getSoma() const; - /** Return the transformation that was passed to the constructor or the - identity matrix is no transformation was given. */ + /** Return \if pybind a 4x4 numpry arry with \endif + * the transformation that was passed to the constructor or the + * identity matrix is no transformation was given. + */ BRAIN_API const Matrix4f& getTransformation() const; private: diff --git a/brain/neuron/section.h b/brain/neuron/section.h index 53e1b53..b49fca0 100644 --- a/brain/neuron/section.h +++ b/brain/neuron/section.h @@ -122,8 +122,11 @@ class Section BRAIN_API bool hasParent() const; /** - * Return the parent section of this section. + * Return the parent section of this section \if pybind or None if doesn't + * have any.\else. + * * @throw runtime_error is the section doesn't have a parent. + * \endif */ BRAIN_API Section getParent() const; diff --git a/brain/neuron/soma.h b/brain/neuron/soma.h index 1c4e67f..1c8f79b 100644 --- a/brain/neuron/soma.h +++ b/brain/neuron/soma.h @@ -63,7 +63,9 @@ class Soma BRAIN_API Soma& operator=( const Soma& soma ); - /** Return the points of the soma profile. */ + /** Return the x,y,z and radius of the points of the soma + * profile \if pybind as a 4xN numpy array\endif. + */ BRAIN_API Vector4fs getProfilePoints() const; /** Return the mean distance between the profile points and the centroid. */ diff --git a/brain/python/CMakeLists.txt b/brain/python/CMakeLists.txt index 479d9f5..1a7010a 100644 --- a/brain/python/CMakeLists.txt +++ b/brain/python/CMakeLists.txt @@ -13,25 +13,48 @@ if(NOT Boost_PYTHON${USE_BOOST_PYTHON_VERSION}_LIBRARY OR return() endif() -set(BRAIN_PYTHON_SOURCE_FILES - arrayHelpers.cpp +include(PythonDocstrings) + +set(BRAIN_PYTHON_SOURCES brain.cpp circuit.cpp + synapses.cpp + neuron/morphology.cpp +) + +set(__docstrings_sources) +set(__docstrings_headers) +# Input files to docstrings need absolute paths. +foreach(__header ${BRAIN_PUBLIC_HEADERS}) + list(APPEND __docstrings_headers ${PROJECT_SOURCE_DIR}/brain/${__header}) +endforeach() +foreach(__source ${BRAIN_PYTHON_SOURCES}) + list(APPEND __docstrings_sources ${CMAKE_CURRENT_SOURCE_DIR}/${__source}) +endforeach() + +set(DOCSTRINGS_INCLUDE_PATH ${PROJECT_BINARY_DIR}/include) +docstrings(__docstrings_sources __docstrings_headers) + +list(APPEND BRAIN_PYTHON_SOURCES + arrayHelpers.cpp spikeReportWriter.cpp spikeReportReader.cpp spikes.cpp - synapses.cpp submodules.cpp test.cpp neuron/module.cpp - neuron/morphology.cpp + ${PROJECT_BINARY_DIR}/docstrings/cpp/docstrings.cpp ) -include_directories(${PYTHON_INCLUDE_DIRS} + +include_directories(${PROJECT_BINARY_DIR}/docstrings/cpp + ${PYTHON_INCLUDE_DIRS} ${PYTHON_NUMPY_INCLUDE_DIR}) -add_library(brain_python MODULE ${BRAIN_PYTHON_SOURCE_FILES}) +add_library(brain_python MODULE ${BRAIN_PYTHON_SOURCES}) common_compile_options(brain_python) -add_dependencies(brain_python Brain) +if(TARGET ${PROJECT_NAME}-docstrings) + add_dependencies(brain_python Brain ${PROJECT_NAME}-docstrings) +endif() target_link_libraries(brain_python PRIVATE Brain ${PYTHON_LIBRARIES} diff --git a/brain/python/brain.cpp b/brain/python/brain.cpp index 22363f6..7a2e4ed 100644 --- a/brain/python/brain.cpp +++ b/brain/python/brain.cpp @@ -25,6 +25,8 @@ #include "arrayHelpers.h" +#include "docstrings.h" + #include namespace brain @@ -65,12 +67,19 @@ struct URItoString BOOST_PYTHON_MODULE(_brain) { +#if defined BRION_USE_SPHINX && defined BRION_USE_DOGYXGEN + /* Only change the default Boost.Python options for documentation if we + are going to get docstrings from doxygen. */ + boost::python::docstring_options doc_options(true, true, false); +#endif + boost::python::to_python_converter< servus::URI, URItoString >(); boost::python::to_python_converter< brain::Vector3f, Vector3fToTuple >(); brain::importArray(); - boost::python::enum_< brain::SynapsePrefetch >( "SynapsePrefetch" ) + boost::python::enum_< brain::SynapsePrefetch >( + "SynapsePrefetch", DOXY_ENUM( brain::SynapsePrefetch )) .value( "none", brain::SynapsePrefetch::none ) .value( "attributes", brain::SynapsePrefetch::attributes ) .value( "positions", brain::SynapsePrefetch::positions ) diff --git a/brain/python/circuit.cpp b/brain/python/circuit.cpp index a57c60c..828e603 100644 --- a/brain/python/circuit.cpp +++ b/brain/python/circuit.cpp @@ -23,6 +23,7 @@ #include "arrayHelpers.h" #include "helpers.h" #include "types.h" +#include "docstrings.h" #include #include @@ -143,7 +144,7 @@ void export_Circuit() { bp::class_< Circuit, boost::noncopyable, CircuitPtr > - circuitWrapper( "Circuit", bp::no_init ); + circuitWrapper( "Circuit", DOXY_CLASS( brain::Circuit ), bp::no_init ); bp::scope circuitScope = circuitWrapper; @@ -152,29 +153,62 @@ bp::enum_< Circuit::Coordinates >( "Coordinates" ) .value( "local", Circuit::Coordinates::local ) ; +const auto selfarg = bp::arg( "self" ); + +// Do not modify whitespace on DOXY_FN lines + circuitWrapper - .def( "__init__", bp::make_constructor( Circuit_initFromURI )) - .def( "gids", Circuit_getAllGIDs ) - .def( "gids", Circuit_getGIDs ) - .def( "random_gids", Circuit_getRandomTargetGIDs ) - .def( "random_gids", Circuit_getRandomGIDs ) - .def( "morphology_uris", Circuit_getMorphologyURIs ) - .def( "load_morphologies", Circuit_loadMorphologies ) - .def( "positions", Circuit_getPositions ) - .def( "morphology_types", Circuit_getMorphologyTypes ) - .def( "morphology_names", Circuit_getMorphologyNames ) - .def( "electrophysiology_types", Circuit_getElectrophysiologyTypes ) - .def( "electrophysiology_names", Circuit_getElectrophysiologyNames ) - .def( "transforms", Circuit_getTransforms ) - .def( "rotations", Circuit_getRotations ) - .def( "num_neurons", &Circuit::getNumNeurons ) + .def( "__init__", bp::make_constructor( Circuit_initFromURI ), + DOXY_FN( brain::Circuit::Circuit(const URI&))) + .def( "gids", Circuit_getAllGIDs, ( selfarg ), + DOXY_FN( brain::Circuit::getGIDs() const)) + .def( "gids", Circuit_getGIDs, ( selfarg, bp::arg( "target" )), + DOXY_FN( brain::Circuit::getGIDs(const std::string&) const)) + .def( "random_gids", Circuit_getRandomTargetGIDs, + ( selfarg, bp::arg( "fraction" ), bp::arg( "target" )), + DOXY_FN( brain::Circuit::getRandomGIDs(float, const std::string&) const)) + .def( "random_gids", Circuit_getRandomGIDs, + ( selfarg, bp::arg( "fraction" )), + DOXY_FN( brain::Circuit::getRandomGIDs(float) const)) + .def( "morphology_uris", Circuit_getMorphologyURIs, + ( selfarg, bp::arg( "gids" )), + DOXY_FN( brain::Circuit::getMorphologyURIs )) + .def( "load_morphologies", Circuit_loadMorphologies, + ( selfarg, bp::arg( "gids" ), bp::arg( "coords" )), + DOXY_FN( brain::Circuit::loadMorphologies )) + .def( "positions", Circuit_getPositions, ( selfarg, bp::arg( "gids" )), + DOXY_FN( brain::Circuit::getPositions )) + .def( "morphology_types", Circuit_getMorphologyTypes, + ( selfarg, bp::arg( "gids" )), + DOXY_FN( brain::Circuit::getMorphologyTypes )) + .def( "morphology_names", Circuit_getMorphologyNames, ( selfarg ), + DOXY_FN( brain::Circuit::getMorphologyNames )) + .def( "electrophysiology_types", Circuit_getElectrophysiologyTypes, + ( selfarg, bp::arg( "gids" )), + DOXY_FN( brain::Circuit::getElectrophysiologyTypes )) + .def( "electrophysiology_names", Circuit_getElectrophysiologyNames, + ( selfarg), + DOXY_FN( brain::Circuit::getElectrophysiologyNames )) + .def( "transforms", Circuit_getTransforms, + ( selfarg, bp::arg( "gids" )), + DOXY_FN( brain::Circuit::getTransforms )) + .def( "rotations", Circuit_getRotations, + ( selfarg, bp::arg( "gids" )), + DOXY_FN( brain::Circuit::getRotations )) + .def( "num_neurons", &Circuit::getNumNeurons, ( selfarg ), + DOXY_FN( brain::Circuit::getNumNeurons )) .def( "afferent_synapses", Circuit_getAfferentSynapses, - ( bp::arg( "gids"), bp::arg( "prefetch" ) = SynapsePrefetch::none )) + ( selfarg, bp::arg( "gids"), + bp::arg( "prefetch" ) = SynapsePrefetch::none ), + DOXY_FN( brain::Circuit::getAfferentSynapses )) .def( "efferent_synapses", Circuit_getEfferentSynapses, - ( bp::arg( "gids"), bp::arg( "prefetch" ) = SynapsePrefetch::none )) + ( selfarg, bp::arg( "gids"), + bp::arg( "prefetch" ) = SynapsePrefetch::none ), + DOXY_FN( brain::Circuit::getEfferentSynapses )) .def( "projected_synapses", Circuit_getProjectedSynapses, - ( bp::arg( "preGids"), bp::arg( "postGIDs" ), - bp::arg( "prefetch" ) = SynapsePrefetch::none )) + ( selfarg, bp::arg( "preGids"), bp::arg( "postGIDs" ), + bp::arg( "prefetch" ) = SynapsePrefetch::none ), + DOXY_FN( brain::Circuit::getProjectedSynapses )) ; } diff --git a/brain/python/neuron/morphology.cpp b/brain/python/neuron/morphology.cpp index 6cf0eca..6fb619a 100644 --- a/brain/python/neuron/morphology.cpp +++ b/brain/python/neuron/morphology.cpp @@ -22,6 +22,7 @@ #include "../arrayHelpers.h" #include "../helpers.h" +#include "docstrings.h" #include #include @@ -180,40 +181,73 @@ bp::object Morphology_getTransformation( const MorphologyPtr& morphology ) void export_Morphology() { +const auto selfarg = bp::arg( "self" ); + +// Do not modify whitespace on DOXY_FN lines + bp::class_< SomaWrapper >( - "Soma", bp::no_init ) - .def( "profile_points", Soma_getProfilePoints ) - .def( "mean_radius", &Soma::getMeanRadius ) - .def( "centroid", &Soma::getCentroid ) + "Soma", DOXY_CLASS( brain::neuron::Soma ), bp::no_init ) + .def( "profile_points", Soma_getProfilePoints, ( selfarg ), + DOXY_FN( brain::neuron::Soma::getProfilePoints )) + .def( "mean_radius", &Soma::getMeanRadius, ( selfarg ), + DOXY_FN( brain::neuron::Soma::getMeanRadius )) + .def( "centroid", &Soma::getCentroid, ( selfarg ), + DOXY_FN( brain::neuron::Soma::getCentroid )) ; bp::class_< SectionWrapper >( - "Section", bp::no_init ) + "Section", DOXY_CLASS( brain::neuron::Section ), bp::no_init ) .def( bp::self == bp::self ) - .def( "id", &Section::getID ) - .def( "type", &Section::getType ) - .def( "length", &Section::getLength ) - .def( "samples", Section_getSamples ) - .def( "samples", Section_getSamplesFromPositions ) - .def( "distance_to_soma", &Section::getDistanceToSoma ) - .def( "sample_distances_to_soma", Section_getSampleDistancesToSoma ) - .def( "parent", Section_getParent ) - .def( "children", Section_getChildren ) + .def( "id", &Section::getID, ( selfarg ), + DOXY_FN( brain::neuron::Section::getID )) + .def( "type", &Section::getType, ( selfarg ), + DOXY_FN( brain::neuron::Section::getType )) + .def( "length", &Section::getLength, ( selfarg ), + DOXY_FN( brain::neuron::Section::getLength )) + .def( "samples", Section_getSamples, ( selfarg ), + DOXY_FN( brain::neuron::Section::getSamples() const)) + .def( "samples", Section_getSamplesFromPositions, + ( selfarg, bp::arg( "positions" )), + DOXY_FN( brain::neuron::Section::getSamples(const floats&) const)) + .def( "distance_to_soma", &Section::getDistanceToSoma, ( selfarg ), + DOXY_FN( brain::neuron::Section::getDistanceToSoma )) + .def( "sample_distances_to_soma", Section_getSampleDistancesToSoma, + ( selfarg ), + DOXY_FN( brain::neuron::Section::getSampleDistancesToSoma )) + .def( "parent", Section_getParent, ( selfarg ), + DOXY_FN( brain::neuron::Section::getParent )) + .def( "children", Section_getChildren, ( selfarg ), + DOXY_FN( brain::neuron::Section::getChildren )) ; bp::class_< Morphology, boost::noncopyable, MorphologyPtr >( - "Morphology", bp::no_init ) - .def( "__init__", bp::make_constructor( Morphology_initFromURI )) - .def( "__init__", bp::make_constructor( Morphology_initFromURIAndTransform )) - .def( "points", Morphology_getPoints ) - .def( "sections", Morphology_getSections ) - .def( "section_types", Morphology_getSectionTypes) - .def( "apicals", Morphology_getApicals ) - .def( "section_ids", Morphology_getSectionIDs ) - .def( "sections", Morphology_getSectionsByType ) - .def( "section", Morphology_getSection ) - .def( "soma", Morphology_getSoma ) - .def( "transformation", Morphology_getTransformation ) + "Morphology", DOXY_CLASS( brain::neuron::Morphology ), bp::no_init ) + .def( "__init__", bp::make_constructor( Morphology_initFromURI ), + DOXY_FN( brain::neuron::Morphology::Morphology(const URI&))) + .def( "__init__", bp::make_constructor( Morphology_initFromURIAndTransform ), + DOXY_FN( brain::neuron::Morphology::Morphology(const URI&, const Matrix4f&))) + // The following docstrings are given explictly because the return types + // are special and the original documentation uses @sa, which points nowhere. + .def( "points", Morphology_getPoints, ( selfarg ), + "Return a 4xN numpy array with the x,y,z and radius of all the points of this morphology.") + .def( "sections", Morphology_getSections, ( selfarg ), + "Return a 2xN numpy array with the parent ID and first point offset of each section." ) + .def( "section_types", Morphology_getSectionTypes, ( selfarg ), + "Return a numpy array with the section types." ) + .def( "apicals", Morphology_getApicals, ( selfarg ), + "Return a 2xN numpy array with the section id and point index of apical points." ) + .def( "section_ids", Morphology_getSectionIDs, + ( selfarg, bp::arg( "types" )), + DOXY_FN( brain::neuron::Morphology::getSectionIDs )) + .def( "sections", Morphology_getSectionsByType, + ( selfarg, bp::arg( "type" )), + DOXY_FN( brain::neuron::Morphology::getSections(const SectionTypes&) const)) + .def( "section", Morphology_getSection, ( selfarg, bp::arg( "id" )), + DOXY_FN( brain::neuron::Morphology::getSections(SectionType) const)) + .def( "soma", Morphology_getSoma, ( selfarg ), + DOXY_FN( brain::neuron::Morphology::getSoma )) + .def( "transformation", Morphology_getTransformation, ( selfarg ), + DOXY_FN( brain::neuron::Morphology::getTransformation )) ; } diff --git a/brain/python/synapses.cpp b/brain/python/synapses.cpp index eb90eff..6bdbb33 100644 --- a/brain/python/synapses.cpp +++ b/brain/python/synapses.cpp @@ -21,9 +21,10 @@ #include "types.h" #include "arrayHelpers.h" +#include "docstrings.h" #include -#include + #include @@ -90,63 +91,115 @@ GET_SYNAPSES_ARRAY_PROPERTY( int, efficacies ) void export_Synapses() { -bp::class_< SynapseWrapper >( "Synapse", bp::no_init ) - .def( "pre_gid", &Synapse::getPresynapticGID ) - .def( "pre_section", &Synapse::getPresynapticSectionID ) - .def( "pre_segment", &Synapse::getPresynapticSegmentID ) - .def( "pre_distance", &Synapse::getPresynapticDistance ) - .def( "pre_center_position", &Synapse::getPresynapticCenterPosition ) - .def( "pre_surface_position", &Synapse::getPresynapticSurfacePosition ) - .def( "post_gid", &Synapse::getPostsynapticGID ) - .def( "post_section", &Synapse::getPostsynapticSectionID ) - .def( "post_segment", &Synapse::getPostsynapticSegmentID ) - .def( "post_distance", &Synapse::getPostsynapticDistance ) - .def( "post_center_position", &Synapse::getPostsynapticCenterPosition ) - .def( "post_surface_position", &Synapse::getPostsynapticSurfacePosition ) - .def( "delay", &Synapse::getDelay ) - .def( "conductance", &Synapse::getConductance ) - .def( "utilization", &Synapse::getUtilization ) - .def( "depression", &Synapse::getDepression ) - .def( "facilitation", &Synapse::getFacilitation ) - .def( "decay", &Synapse::getDecay ) - .def( "efficacy", &Synapse::getEfficacy ) +const auto selfarg = bp::arg( "self" ); + +bp::class_< SynapseWrapper >( "Synapse", + DOXY_CLASS( brain::Synapse ), bp::no_init ) + .def( "pre_gid", &Synapse::getPresynapticGID, ( selfarg ), + DOXY_FN( brain::Synapse::getPresynapticGID )) + .def( "pre_section", &Synapse::getPresynapticSectionID, ( selfarg ), + DOXY_FN( brain::Synapse::getPresynapticSectionID )) + .def( "pre_segment", &Synapse::getPresynapticSegmentID, ( selfarg ), + DOXY_FN( brain::Synapse::getPresynapticSegmentID )) + .def( "pre_distance", &Synapse::getPresynapticDistance, ( selfarg ), + DOXY_FN( brain::Synapse::getPresynapticDistance )) + .def( "pre_center_position", &Synapse::getPresynapticCenterPosition, + ( selfarg ), DOXY_FN( brain::Synapse::getPresynapticCenterPosition )) + .def( "pre_surface_position", &Synapse::getPresynapticSurfacePosition, + ( selfarg ), DOXY_FN( brain::Synapse::getPresynapticSurfacePosition )) + .def( "post_gid", &Synapse::getPostsynapticGID, ( selfarg ), + DOXY_FN( brain::Synapse::getPostsynapticGID )) + .def( "post_section", &Synapse::getPostsynapticSectionID, ( selfarg ), + DOXY_FN( brain::Synapse::getPostsynapticSectionID )) + .def( "post_segment", &Synapse::getPostsynapticSegmentID, ( selfarg ), + DOXY_FN( brain::Synapse::getPostsynapticSegmentID )) + .def( "post_distance", &Synapse::getPostsynapticDistance, ( selfarg ), + DOXY_FN( brain::Synapse::getPostsynapticDistance )) + .def( "post_center_position", &Synapse::getPostsynapticCenterPosition, + ( selfarg ), DOXY_FN( brain::Synapse::getPostsynapticCenterPosition )) + .def( "post_surface_position", &Synapse::getPostsynapticSurfacePosition, + ( selfarg ), DOXY_FN( brain::Synapse::getPostsynapticSurfacePosition )) + .def( "delay", &Synapse::getDelay, ( selfarg ), + DOXY_FN( brain::Synapse::getDelay )) + .def( "conductance", &Synapse::getConductance, ( selfarg ), + DOXY_FN( brain::Synapse::getConductance )) + .def( "utilization", &Synapse::getUtilization, ( selfarg ), + DOXY_FN( brain::Synapse::getUtilization )) + .def( "depression", &Synapse::getDepression, ( selfarg ), + DOXY_FN( brain::Synapse::getDepression )) + .def( "facilitation", &Synapse::getFacilitation, ( selfarg ), + DOXY_FN( brain::Synapse::getFacilitation )) + .def( "decay", &Synapse::getDecay, ( selfarg ), + DOXY_FN( brain::Synapse::getDecay )) + .def( "efficacy", &Synapse::getEfficacy, ( selfarg ), + DOXY_FN( brain::Synapse::getEfficacy )) ; -bp::class_< SynapsesWrapper >( "Synapses", bp::no_init ) +bp::class_< SynapsesWrapper >( "Synapses", DOXY_CLASS( brain::Synapses ), + bp::no_init ) .def( "__nonzero__", nonzero ) .def( "__len__", &Synapses::size ) .def( "__getitem__", Synapses_get ) // There is no need to wrap the iterator, Python provides one out of the // box thanks to __len__ and __getitem__ - .def( "empty", &Synapses::empty ) - .def( "indices", Synapses_indices ) - .def( "pre_gids", Synapses_preGIDs ) - .def( "pre_section_ids", Synapses_preSectionIDs ) - .def( "pre_segment_ids", Synapses_preSegmentIDs ) - .def( "pre_distances", Synapses_preDistances ) - .def( "pre_surface_x_positions", Synapses_preSurfaceXPositions ) - .def( "pre_surface_y_positions", Synapses_preSurfaceYPositions ) - .def( "pre_surface_z_positions", Synapses_preSurfaceZPositions ) - .def( "pre_center_x_positions", Synapses_preCenterXPositions ) - .def( "pre_center_y_positions", Synapses_preCenterYPositions ) - .def( "pre_center_z_positions", Synapses_preCenterZPositions ) - .def( "post_gids", Synapses_postGIDs ) - .def( "post_section_ids", Synapses_postSectionIDs ) - .def( "post_segment_ids", Synapses_postSegmentIDs ) - .def( "post_distances", Synapses_postDistances ) - .def( "post_surface_x_positions", Synapses_postSurfaceXPositions ) - .def( "post_surface_y_positions", Synapses_postSurfaceYPositions ) - .def( "post_surface_z_positions", Synapses_postSurfaceZPositions ) - .def( "post_center_x_positions", Synapses_postCenterXPositions ) - .def( "post_center_y_positions", Synapses_postCenterYPositions ) - .def( "post_center_z_positions", Synapses_postCenterZPositions ) - .def( "delays", Synapses_delays ) - .def( "conductances", Synapses_conductances ) - .def( "utilizations", Synapses_utilizations ) - .def( "depressions", Synapses_depressions ) - .def( "facilitations", Synapses_facilitations ) - .def( "decays", Synapses_decays ) - .def( "efficacies", Synapses_efficacies ) + .def( "empty", &Synapses::empty, ( selfarg ), + DOXY_FN( brain::Synapses::empty )) + .def( "indices", Synapses_indices, ( selfarg ), + DOXY_FN( brain::Synapses::indices )) + .def( "pre_gids", Synapses_preGIDs, ( selfarg ), + DOXY_FN( brain::Synapses::preGIDs )) + .def( "pre_section_ids", Synapses_preSectionIDs, ( selfarg ), + DOXY_FN( brain::Synapses::preSectionIDs )) + .def( "pre_segment_ids", Synapses_preSegmentIDs, ( selfarg ), + DOXY_FN( brain::Synapses::preSegmentIDs )) + .def( "pre_distances", Synapses_preDistances, ( selfarg ), + DOXY_FN( brain::Synapses::preDistances )) + .def( "pre_surface_x_positions", Synapses_preSurfaceXPositions, + ( selfarg ), DOXY_FN( brain::Synapses::preSurfaceXPositions )) + .def( "pre_surface_y_positions", Synapses_preSurfaceYPositions, + ( selfarg ), DOXY_FN( brain::Synapses::preSurfaceYPositions )) + .def( "pre_surface_z_positions", Synapses_preSurfaceZPositions, + ( selfarg ), DOXY_FN( brain::Synapses::preSurfaceZPositions )) + .def( "pre_center_x_positions", Synapses_preCenterXPositions, ( selfarg ), + DOXY_FN( brain::Synapses::preCenterXPositions )) + .def( "pre_center_y_positions", Synapses_preCenterYPositions, ( selfarg ), + DOXY_FN( brain::Synapses::preCenterYPositions )) + .def( "pre_center_z_positions", Synapses_preCenterZPositions, ( selfarg ), + DOXY_FN( brain::Synapses::preCenterZPositions )) + .def( "post_gids", Synapses_postGIDs, ( selfarg ), + DOXY_FN( brain::Synapses::postGIDs )) + .def( "post_section_ids", Synapses_postSectionIDs, ( selfarg ), + DOXY_FN( brain::Synapses::postSectionIDs )) + .def( "post_segment_ids", Synapses_postSegmentIDs, ( selfarg ), + DOXY_FN( brain::Synapses::postSegmentIDs )) + .def( "post_distances", Synapses_postDistances, ( selfarg ), + DOXY_FN( brain::Synapses::postDistances )) + .def( "post_surface_x_positions", Synapses_postSurfaceXPositions, + ( selfarg ), DOXY_FN( brain::Synapses::postSurfaceXPositions )) + .def( "post_surface_y_positions", Synapses_postSurfaceYPositions, + ( selfarg ), DOXY_FN( brain::Synapses::postSurfaceYPositions )) + .def( "post_surface_z_positions", Synapses_postSurfaceZPositions, + ( selfarg ), DOXY_FN( brain::Synapses::postSurfaceZPositions )) + .def( "post_center_x_positions", Synapses_postCenterXPositions, ( selfarg ), + DOXY_FN( brain::Synapses::postCenterXPositions )) + .def( "post_center_y_positions", Synapses_postCenterYPositions, ( selfarg ), + DOXY_FN( brain::Synapses::postCenterYPositions )) + .def( "post_center_z_positions", Synapses_postCenterZPositions, ( selfarg ), + DOXY_FN( brain::Synapses::postCenterZPositions )) + .def( "delays", Synapses_delays, ( selfarg ), + DOXY_FN( brain::Synapses::delays )) + .def( "conductances", Synapses_conductances, ( selfarg ), + DOXY_FN( brain::Synapses::conductances )) + .def( "utilizations", Synapses_utilizations, ( selfarg ), + DOXY_FN( brain::Synapses::utilizations )) + .def( "depressions", Synapses_depressions, ( selfarg ), + DOXY_FN( brain::Synapses::depressions )) + .def( "facilitations", Synapses_facilitations, ( selfarg ), + DOXY_FN( brain::Synapses::facilitations )) + .def( "decays", Synapses_decays, ( selfarg ), + DOXY_FN( brain::Synapses::decays )) + .def( "efficacies", Synapses_efficacies, ( selfarg ), + DOXY_FN( brain::Synapses::efficacies )) ; } diff --git a/brain/synapses.h b/brain/synapses.h index 4b6b4bb..9174a56 100644 --- a/brain/synapses.h +++ b/brain/synapses.h @@ -34,6 +34,9 @@ namespace brain * per-array access on the various synapses attributes. Data which was not * prefetched will be loaded on-demand. * + * This container can be iterated as well as random accessed using the + * operator []. + * * This class is thread-safe, moveable and copyable. */ class Synapses diff --git a/doc/Changelog.md b/doc/Changelog.md index fc87dcd..4980e4a 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -3,6 +3,8 @@ Changelog {#Changelog} # Release 1.9.0 (git master) +* [107](https://github.com/BlueBrain/Brion/pull/107): + Added Sphinx generated documentation of the brain python module. * [102](https://github.com/BlueBrain/Brion/pull/102): Use PersistentMap for caching synapse positions loaded from brain::Circuit * [94](https://github.com/BlueBrain/Brion/pull/94): diff --git a/doc/feature/compartmentReport.md b/doc/feature/compartmentReport.md index 169deda..864157e 100644 --- a/doc/feature/compartmentReport.md +++ b/doc/feature/compartmentReport.md @@ -1,4 +1,4 @@ -Additions to compartmentReport to support ZeroEQ streams +Additions to compartmentReport to support ZeroEQ streams {#compartmentReport} ============ ## Motivation diff --git a/doc/feature/compartmentReportMPI.md b/doc/feature/compartmentReportMPI.md index 3fc9f61..75c503c 100644 --- a/doc/feature/compartmentReportMPI.md +++ b/doc/feature/compartmentReportMPI.md @@ -1,4 +1,4 @@ -Compartment report writing from MPI applications +Compartment report writing from MPI applications {#compartmentReportMPI} ============ This feature is a modification of the CompartmentReport to allow MPI diff --git a/doc/feature/feature.md b/doc/feature/feature.md new file mode 100644 index 0000000..82c9022 --- /dev/null +++ b/doc/feature/feature.md @@ -0,0 +1,8 @@ +Feature specifications {#FeatureSpecs} +====================== + +* @subpage compartmentReport +* @subpage compartmentReportMPI +* @subpage morphology11 +* @subpage spikeReport +* @subpage brainSynapses diff --git a/doc/feature/morphology11.md b/doc/feature/morphology11.md index 1be488e..fbcde61 100644 --- a/doc/feature/morphology11.md +++ b/doc/feature/morphology11.md @@ -1,4 +1,4 @@ -Implementing Morphology version 1.1, support for glia cells +Implementing Morphology version 1.1, support for glia cells {#morphology11} ============ The current morphology version 1 specification and implementation is tailored diff --git a/doc/feature/spikeReport.md b/doc/feature/spikeReport.md index 4d0053a..347429d 100644 --- a/doc/feature/spikeReport.md +++ b/doc/feature/spikeReport.md @@ -1,4 +1,4 @@ -Redesign of the SpikeReport and Spikes container +Redesign of the SpikeReport and Spikes container {#spikeReport} ============ The current design of the SpikeReport has several flaws that need to be diff --git a/doc/feature/synapses.md b/doc/feature/synapses.md index 8bd8bfe..0e85de7 100644 --- a/doc/feature/synapses.md +++ b/doc/feature/synapses.md @@ -1,4 +1,4 @@ -Synapse support in Brain +Synapse support in Brain {#brainSynapses} ============ The low-level data access for synapses provided by Brion needs a complementary diff --git a/doc/python/CMakeLists.txt b/doc/python/CMakeLists.txt new file mode 100644 index 0000000..803aae5 --- /dev/null +++ b/doc/python/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (c) 2016, EPFL/Blue Brain Project +# Juan Hernando Vieites +# +# This file is part of Brion +# + +if(NOT SPHINX_FOUND) + return() +endif() + +configure_file(conf.py.in ${PROJECT_BINARY_DIR}/doc/python/conf.py) + +file(COPY index.rst DESTINATION ${PROJECT_BINARY_DIR}/doc/python) + +add_custom_target(${PROJECT_NAME}-python-doc-html + ${SPHINX_EXECUTABLE} -b html . ${PROJECT_BINARY_DIR}/doc/html/python + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/doc/python + DEPENDS index.rst conf.py.in + COMMENT "Generating Python documentation using Sphinx" VERBATIM) +set_target_properties(${PROJECT_NAME}-python-doc-html PROPERTIES + EXCLUDE_FROM_DEFAULT_BUILD ON FOLDER "doxygen") + +add_dependencies(${PROJECT_NAME}-python-doc-html brain_python) +add_dependencies(${PROJECT_NAME}-doxygen ${PROJECT_NAME}-python-doc-html) diff --git a/doc/python/conf.py.in b/doc/python/conf.py.in new file mode 100644 index 0000000..ef035c1 --- /dev/null +++ b/doc/python/conf.py.in @@ -0,0 +1,189 @@ +# Copyright (c) 2016, EPFL/Blue Brain Project +# Juan Hernando Vieites +# +# This file is part of Brion +# + +import sys, os +import re + +sys.path.append('${CMAKE_BINARY_DIR}/lib') +sys.path.append('${PROJECT_BINARY_DIR}/doc/python') + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc'] + +# Add any paths that contain templates here, relative to this directory. +# templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Brain' +copyright = u'2016, EPFL/Blue Brian Project' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}' +# The full version, including alpha/beta/rc tags. +release = '${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = 'Brain ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} Python API documentation' + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'BrainPythondoc' + +def setup(app): + # Connecting a signature processing event to remove the ugly appearance of + # some default parameters of C++ wrapped functions + # (e.g. (AttributeMap)attributes=<_rtneuron.AttributeMap object at 0x2ac1adb69520> + expr = re.compile("<([\.0-9A-Za-z_]*) object at 0x[0-9a-f]*>") + + def remove_cpp_address(app, what, name, obj, options, + signature, return_annotation): + if not signature: + return (signature, return_annotation) + + def replace(match): + return match.group(1) + "()" + signature = expr.sub(replace, signature) + return (signature, return_annotation) + + def skip_selected(app, what, name, obj, skip, options): + # Do not skip constructors + if name == "__init__": + return False + # Skip the 'values' and 'names' attributes from enums + if name in ['values', 'names'] and \ + what == 'class' and type(obj) is dict: + return True + return skip + + app.connect("autodoc-process-signature", remove_cpp_address) + app.connect("autodoc-skip-member", skip_selected) + diff --git a/doc/python/index.rst b/doc/python/index.rst new file mode 100644 index 0000000..b65bc7c --- /dev/null +++ b/doc/python/index.rst @@ -0,0 +1,19 @@ +.. _python-doc: + +Brain Python API documentation +================================= + +.. toctree:: + :maxdepth: 2 + +brain namespace +~~~~~~~~~~~~~~~ +.. automodule:: brain._brain + :members: + :undoc-members: + +brain.neuron namespace +~~~~~~~~~~~~~~~~~~~~~~ +.. automodule:: brain._brain._neuron + :members: + :undoc-members: