Write more documentation

Sphinx autoapi also now only shows subpackages 1 level deep. This prevents us having a huge long list. Also don't show private or special members. Also show imported members so ifcopenshell.file and ifcopenshell.entity_instance works in docs too.
This commit is contained in:
Dion Moult
2024-05-07 17:32:47 +10:00
parent 722201a1af
commit d76462ca42
11 changed files with 248 additions and 74 deletions
@@ -0,0 +1,16 @@
Python API Reference
====================
This page contains auto-generated API reference documentation [#f1]_.
.. toctree::
:titlesonly:
:maxdepth: 1
{% for page in pages %}
{% if page.top_level_object and page.display %}
{{ page.include_path }}
{% endif %}
{% endfor %}
.. [#f1] Created with `sphinx-autoapi <https://github.com/readthedocs/sphinx-autoapi>`_
@@ -0,0 +1,114 @@
{% if not obj.display %}
:orphan:
{% endif %}
:py:mod:`{{ obj.name }}`
=========={{ "=" * obj.name|length }}
.. py:module:: {{ obj.name }}
{% if obj.docstring %}
.. autoapi-nested-parse::
{{ obj.docstring|indent(3) }}
{% endif %}
{% block subpackages %}
{% set visible_subpackages = obj.subpackages|selectattr("display")|list %}
{% if visible_subpackages %}
Subpackagesa
------------
.. toctree::
:titlesonly:
:maxdepth: 1
{% for subpackage in visible_subpackages %}
{{ subpackage.short_name }}/index.rst
{% endfor %}
{% endif %}
{% endblock %}
{% block submodules %}
{% set visible_submodules = obj.submodules|selectattr("display")|list %}
{% if visible_submodules %}
Submodules
----------
.. toctree::
:titlesonly:
:maxdepth: 1
{% for submodule in visible_submodules %}
{{ submodule.short_name }}/index.rst
{% endfor %}
{% endif %}
{% endblock %}
{% block content %}
{% if obj.all is not none %}
{% set visible_children = obj.children|selectattr("short_name", "in", obj.all)|list %}
{% elif obj.type is equalto("package") %}
{% set visible_children = obj.children|selectattr("display")|list %}
{% else %}
{% set visible_children = obj.children|selectattr("display")|rejectattr("imported")|list %}
{% endif %}
{% if visible_children %}
{{ obj.type|title }} Contents
{{ "-" * obj.type|length }}---------
{% set visible_classes = visible_children|selectattr("type", "equalto", "class")|list %}
{% set visible_functions = visible_children|selectattr("type", "equalto", "function")|list %}
{% set visible_attributes = visible_children|selectattr("type", "equalto", "data")|list %}
{% if "show-module-summary" in autoapi_options and (visible_classes or visible_functions) %}
{% block classes scoped %}
{% if visible_classes %}
Classes
~~~~~~~
.. autoapisummary::
{% for klass in visible_classes %}
{{ klass.id }}
{% endfor %}
{% endif %}
{% endblock %}
{% block functions scoped %}
{% if visible_functions %}
Functions
~~~~~~~~~
.. autoapisummary::
{% for function in visible_functions %}
{{ function.id }}
{% endfor %}
{% endif %}
{% endblock %}
{% block attributes scoped %}
{% if visible_attributes %}
Attributes
~~~~~~~~~~
.. autoapisummary::
{% for attribute in visible_attributes %}
{{ attribute.id }}
{% endfor %}
{% endif %}
{% endblock %}
{% endif %}
{% for obj_item in visible_children %}
{{ obj_item.render()|indent(0) }}
{% endfor %}
{% endif %}
{% endblock %}
+4 -1
View File
@@ -74,6 +74,9 @@ autoapi_dirs = ['../ifcopenshell', '../../bcf/src', '../../bsdd', '../../ifccsv'
# These are auto-generated based on the IFC schema, so exclude them
autoapi_ignore = ['*ifcopenshell/express/rules*']
# Custom autoapi templates to make it easier to read our docs
autoapi_template_dir = "_autoapi_templates"
# autoapi_options doesn't have show-module-summary, as it tends to create one
# page per function which contradicts the presentation of showing all functions
# as a list. This creates two possible locations where a function is documented
@@ -81,7 +84,7 @@ autoapi_ignore = ['*ifcopenshell/express/rules*']
# ifcopenshell.file is imported from ifcopenshell.file.file, but it gets pretty
# confusing to see the docs again in multiple places (seriously,
# ifcopenshell.file.file is everywhere).
autoapi_options = ['members', 'undoc-members', 'private-members', 'special-members', 'show-inheritance']
autoapi_options = ['members', 'undoc-members', 'show-inheritance', 'imported-members']
# This option is set to both to allow both class docstrings and __init__ docstrings.
autoapi_python_class_content = 'both'
@@ -16,18 +16,42 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""The entry module for IfcOpenShell
"""Welcome to IfcOpenShell! IfcOpenShell provides a way to read and write IFCs.
Typically used for opening an IFC via a filepath, or accessing one of the
submodules.
IfcOpenShell can open IFC files, read entities (such as walls, buildings,
properties, systems, etc), edit attributes, write out ``.ifc`` files and more.
This module provides primitive functions to interact with IFC, including:
- For most users, you can open and read IFC models, see docs for :func:`open`.
This returns an :class:`file` object representing the IFC model. You can then
query the model to filter elements.
- For developers, you can query the schema itself, see docs for
:func:`schema_by_name`. This returns a schema object which you can use to
analyse the definitions of IFC classes and data types.
You may also be interested in:
- For model authoring and editing operations, see :mod:`ifcopenshell.api`.
- For extracting information from models, see :mod:`ifcopenshell.util`.
- For processing geometry, see :mod:`ifcopenshell.geom`.
For more details, consult https://docs.ifcopenshell.org/
Example:
.. code:: python
import ifcopenshell
print(ifcopenshell.version) # v0.7.0-1b1fd1e6
model = ifcopenshell.open("/path/to/model.ifc")
walls = model.by_type("IfcWall")
for wall in walls:
print(wall.Name)
"""
import os
@@ -219,7 +243,7 @@ def schema_by_name(
def guess_format(path: Path) -> Union[str | None]:
"""Try to guess format using file extension
"""Guesses the IFC format using file extension
IFCs may be serialised as different formats. The most common is a ``.ifc``
file, which is plaintext and stores data using the STEP Physical File
@@ -229,6 +253,9 @@ def guess_format(path: Path) -> Union[str | None]:
has the extension of .xml or .ifcxml (case insensitive), it will return
.ifcXML.
Users generally won't call this function. The :func:`open` function uses
this internally to guess the file format.
:return: Either .ifc, .ifcZIP, .ifcXML, .ifcJSON, .ifcSQLite, or None.
"""
suffix = path.suffix.lower()
@@ -245,4 +272,5 @@ def guess_format(path: Path) -> Union[str | None]:
return None
from .main import *
version = ifcopenshell_wrapper.version()
get_log = ifcopenshell_wrapper.get_log
@@ -16,7 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""High level user-oriented IFC authoring capabilities"""
"""High level IFC authoring and editing functions
Authoring, editing, and deleting IFC data requires a detailed understanding of
the rules of the IFC schema. This API module provides simple to use authoring
functions that hide this complexity from you. Things like managing differences
between IFC versions, tracking owernship changes, or cleaning up after orphaned
relationships are all handled automatically.
"""
import json
import numpy
@@ -24,13 +31,12 @@ import pkgutil
import inspect
import importlib
import ifcopenshell
import ifcopenshell.api
from typing import Callable, Any, Optional
from functools import partial
pre_listeners = {}
post_listeners = {}
pre_listeners: dict[str, dict] = {}
post_listeners: dict[str, dict] = {}
def batching_argument_deprecation(
@@ -128,8 +134,8 @@ ARGUMENTS_DEPRECATION = {
}
CACHED_USECASE_CLASSES = {}
CACHED_USECASES = {}
CACHED_USECASE_CLASSES: dict[str, Callable] = {}
CACHED_USECASES: dict[str, Callable] = {}
def run(
@@ -250,8 +256,6 @@ def extract_docs(module, usecase):
import typing
import collections
results = []
inputs = collections.OrderedDict()
function_init = getattr(getattr(ifcopenshell.api, module), usecase).Usecase.__init__
@@ -307,7 +311,7 @@ def wrap_usecase(usecase_path, usecase):
try:
result = usecase(*args, **settings)
except TypeError as e:
msg = f"Incorrect function arguments provided for {usecase_path}\n{str(e)}. You specified args {args} and settings {settings}\n\nCorrect signature is {inspect.signature(Usecase.__init__)}\nSee help(ifcopenshell.api.{usecase_path}) for documentation."
msg = f"Incorrect function arguments provided for {usecase_path}\n{str(e)}. You specified args {args} and settings {settings}\n\nCorrect signature is {inspect.signature(usecase)}\nSee help(ifcopenshell.api.{usecase_path}) for documentation."
raise TypeError(msg) from e
if should_run_listeners:
@@ -196,33 +196,36 @@ class entity_instance:
@staticmethod
def walk(f: Callable[[Any], bool], g: Callable[[Any], Any], value: Any) -> Any:
"""
Applies transformation to `value` based on a given condition.
If value is a nested structure (e.g., a list or a tuple) will apply transformation to it's elements.
.
"""Applies a transformation to `value` based on a given condition.
:param f: A callable that takes a single argument and returns a boolean value. It represents the condition
:type f: Callable
:param g: A callable that takes a single argument and returns a transformed value. It represents the transformation
:type g: Callable
:param value: Any object, the input value to be processed
:type value: Any
:return: Transformed value
:rtype: Any
If value is a nested structure (e.g., a list or a tuple) will apply
transformation to it's elements.
Example:
:param f: A callable that takes a single argument and returns a boolean
value. It represents the condition.
:type f: Callable
:param g: A callable that takes a single argument and returns a
transformed value. It represents the transformation.
:type g: Callable
:param value: Any object, the input value to be processed
:type value: Any
:return: Transformed value
:rtype: Any
.. code:: python
Example:
# Define condition and transformation functions
condition = lambda v: v == old
transform = lambda v: new
.. code:: python
# Usage example
attribute_value = element.RelatedElements
print(old in attribute_value, new in attribute_value) # True, False
result = element.walk(condition, transform, element.RelatedElements)
print(old in attribute_value, new in attribute_value) # False, True
# Define condition and transformation functions
condition = lambda v: v == old
transform = lambda v: new
# Usage example
attribute_value = element.RelatedElements
print(old in attribute_value, new in attribute_value) # True, False
result = element.walk(condition, transform, element.RelatedElements)
print(old in attribute_value, new in attribute_value) # False, True
"""
if isinstance(value, (tuple, list)):
+17 -11
View File
@@ -550,20 +550,26 @@ class file:
def __iter__(self):
return iter(self[id] for id in self.wrapped_data.entity_names())
def write(self, path: "os.PathLike | str", format=None, zipped=False) -> None:
def write(self, path: "os.PathLike | str", format: Optional[str] = None, zipped: bool = False) -> None:
"""Write ifc model to file.
:param format: Force use of a specific format. Guessed from file name if None.
Supported formats : .ifc, .ifcXML, .ifcZIP (equivalent to format=".ifc" with zipped=True)
For zipped .ifcXML use format=".ifcXML" with zipped=True
:param format: Force use of a specific format. Guessed from file name
if None. Supported formats : .ifc, .ifcXML, .ifcZIP (equivalent to
format=".ifc" with zipped=True) For zipped .ifcXML use
format=".ifcXML" with zipped=True
:type format: str
:param zipped: zip the file after it is written
:type zipped: bool
Examples:
>>> model.write("path/to/model.ifc")
>>> model.write("path/to/model.ifcXML")
>>> model.write("path/to/model.ifcZIP")
>>> model.write("path/to/model.ifcZIP", format=".ifcXML", zipped=True)
>>> model.write("path/to/model.anyextension", format=".ifcXML")
Example:
.. code:: python
model.write("path/to/model.ifc")
model.write("path/to/model.ifcXML")
model.write("path/to/model.ifcZIP")
model.write("path/to/model.ifcZIP", format=".ifcXML", zipped=True)
model.write("path/to/model.anyextension", format=".ifcXML")
"""
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
@@ -595,7 +601,7 @@ class file:
return
@staticmethod
def from_string(s: str) -> file:
def from_string(s: str) -> "file":
return file(ifcopenshell_wrapper.read(s))
@staticmethod
@@ -16,8 +16,16 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Geometry processing and analysis"""
"""Geometry processing and analysis
IFC may define geometry explicitly (such as meshes) or implicitly (such as
parametric extrusions). This module provides methods to extract geometric
definitions in IFC into explicitly tessellated triangles or OpenCASCADE Breps
for further processing.
This is typically needed when writing software to visualise or analyse
geometry. See also :mod:`ifcopenshell.util.shape` for deriving quantities.
"""
def _has_occ():
+7 -1
View File
@@ -16,8 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Reads and writes encoded GlobalIds"""
"""Reads and writes encoded GlobalIds
IFC entities may be identified using a unique ID (called a UUID or GUID). This
128-bit label is often represented in the form
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. However, in IFC, it is also usually
stored as a 22 character base 64 encoded string. This module lets you convert
between these representations and generate new UUIDs.
"""
import uuid
import string
@@ -1,23 +0,0 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2021 Thomas Krijnen <thomas@aecgeeks.com>
#
# This file is part of IfcOpenShell.
#
# IfcOpenShell is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcOpenShell is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
from . import ifcopenshell_wrapper
version = ifcopenshell_wrapper.version()
get_log = ifcopenshell_wrapper.get_log
@@ -16,4 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
"""Utility functions for common IFC queries"""
"""Utility functions for extracting IFC data
Data in IFC files is represented using relationships between IFC entities. To
extract data like "what properties does this wall have" involves looping
through these relationships which can be tedious.
This module makes it easy to get commonly requested data from IFC
relationships, such as properties of a wall, what elements are connected to
pipes, dates from work schedules, filtering maintainable elements, and more.
"""