From 29a12be3e6bd6ffc6a894d0be63e80b1889ecf0f Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Tue, 8 Sep 2020 17:29:06 -0400 Subject: [PATCH 1/2] basic working docs --- .gitignore | 1 + docs/Makefile | 20 ++ docs/make.bat | 35 +++ docs/requirements.txt | 4 + docs/source/_static/css/rtd.css | 199 ++++++++++++++++++ .../_templates/custom-class-template.rst | 9 + .../_templates/custom-module-template.rst | 66 ++++++ docs/source/api.rst | 11 + docs/source/conf.py | 82 ++++++++ docs/source/index.rst | 17 ++ docs/source/ome_types.model.rst | 108 ++++++++++ docs/source/ome_types.rst | 25 +++ docs/source/usage.rst | 107 ++++++++++ src/ome_autogen.py | 4 +- 14 files changed, 687 insertions(+), 1 deletion(-) create mode 100644 docs/Makefile create mode 100644 docs/make.bat create mode 100644 docs/requirements.txt create mode 100644 docs/source/_static/css/rtd.css create mode 100644 docs/source/_templates/custom-class-template.rst create mode 100644 docs/source/_templates/custom-module-template.rst create mode 100644 docs/source/api.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/index.rst create mode 100644 docs/source/ome_types.model.rst create mode 100644 docs/source/ome_types.rst create mode 100644 docs/source/usage.rst diff --git a/.gitignore b/.gitignore index 8526877c..31df233f 100644 --- a/.gitignore +++ b/.gitignore @@ -109,3 +109,4 @@ venv.bak/ _test_data src/ome_types/model/ src/ome_types/_version.py +docs/source/_autosummary \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..6247f7e2 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..04d38176 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,4 @@ +sphinx==3.1.1 +sphinx-rtd-theme==0.5.0 +sphinx-autodoc-typehints +ipython==7.15.0 \ No newline at end of file diff --git a/docs/source/_static/css/rtd.css b/docs/source/_static/css/rtd.css new file mode 100644 index 00000000..89494bb1 --- /dev/null +++ b/docs/source/_static/css/rtd.css @@ -0,0 +1,199 @@ +@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400;500;600&family=Roboto:wght@100;300;400;700&display=swap"); + +body { + font-family: "Roboto", "Lato", "proxima-nova", "Helvetica Neue", Arial, + sans-serif !important; + font-weight: 300; + color: #404040; +} + +a { + color: #0088e2; +} + +a:visited { + color: #4290c3; +} + +.rst-content a { + font-weight: 400 +} + +a.icon-home { + color: white; +} + + + +.wy-menu-vertical a { + color: #d9d9d9; +} + +.wy-menu-vertical header, +.wy-menu-vertical p.caption { + color: #00a9a9; +} + +.wy-nav-content-wrap { + background: white; +} + +pre, +code samp { + font-family: "IBM Plex Mono", "InconsolataRegular", "Inconsolata", + "RobotoMonoRegular", "Roboto Mono", monospace !important; + font-size: 1em; +} + +code, +.rst-content tt, +.rst-content code { + border-radius: 3px; +} + +h1, +h2, +.rst-content .toctree-wrapper p.caption, +h3, +h4, +h5, +h6, +legend { + margin-top: 0; + font-weight: 400; + font-family: "Roboto", "Georgia", Arial, sans-serif; +} + +.rst-content pre.literal-block, +.rst-content div[class^="highlight"] { + border-radius: 3px; +} + +.rst-content dl:not(.docutils) dt { + background-color: lightcyan; + border-color: #c8b4da; +} + +.rst-content dl:not(.docutils) dt:first-child { + margin-top: 0; + padding-left: 4rem; + padding-right: 100px; +} + +.rst-content dl.field-list.simple dt:first-child { + padding-left: 0.5rem; +} + + +.rst-content dl:not(.docutils) .property { + display: inline-block; + padding-right: 8px; + /* position: absolute; */ + left: 0.5rem; + text-transform: uppercase; + font-style: normal; + color: darkcyan; +} + +.rst-content dl.py.data .property { + display: inline-block; + padding-right: 8px; + position: inherit; + text-transform: none; +} + +.class .method dt { + padding-left: 0.5rem; +} + +.rst-content dl.method dt:first-child { + margin-top: 0; + padding-left: 0.5rem; +} + +.rst-content dl.method em.property { + display: inline-block; + position: inherit; + margin-right: 0.5rem; + left: 0.5rem; + font-style: normal; + text-transform: uppercase; + color: darkcyan; +} + +/* .function dt a, +.attribute dt a, +.class .attribute dt a, +.class dt a { + position: absolute; + right: 15px; + padding-right: 0; + top: 50%; + -webkit-transform: perspective(1px) translateY(-50%); + transform: perspective(1px) translateY(-50%); +} */ + +.function .viewcode-link, +.attribute .viewcode-link, +.class .viewcode-link { + font-size: 0.8rem; + color: #979797; + letter-spacing: 0; + line-height: 1.5rem; + font-weight: 300; + text-transform: uppercase; + padding-right: 15px; +} + +.wy-nav-content { + background: white; +} + +.wy-side-nav-search input[type="text"] { + border-radius: 5px; +} + +span.sig-paren { + font-weight: 400; +} + +em.sig-param { + font-size: 0.85rem; + font-style: italic; + font-weight: 400; +} + +.wy-side-nav-search, +.wy-nav-top { + background-color: darkcyan; +} + +.wy-table-responsive td code { + font-size: 0.75rem; +} + +dl.py.attribute em.property { + display: none; +} + +.rst-content dl.py.attribute dt:first-child { + padding-left: 0.5rem; +} + +/* .rst-content dl.py.attribute dt:first-child code.descname::before { + content: "ATTR"; + padding-right: 5px; + color: darkcyan; +} */ + +.rst-content dl:not(.docutils) dt:first-child { + margin-top: 0; + padding-left: 4rem; + padding-right: 50px; +} + +.rst-content .section ul, .rst-content .toctree-wrapper ul, .wy-plain-list-disc, article ul { + list-style: disc; + line-height: 30px; + margin-bottom: 24px; +} \ No newline at end of file diff --git a/docs/source/_templates/custom-class-template.rst b/docs/source/_templates/custom-class-template.rst new file mode 100644 index 00000000..277299a9 --- /dev/null +++ b/docs/source/_templates/custom-class-template.rst @@ -0,0 +1,9 @@ +{{ name | escape | underline}} + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ name }} + :members: + :show-inheritance: + :inherited-members: + :exclude-members: validate_id diff --git a/docs/source/_templates/custom-module-template.rst b/docs/source/_templates/custom-module-template.rst new file mode 100644 index 00000000..d066d0e4 --- /dev/null +++ b/docs/source/_templates/custom-module-template.rst @@ -0,0 +1,66 @@ +{{ fullname | escape | underline}} + +.. automodule:: {{ fullname }} + + {% block attributes %} + {% if attributes %} + .. rubric:: Module attributes + + .. autosummary:: + :toctree: + {% for item in attributes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block functions %} + {% if functions %} + .. rubric:: {{ _('Functions') }} + + .. autosummary:: + :toctree: + :nosignatures: + {% for item in functions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block classes %} + {% if classes %} + .. rubric:: {{ _('Classes') }} + + .. autosummary:: + :toctree: + :template: custom-class-template.rst + :nosignatures: + {% for item in classes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block exceptions %} + {% if exceptions %} + .. rubric:: {{ _('Exceptions') }} + + .. autosummary:: + :toctree: + {% for item in exceptions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + +{% block modules %} +{% if modules %} +.. autosummary:: + :toctree: + :template: custom-module-template.rst + :recursive: +{% for item in modules %} + {{ item }} +{%- endfor %} +{% endif %} +{% endblock %} diff --git a/docs/source/api.rst b/docs/source/api.rst new file mode 100644 index 00000000..dd99fe6b --- /dev/null +++ b/docs/source/api.rst @@ -0,0 +1,11 @@ +API Reference +============= + + +.. toctree:: + :maxdepth: 2 + :caption: Contents + :hidden: + + ome_types + ome_types.model diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..3391396a --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,82 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys + +sys.path.insert(0, os.path.abspath("../../src")) +from ome_types import __version__ # noqa: E402 + + +# -- Project information ----------------------------------------------------- + +project = "ome-types" +copyright = "2020, Talley Lambert, Jeremy Muhlich" +author = "Talley Lambert, Jeremy Muhlich" + +# The full version, including alpha/beta/rc tags +release = __version__ +version = __version__ + + +# -- General configuration --------------------------------------------------- + +# 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.todo', + 'sphinx.ext.viewcode', + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', + 'sphinx_autodoc_typehints', + 'sphinx.ext.autosummary', + 'sphinx.ext.intersphinx', + 'IPython.sphinxext.ipython_directive', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] +pygments_style = 'paraiso-dark' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + + +# -- 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 = "sphinx_rtd_theme" + +# 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"] +html_css_files = ['css/rtd.css'] + +add_module_names = False + +# intersphinx allows us to link directly to other repos sphinxdocs. +# https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html +intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} + + +autosummary_generate = True # Turn on sphinx.ext.autosummary +# autoclass_content = "both" # Add __init__ doc (ie. params) to class summaries +# html_show_sourcelink = False # Remove 'view source code' from top of page (for html, not python) +# autodoc_inherit_docstrings = True # If no class summary, inherit base class summary +autosummary_generate_overwrite = True +autosummary_imported_members = True diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..15860248 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,17 @@ +ome-types documentation +======================= + +``ome-types`` is a set of autogenerated dataclasses for a pythonic interface +into the `OME data model `_. + +It converts the `ome.xsd schema +`_ into a set of +python dataclasses and types. + + +.. toctree:: + :maxdepth: 3 + :caption: Contents + + usage + api diff --git a/docs/source/ome_types.model.rst b/docs/source/ome_types.model.rst new file mode 100644 index 00000000..35b106e5 --- /dev/null +++ b/docs/source/ome_types.model.rst @@ -0,0 +1,108 @@ +ome\_types.model +================ + +.. automodule:: ome_types.model + + .. rubric:: Classes + + .. autosummary:: + :toctree: _autosummary + :template: custom-class-template.rst + :nosignatures: + + AffineTransform + Annotation + AnnotationRef + Arc + BasicAnnotation + BinData + BinaryFile + BooleanAnnotation + Channel + ChannelRef + CommentAnnotation + Dataset + DatasetRef + Detector + DetectorSettings + Dichroic + DichroicRef + DoubleAnnotation + Ellipse + Experiment + ExperimentRef + Experimenter + ExperimenterGroup + ExperimenterGroupRef + ExperimenterRef + External + Filament + FileAnnotation + Filter + FilterRef + FilterSet + FilterSetRef + Folder + FolderRef + GenericExcitationSource + Image + ImageRef + ImagingEnvironment + Instrument + InstrumentRef + Label + Laser + Leader + LightEmittingDiode + LightPath + LightSource + LightSourceGroup + LightSourceSettings + Line + ListAnnotation + LongAnnotation + ManufacturerSpec + Map + MapAnnotation + Mask + MicrobeamManipulation + MicrobeamManipulationRef + Microscope + NumericAnnotation + OME + Objective + ObjectiveSettings + Pixels + Plane + Plate + PlateAcquisition + Point + Polygon + Polyline + Project + ProjectRef + Pump + ROI + ROIRef + Reagent + ReagentRef + Rectangle + Reference + Rights + Screen + Settings + Shape + ShapeGroup + StageLabel + StructuredAnnotations + TagAnnotation + TermAnnotation + TextAnnotation + TiffData + TimestampAnnotation + TransmittanceRange + TypeAnnotation + Well + WellSample + WellSampleRef + XMLAnnotation diff --git a/docs/source/ome_types.rst b/docs/source/ome_types.rst new file mode 100644 index 00000000..0098db94 --- /dev/null +++ b/docs/source/ome_types.rst @@ -0,0 +1,25 @@ +ome\_types +========== + +ome\_types.util +--------------- + +.. automodule:: ome_types.util + :members: + +ome\_types.schema +----------------- + +.. automodule:: ome_types.schema + :members: + +ome\_types.dataclasses +---------------------- + +.. automodule:: ome_types.dataclasses + :members: + +ome\_types +---------- + +.. autofunction:: ome_types.from_xml diff --git a/docs/source/usage.rst b/docs/source/usage.rst new file mode 100644 index 00000000..8b99a45c --- /dev/null +++ b/docs/source/usage.rst @@ -0,0 +1,107 @@ +Usage +===== + +``ome_types`` is useful for parsing the `OME XML format +`_ into python +classes for interactive or programmatic access in python. + +For example, you can parse an ome.xml, and then explore it with pythonic, +``camel_case`` syntax and nice object representations: + + +.. code-block:: python + + In [1]: from ome_types import from_xml + + In [2]: ome = from_xml('path/to/metadata.ome.xml') + + In [3]: ome + Out[3]: + OME( + images=[<1 Images>], + plates=[<1 Plates>], + ) + + In [4]: ome.plates[0] + Out[4]: + Plate( + id='Plate:1', + name='Control Plate', + column_naming_convention='letter', + columns=12, + row_naming_convention='number', + rows=8, + wells=[<1 Wells>], + ) + + In [5]: ome.plates[0].wells[0] + Out[5]: + Well( + id='Well:1', + column=0, + row=0, + well_samples=[<1 Well_Samples>], + ) + + In [6]: ome.images[0] + Out[6]: + Image( + id='Image:0', + name='Series 1', + pixels=Pixels( + id='Pixels:0', + dimension_order='XYCZT', + size_c=3, + size_t=16, + size_x=1024, + size_y=1024, + size_z=1, + type='uint16', + bin_data=[<1 Bin_Data>], + channels=[<3 Channels>], + physical_size_x=0.207, + physical_size_y=0.207, + time_increment=120.1302, + ), + acquisition_date=datetime.fromisoformat('2008-02-06T13:43:19'), + description='An example OME compliant file, based on Olympus.oib', + ) + + In [7]: ome.images[0].pixels.channels[0] + Out[7]: + Channel( + id='Channel:0:0', + name='CH1', + acquisition_mode='LaserScanningConfocalMicroscopy', + emission_wavelength=523.0, + excitation_wavelength=488.0, + illumination_type='Epifluorescence', + pinhole_size=103.5, + samples_per_pixel=1, + ) + + In [8]: ome.images[0].pixels.channels[0].emission_wavelength + Out[8]: 523.0 + + +You can also construct OME model objects (output to XML coming) + +.. code-block:: python + + In [1]: from ome_types.model import Channel + + In [4]: channel = Channel( + ...: excitation_wavelength=475, + ...: excitation_wavelength_unit="nm", + ...: emission_wavelength=530000, + ...: emission_wavelength_unit="pm", + ...: ) + + In [5]: channel + Out[5]: + Channel( + id='Channel:3', + emission_wavelength=530000.0, + emission_wavelength_unit='pm', + excitation_wavelength=475.0, + ) diff --git a/src/ome_autogen.py b/src/ome_autogen.py index cccc2428..6700ab96 100644 --- a/src/ome_autogen.py +++ b/src/ome_autogen.py @@ -393,7 +393,9 @@ def make_dataclass(component: Union[XsdComponent, XsdType]) -> List[str]: lines += ["@ome_dataclass", f"class {component.local_name}{base_name}:"] doc = get_docstring(component, summary=True) - doc = MemberSet(iter_members(component)).docstring(doc) + doc = MemberSet(iter_members(component)).docstring( + doc or f"{component.local_name}." + ) doc = f'"""{doc.strip()}\n"""\n' lines += indent(doc, " ").splitlines() if class_override and class_override.fields: From e4a38d13595068d5ec4344c7be0229b9a5ec4801 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Tue, 8 Sep 2020 17:30:20 -0400 Subject: [PATCH 2/2] update reqs --- docs/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index 04d38176..f2684e28 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,5 @@ sphinx==3.1.1 +pygments sphinx-rtd-theme==0.5.0 sphinx-autodoc-typehints ipython==7.15.0 \ No newline at end of file