diff --git a/pyproject.toml b/pyproject.toml index ea92b0ad6c..1e0121dedd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ include = ''' |ifcopenshell-python |ifcsverchok |opencdeserver - )/.*.py$ + )/.*.pyi?$ ''' extend-exclude = ''' src/ifcopenshell-python/ifcopenshell/express/* diff --git a/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi b/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi index 85cb0171f2..a9de6b7bb4 100644 --- a/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi +++ b/src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.pyi @@ -1,10 +1,28 @@ -# ifcopenshell_wrapper.pyi +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2021 Thomas Krijnen +# +# 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 . -class FileDescription: +from typing import Any + +class FileDescription(HeaderEntity): description: tuple[str, ...] implementation_level: str -class FileName: +class FileName(HeaderEntity): name: str time_stamp: str author: tuple[str, ...] @@ -14,8 +32,1268 @@ class FileName: authorization: str class IfcSpfHeader: + def file(self, *args): ... @property def file_description(self) -> FileDescription: ... - @property def file_name(self) -> FileName: ... + @property + def file_schema(self): ... + def read(self): ... + def tryRead(self): ... + def write(self, out): ... + +class BRep(Representation): + def as_compound(self, force_meters): ... + def begin(self): ... + def calculate_projected_surface_area(self, ax, along_x, along_y, along_z): ... + def calculate_surface_area(self, arg2): ... + def calculate_volume(self, arg2): ... + def end(self): ... + def item(self, i): ... + def item_id(self, i): ... + def shapes(self): ... + def size(self): ... + +class BRepElement(Element): + def calculate_projected_surface_area(self, along_x, along_y, along_z): ... + @property + def geometry(self): ... + def geometry_pointer(self): ... + @property + def surface_area(self): ... + @property + def volume(self): ... + +class CacheShapes: + name: Any + description: Any + defaultvalue: Any + +class CgalEmitOriginalEdges: + name: Any + description: Any + defaultvalue: Any + +class ColladaSerializer(WriteOnlyGeometrySerializer): + def finalize(self): ... + def isTesselated(self): ... + def object_id(self, o): ... + def ready(self): ... + def setFile(self, arg2): ... + def setUnitNameAndMagnitude(self, name, magnitude): ... + def write(self, *args): ... + def writeHeader(self): ... + +class ComputeCurvature: + name: Any + description: Any + defaultvalue: Any + +class ConversionResult: + def ItemId(self): ... + def Placement(self): ... + def Shape(self): ... + def Style(self): ... + def StylePtr(self): ... + def append(self, trsf): ... + def hasStyle(self): ... + def prepend(self, trsf): ... + def setStyle(self, newStyle): ... + +class ConversionResultShape: + def Serialize(self, place, arg3): ... + def Triangulate(self, *args): ... + def add(self, arg2): ... + def area(self): ... + def axis(self): ... + def bounding_box(self, *args): ... + def box(self): ... + def convex_decomposition(self): ... + def convex_tag(self, b): ... + def edges(self): ... + def facets(self): ... + def halfspaces(self): ... + def intersect(self, arg2): ... + def is_manifold(self): ... + def length(self): ... + def map(self, *args): ... + def moved(self, arg2): ... + def num_edges(self): ... + def num_faces(self): ... + def num_vertices(self): ... + def plane_equation(self): ... + def position(self): ... + def serialize(self): ... + def serialize_obj(self): ... + def set_box(self, b): ... + def solid(self): ... + def solid_mt(self): ... + def subtract(self, arg2): ... + def surface_genus(self): ... + def vertices(self): ... + def volume(self): ... + +class DoubleArray3: + def back(self): ... + def begin(self): ... + def empty(self): ... + def end(self): ... + def fill(self, u): ... + def front(self): ... + def iterator(self): ... + def rbegin(self): ... + def rend(self): ... + def size(self): ... + def swap(self, v): ... + +class Element: + def SetParents(self, newparents): ... + @property + def context(self): ... + @property + def guid(self): ... + @property + def id(self): ... + @property + def name(self): ... + @property + def parent_id(self): ... + def parents(self): ... + @property + def product(self): ... + @property + def transformation(self): ... + @property + def transformation_buffer(self): ... + @property + def type(self): ... + @property + def unique_id(self): ... + +class FileSchema(HeaderEntity): + schema_identifiers: Any + +class FunctionStepParam: + name: Any + description: Any + defaultvalue: Any + +class FunctionStepType: + name: Any + description: Any + defaultvalue: Any + +class GeometrySerializer: + READ_BREP: Any + READ_TRIANGULATION: Any + def geometry_settings(self, *args): ... + def isTesselated(self): ... + def object_id(self, o): ... + def read(self, *args): ... + def setUnitNameAndMagnitude(self, name, magnitude): ... + def settings(self, *args): ... + def write(self, *args): ... + +class HdfSerializer(GeometrySerializer): + def finalize(self): ... + def isTesselated(self): ... + def read(self, *args): ... + def ready(self): ... + def remove(self, guid): ... + def setFile(self, arg2): ... + def setUnitNameAndMagnitude(self, arg2, arg3): ... + def write(self, *args): ... + def writeHeader(self): ... + +class HeaderEntity: + def getArgument(self, index): ... + def getArgumentCount(self): ... + def toString(self, upper): ... + +class IfcBaseEntity(entity_instance): + def declaration(self): ... + def get(self, name): ... + def get_inverse(self, name): ... + def populate_derived(self): ... + def set_id(self, i): ... + +class IfcBaseType(entity_instance): + def declaration(self): ... + +class IfcEntityInstanceData: ... + +class IfcLateBoundEntity(IfcBaseEntity): + def declaration(self): ... + +class InstanceReference: ... + +class Iterator: + def bounds_max(self): ... + def bounds_min(self): ... + def compute_bounds(self, with_geometry): ... + def create(self): ... + def file(self): ... + def filters(self, *args): ... + def get(self): ... + def getLog(self): ... + def get_native(self): ... + def get_object(self, id): ... + def had_error_processing_elements(self): ... + def initialize(self): ... + def next(self): ... + def process_concurrently(self): ... + def process_finished_rep(self, rep): ... + def progress(self): ... + def set_cache(self, cache): ... + def unit_magnitude(self): ... + def unit_name(self): ... + +class OcctNoCleanTriangulation: + name: Any + description: Any + defaultvalue: Any + +class OpaqueCoordinate_3: + def get(self, i): ... + def set(self, i, n): ... + +class OpaqueCoordinate_4: + def get(self, i): ... + def set(self, i, n): ... + +class OpaqueNumber: + def clone(self): ... + def to_double(self): ... + def to_string(self): ... + +class PermissiveShapeReuse: + name: Any + description: Any + defaultvalue: Any + +class Representation: + def entity(self): ... + @property + def id(self): ... + def settings(self): ... + +class Serialization(Representation): + @property + def brep_data(self): ... + @property + def surface_style_ids(self): ... + @property + def surface_styles(self): ... + +class SerializedElement(Element): + @property + def geometry(self): ... + +class SerializerSettings: + def get_(self, name): ... + def get_type(self, name): ... + def set_(self, *args): ... + def setting_names(self): ... + +class Settings: + def get_(self, name): ... + def get_type(self, name): ... + def set_(self, *args): ... + def setting_names(self): ... + +class SvgSerializer (WriteOnlyGeometrySerializer): + SH_NONE: Any + SH_FULL: Any + SH_LEFT: Any + def addDrawing(self, pos, dir, ref, name, include_projection): ... + def addSizeComponent(self, fi): ... + def addTextAnnotations(self, k): ... + def addXCoordinate(self, fi): ... + def addYCoordinate(self, fi): ... + def doWriteHeader(self): ... + def finalize(self): ... + def getMirrorX(self): ... + def getMirrorY(self): ... + def getOnlyValid(self, b): ... + def getProfileThreshold(self): ... + def getSegmentProjection(self): ... + def getSubtractionSettings(self): ... + def getUnifyInputs(self): ... + def getUsePrefiltering(self): ... + def growBoundingBox(self, x, y): ... + def idElement(self, elem): ... + def isTesselated(self): ... + def nameElement(self, *args): ... + def object_id(self, storey, o): ... + def ready(self): ... + def resetScale(self): ... + def resize(self): ... + def setAlwaysProject(self, b): ... + def setAutoElevation(self, b): ... + def setAutoSection(self, b): ... + def setBoundingRectangle(self, width, height): ... + def setDrawDoorArcs(self, b): ... + def setDrawStoreyHeights(self, sh): ... + def setDrawingCenter(self, x, y): ... + def setElevationRef(self, s): ... + def setElevationRefGuid(self, s): ... + def setFile(self, f): ... + def setMirrorX(self, b): ... + def setMirrorY(self, b): ... + def setNoCSS(self, b): ... + def setOnlyValid(self, b): ... + def setPolygonal(self, b): ... + def setPrintSpaceAreas(self, b): ... + def setPrintSpaceNames(self, b): ... + def setProfileThreshold(self, i): ... + def setScale(self, s): ... + def setSectionHeight(self, h, storey): ... + def setSectionHeightsFromStoreys(self, offset): ... + def setSectionRef(self, s): ... + def setSegmentProjection(self, b): ... + def setSpaceNameTransform(self, v): ... + def setStoreyHeightLineLength(self, d): ... + def setSubtractionSettings(self, sbp): ... + def setUnifyInputs(self, b): ... + def setUnitNameAndMagnitude(self, arg2, arg3): ... + def setUseHlrPoly(self, b): ... + def setUseNamespace(self, b): ... + def setUsePrefiltering(self, b): ... + def setWithoutStoreys(self, b): ... + def start_path(self, *args): ... + def write(self, *args): ... + def writeHeader(self): ... + +class SwigPyIterator: + def advance(self, n): ... + def copy(self): ... + def decr(self, n): ... + def distance(self, x): ... + def equal(self, x): ... + def incr(self, n): ... + def next(self): ... + def previous(self): ... + def value(self): ... + +class Transformation: + def data(self): ... + @property + def matrix(self): ... + +class Triangulation(Representation): + def addEdge(self, item_id, style, i0, i1): ... + def addFace(self, *args): ... + def addNormal(self, X, Y, Z): ... + def addVertex(self, item_index, material_index, X, Y, Z): ... + @staticmethod + def box_project_uvs(vertices, normals): ... + @property + def colors_buffer(self): ... + @property + def edges(self): ... + @property + def edges_buffer(self): ... + def edges_item_ids(self): ... + @property + def edges_item_ids_buffer(self): ... + @staticmethod + def empty(settings): ... + @property + def faces(self): ... + @property + def faces_buffer(self): ... + @property + def faces_tri(self): ... + @property + def item_ids(self): ... + @property + def item_ids_buffer(self): ... + @property + def material_ids(self): ... + @property + def material_ids_buffer(self): ... + @property + def materials(self): ... + @property + def normals(self): ... + @property + def normals_buffer(self): ... + @property + def polyhedral_faces_with_holes(self): ... + @property + def polyhedral_faces_without_holes(self): ... + def registerEdge(self, item_id, i0, i1): ... + def registerEdgeCount(self, n1, n2, edgecount): ... + def resetWelds(self): ... + @property + def uvs(self): ... + def uvs_ref(self): ... + @property + def verts(self): ... + @property + def verts_buffer(self): ... + +class TriangulationElement(Element): + @property + def geometry(self): ... + def geometry_pointer(self): ... + +class TriangulationType: + name: Any + description: Any + defaultvalue: Any + +class TtlWktSerializer(WriteOnlyGeometrySerializer): + def finalize(self): ... + def isTesselated(self): ... + def ready(self): ... + def setFile(self, arg2): ... + def setUnitNameAndMagnitude(self, arg2, arg3): ... + def ttl_object_id(self, o, postfix): ... + def write(self, *args): ... + def writeHeader(self): ... + +class WaveFrontOBJSerializer(WriteOnlyGeometrySerializer): + def finalize(self): ... + def isTesselated(self): ... + def ready(self): ... + def setFile(self, arg2): ... + def setUnitNameAndMagnitude(self, arg2, arg3): ... + def write(self, *args): ... + def writeHeader(self): ... + def writeMaterial(self, style): ... + +class WriteOnlyGeometrySerializer(GeometrySerializer): + def read(self, *args): ... + +class XmlSerializer: + def finalize(self): ... + def ready(self): ... + def setFile(self, arg2): ... + def writeHeader(self): ... + +class XmlSerializerFactory: + @staticmethod + def implementations(): ... + +class abstract_arrangement: + def get_face_pairs(self): ... + def merge(self, edge_indices): ... + def num_edges(self): ... + def num_faces(self): ... + def write(self, polygons, progress): ... + +class aggregation_type(parameter_type): + array_type: Any + bag_type: Any + list_type: Any + set_type: Any + def as_aggregation_type(self): ... + def bound1(self): ... + def bound2(self): ... + def type_of_aggregation(self): ... + def type_of_aggregation_string(self): ... + def type_of_element(self): ... + +class attribute: + def name(self): ... + def optional(self): ... + def type_of_attribute(self): ... + +class attribute_value_derived: ... + +class boolean_result: + INTERSECTION: Any + SUBTRACTION: Any + UNION: Any + def calc_hash(self): ... + @property + def children(self): ... + def clone_(self): ... + def kind(self): ... + @staticmethod + def operation_str(op): ... + +class bspline_curve(curve): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + +class bspline_surface(surface): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + +class buffer: + def filename(self): ... + def get_value(self): ... + def is_ready(self): ... + +class cant_function(function_item): + def calc_hash(self): ... + def clone_(self): ... + def end(self): ... + def get_cant(self): ... + def get_gradient(self): ... + def kind(self): ... + def start(self): ... + +class circle(curve): + def calc_hash(self): ... + def clone_(self): ... + @staticmethod + def from_3_points(p1, p2, p3): ... + def kind(self): ... + @property + def matrix(self): ... + +class clash: ... + +class clashes: + def append(self, x): ... + def assign(self, n, x): ... + def back(self): ... + def begin(self): ... + def capacity(self): ... + def clear(self): ... + def empty(self): ... + def end(self): ... + def erase(self, *args): ... + def front(self): ... + def get_allocator(self): ... + def insert(self, *args): ... + def iterator(self): ... + def pop(self): ... + def pop_back(self): ... + def push_back(self, x): ... + def rbegin(self): ... + def rend(self): ... + def reserve(self, n): ... + def resize(self, *args): ... + def size(self): ... + def swap(self, v): ... + +class collection: + def calc_hash(self): ... + @property + def children(self): ... + def clone_(self): ... + def kind(self): ... + @property + def matrix(self): ... + +class colour(item): + def b(self): ... + def calc_hash(self): ... + def clone_(self): ... + @property + def components(self): ... + def g(self): ... + def kind(self): ... + def r(self): ... + +class context: + def add(self, segments): ... + def build(self): ... + def get_face_pairs(self): ... + def merge(self, edge_indices): ... + def num_edges(self): ... + def num_faces(self): ... + def write(self, arg2): ... + +class curve(geom_item): + def print_impl(self, o, classname, indent): ... + +class cylinder(surface): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + @property + def matrix(self): ... + +class declaration: + def as_entity(self): ... + def as_enumeration_type(self): ... + def as_select_type(self): ... + def as_type_declaration(self): ... + def index_in_schema(self): ... + def name(self): ... + def name_uc(self): ... + def schema(self): ... + def type(self): ... + +class direction3: + def calc_hash(self): ... + def clone_(self): ... + @property + def components(self): ... + def kind(self): ... + +class drawing_meta: ... + +class edge(trimmed_curve): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + +class ellipse(curve): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + @property + def matrix(self): ... + +class entity(declaration): + def all_attributes(self): ... + def all_inverse_attributes(self): ... + def argument_types(self): ... + def as_entity(self): ... + def attribute_by_index(self, index): ... + def attribute_count(self): ... + def attribute_index(self, *args): ... + def attributes(self): ... + def derived(self): ... + def is_abstract(self): ... + def set_attributes(self, attributes, derived): ... + def set_inverse_attributes(self, inverse_attributes): ... + def set_subtypes(self, subtypes): ... + def subtypes(self): ... + def supertype(self): ... + +class entity_instance: + def data(self, *args): ... + def declaration(self): ... + def file_pointer(self): ... + def get_argument(self, *args): ... + def get_argument_index(self, a): ... + def get_argument_name(self, i): ... + def get_argument_type(self, i): ... + def get_attribute_category(self, name): ... + def get_attribute_names(self): ... + def get_inverse(self, a): ... + def get_inverse_attribute_names(self): ... + def id(self): ... + def identity(self): ... + def is_a(self, *args): ... + def setArgumentAsAggregateOfAggregateOfDouble(self, i, v): ... + def setArgumentAsAggregateOfAggregateOfEntityInstance(self, i, v): ... + def setArgumentAsAggregateOfAggregateOfInt(self, i, v): ... + def setArgumentAsAggregateOfDouble(self, i, v): ... + def setArgumentAsAggregateOfEntityInstance(self, i, v): ... + def setArgumentAsAggregateOfInt(self, i, v): ... + def setArgumentAsAggregateOfString(self, i, v): ... + def setArgumentAsBool(self, i, v): ... + def setArgumentAsDouble(self, i, v): ... + def setArgumentAsEntityInstance(self, i, v): ... + def setArgumentAsInt(self, i, v): ... + def setArgumentAsLogical(self, i, v): ... + def setArgumentAsNull(self, i): ... + def setArgumentAsString(self, i, a): ... + def toString(self, arg2, upper): ... + def to_string(self, valid_spf): ... + def unset_attribute_value(self, i): ... + +class enumeration_type(declaration): + def argument_types(self): ... + def as_enumeration_type(self): ... + def enumeration_items(self): ... + def lookup_enum_offset(self, string): ... + def lookup_enum_value(self, i): ... + +class equal_functor: ... + +class extrusion(sweep): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + @property + def matrix(self): ... + +class face: + def calc_hash(self): ... + @property + def children(self): ... + def clone_(self): ... + def kind(self): ... + @property + def matrix(self): ... + def print_impl(self, o, indent): ... + +class file: + INSTANCE_ID: Any + INSTANCE_TYPE: Any + ATTRIBUTE_INDEX: Any + def FreshId(self): ... + def add(self, entity, id): ... + def addEntities(self, entities): ... + def batch(self): ... + def build_inverses(self): ... + def by_guid(self, guid): ... + def by_id(self, id): ... + def by_type(self, *args): ... + def by_type_excl_subtypes(self, *args): ... + @staticmethod + def createTimestamp(): ... + def entity_names(self): ... + def file_pointer(self): ... + def getInverse(self, instance_id, type, attribute_index): ... + def getMaxId(self): ... + def getTotalInverses(self, instance_id): ... + def getUnit(self, unit_type): ... + def get_inverse(self, e): ... + def get_inverse_indices(self, *args): ... + def get_total_inverses(self, e): ... + def good(self): ... + @staticmethod + def guid_map(*args): ... + @property + def header(self): ... + def ifcroot_type(self): ... + def instance_by_guid(self, guid): ... + def instances_by_reference(self, id): ... + def internal_guid_map(self): ... + def load(self, entity_instance_name, entity, arg4, attribute_index): ... + def recalculate_id_counter(self): ... + def remove(self, entity): ... + @property + def schema(self): ... + def to_string(self): ... + @staticmethod + def traverse(instance, max_level): ... + @staticmethod + def traverse_breadth_first(instance, max_level): ... + def try_read_semicolon(self): ... + def types(self): ... + def types_begin(self): ... + def types_end(self): ... + def unbatch(self): ... + def write(self, fn): ... + +class file_open_status: + SUCCESS: Any + READ_ERROR: Any + NO_HEADER: Any + UNSUPPORTED_SCHEMA: Any + INVALID_SYNTAX: Any + def value(self): ... + +class fn_evaluator: + def clone(self): ... + def end(self): ... + def evaluate(self, u): ... + def length(self): ... + def start(self): ... + +class function_item(implicit_item): + def calc_hash(self): ... + def end(self): ... + def kind(self): ... + def length(self): ... + def start(self): ... + +class function_item_evaluator: + def evaluate(self, *args): ... + def evaluation_points(self, *args): ... + +class functor_item(function_item): + def calc_hash(self): ... + def clone_(self): ... + def end(self): ... + def kind(self): ... + def start(self): ... + +class geom_item(item): ... + +class geometry_exception: + def what(self): ... + +class gradient_function(function_item): + def calc_hash(self): ... + def clone_(self): ... + def end(self): ... + def get_horizontal(self): ... + def get_vertical(self): ... + def kind(self): ... + def start(self): ... + +class hash_functor: ... +class horizontal_plan_at_element: ... +class implicit_item(geom_item): ... + +class inverse_attribute: + bag_type: Any + set_type: Any + unspecified_type: Any + def attribute_reference(self): ... + def bound1(self): ... + def bound2(self): ... + def entity_reference(self): ... + def name(self): ... + def type_of_aggregation(self): ... + def type_of_aggregation_string(self): ... + +class item: + def calc_hash(self): ... + def clone_(self): ... + def hash(self): ... + def identity(self): ... + def kind(self): ... + def reverse(self): ... + +class less_functor: ... + +class line(curve): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + @property + def matrix(self): ... + +class line_segment: + def back(self): ... + def begin(self): ... + def empty(self): ... + def end(self): ... + def fill(self, u): ... + def front(self): ... + def iterator(self): ... + def rbegin(self): ... + def rend(self): ... + def size(self): ... + def swap(self, v): ... + +class loft: + def calc_hash(self): ... + @property + def children(self): ... + def clone_(self): ... + def kind(self): ... + def print_impl(self, o, indent): ... + +class loop: + def calc_hash(self): ... + def calculate_linear_edge_curves(self): ... + @property + def children(self): ... + def clone_(self): ... + def is_polyhedron(self): ... + def kind(self): ... + def remove_linear_edge_curves(self): ... + +class matrix4(item): + IDENTITY: Any + AFFINE_WO_SCALE: Any + AFFINE_W_UNIFORM_SCALE: Any + AFFINE_W_NONUNIFORM_SCALE: Any + OTHER: Any + def calc_hash(self): ... + def clone_(self): ... + @property + def components(self): ... + def is_identity(self): ... + def kind(self): ... + def translation_part(self): ... + +class named_type(parameter_type): + def as_named_type(self): ... + def declared_type(self): ... + +class node(item): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + +class offset_curve(curve): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + +class offset_function(function_item): + def calc_hash(self): ... + def clone_(self): ... + def end(self): ... + def get_basis(self): ... + def get_offset(self): ... + def kind(self): ... + def start(self): ... + +class parameter_type: + def as_aggregation_type(self): ... + def as_named_type(self): ... + def as_simple_type(self): ... + +class piecewise_function(function_item): + def calc_hash(self): ... + def clone_(self): ... + def end(self): ... + def is_empty(self): ... + def kind(self): ... + def length(self): ... + def span_count(self): ... + def span_fn(self, i): ... + def spans(self): ... + def start(self): ... + +class plane(surface): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + @property + def matrix(self): ... + +class point3: + def calc_hash(self): ... + def clone_(self): ... + @property + def components(self): ... + def kind(self): ... + +class polygon_2: ... +class ray_intersection_result: ... + +class ray_intersection_results: + def append(self, x): ... + def assign(self, n, x): ... + def back(self): ... + def begin(self): ... + def capacity(self): ... + def clear(self): ... + def empty(self): ... + def end(self): ... + def erase(self, *args): ... + def front(self): ... + def get_allocator(self): ... + def insert(self, *args): ... + def iterator(self): ... + def pop(self): ... + def pop_back(self): ... + def push_back(self, x): ... + def rbegin(self): ... + def rend(self): ... + def reserve(self, n): ... + def resize(self, *args): ... + def size(self): ... + def swap(self, v): ... + +class revolve(sweep): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + @property + def matrix(self): ... + +class schema_definition: + def declaration_by_name(self, *args): ... + def declarations(self): ... + def entities(self): ... + def enumeration_types(self): ... + def instantiate(self, decl, data): ... + def name(self): ... + def select_types(self): ... + def type_declarations(self): ... + +class select_type(declaration): + def as_select_type(self): ... + def select_list(self): ... + +class shell: + def calc_hash(self): ... + @property + def children(self): ... + def clone_(self): ... + def kind(self): ... + def print_impl(self, o, indent): ... + +class simple_type(parameter_type): + binary_type: Any + boolean_type: Any + integer_type: Any + logical_type: Any + number_type: Any + real_type: Any + string_type: Any + datatype_COUNT: Any + def as_simple_type(self): ... + def declared_type(self): ... + +class solid: + def calc_hash(self): ... + @property + def children(self): ... + def clone_(self): ... + def kind(self): ... + @property + def matrix(self): ... + +class sphere(surface): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + @property + def matrix(self): ... + +class style(item): + def calc_hash(self): ... + def clone_(self): ... + def get_color(self): ... + def has_specularity(self): ... + def has_transparency(self): ... + def instance_id(self): ... + def kind(self): ... + +class surface(geom_item): ... + +class svg_groups_of_line_segments: + def append(self, x): ... + def assign(self, n, x): ... + def back(self): ... + def begin(self): ... + def capacity(self): ... + def clear(self): ... + def empty(self): ... + def end(self): ... + def erase(self, *args): ... + def front(self): ... + def get_allocator(self): ... + def insert(self, *args): ... + def iterator(self): ... + def pop(self): ... + def pop_back(self): ... + def push_back(self, x): ... + def rbegin(self): ... + def rend(self): ... + def reserve(self, n): ... + def resize(self, *args): ... + def size(self): ... + def swap(self, v): ... + +class svg_groups_of_polygons: + def append(self, x): ... + def assign(self, n, x): ... + def back(self): ... + def begin(self): ... + def capacity(self): ... + def clear(self): ... + def empty(self): ... + def end(self): ... + def erase(self, *args): ... + def front(self): ... + def get_allocator(self): ... + def insert(self, *args): ... + def iterator(self): ... + def pop(self): ... + def pop_back(self): ... + def push_back(self, x): ... + def rbegin(self): ... + def rend(self): ... + def reserve(self, n): ... + def resize(self, *args): ... + def size(self): ... + def swap(self, v): ... + +class svg_line_segments: + def append(self, x): ... + def assign(self, n, x): ... + def back(self): ... + def begin(self): ... + def capacity(self): ... + def clear(self): ... + def empty(self): ... + def end(self): ... + def erase(self, *args): ... + def front(self): ... + def get_allocator(self): ... + def insert(self, *args): ... + def iterator(self): ... + def pop(self): ... + def pop_back(self): ... + def push_back(self, x): ... + def rbegin(self): ... + def rend(self): ... + def reserve(self, n): ... + def resize(self, *args): ... + def size(self): ... + def swap(self, v): ... + +class svg_loop: + def append(self, x): ... + def assign(self, n, x): ... + def back(self): ... + def begin(self): ... + def capacity(self): ... + def clear(self): ... + def empty(self): ... + def end(self): ... + def erase(self, *args): ... + def front(self): ... + def get_allocator(self): ... + def insert(self, *args): ... + def iterator(self): ... + def pop(self): ... + def pop_back(self): ... + def push_back(self, x): ... + def rbegin(self): ... + def rend(self): ... + def reserve(self, n): ... + def resize(self, *args): ... + def size(self): ... + def swap(self, v): ... + +class svg_loops: + def append(self, x): ... + def assign(self, n, x): ... + def back(self): ... + def begin(self): ... + def capacity(self): ... + def clear(self): ... + def empty(self): ... + def end(self): ... + def erase(self, *args): ... + def front(self): ... + def get_allocator(self): ... + def insert(self, *args): ... + def iterator(self): ... + def pop(self): ... + def pop_back(self): ... + def push_back(self, x): ... + def rbegin(self): ... + def rend(self): ... + def reserve(self, n): ... + def resize(self, *args): ... + def size(self): ... + def swap(self, v): ... + +class svg_point: + def back(self): ... + def begin(self): ... + def empty(self): ... + def end(self): ... + def fill(self, u): ... + def front(self): ... + def iterator(self): ... + def rbegin(self): ... + def rend(self): ... + def size(self): ... + def swap(self, v): ... + +class svg_polygons: + def append(self, x): ... + def assign(self, n, x): ... + def back(self): ... + def begin(self): ... + def capacity(self): ... + def clear(self): ... + def empty(self): ... + def end(self): ... + def erase(self, *args): ... + def front(self): ... + def get_allocator(self): ... + def insert(self, *args): ... + def iterator(self): ... + def pop(self): ... + def pop_back(self): ... + def push_back(self, x): ... + def rbegin(self): ... + def rend(self): ... + def reserve(self, n): ... + def resize(self, *args): ... + def size(self): ... + def swap(self, v): ... + +class sweep(geom_item): ... + +class sweep_along_curve(sweep): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + +class too_many_faces_exception(geometry_exception): ... +class topology_error: ... + +class torus(surface): + def calc_hash(self): ... + def clone_(self): ... + def kind(self): ... + @property + def matrix(self): ... + +class tree: + def add_element(self, *args): ... + def add_file(self, *args): ... + def clash_clearance_many(self, set_a, set_b, clearance, check_all): ... + def clash_collision_many(self, set_a, set_b, allow_touching): ... + def clash_intersection_many(self, set_a, set_b, tolerance, check_all): ... + def distances(self): ... + def enable_face_styles(self, *args): ... + @staticmethod + def is_manifold(fs): ... + def protrusion_distances(self): ... + def select(self, *args): ... + def select_box(self, *args): ... + def select_ray(self, p0, d, length): ... + def styles(self): ... + def uint8_to_b64(self, uuids_array): ... + @staticmethod + def vector_to_list(ps): ... + def write_h5(self): ... + +class trimmed_curve(geom_item): + def reverse(self): ... + +class type_by_kind: + max: Any + +class type_declaration(declaration): + def argument_types(self): ... + def as_type_declaration(self): ... + def declared_type(self): ... + +def Triangulation_box_project_uvs(vertices, normals): ... +def Triangulation_empty(settings): ... +def XmlSerializerFactory_implementations(): ... +def arrange_polygons(polygons): ... +def boolean_result_operation_str(op): ... +def circle_from_3_points(p1, p2, p3): ... +def clear_schemas(): ... +def construct_iterator_with_include_exclude(geometry_library, settings, file, elems, include, num_threads): ... +def construct_iterator_with_include_exclude_globalid(geometry_library, settings, file, elems, include, num_threads): ... +def construct_iterator_with_include_exclude_id(geometry_library, settings, file, elems, include, num_threads): ... +def create_box(*args): ... +def create_epeck(*args): ... +def create_shape(*args): ... +def file_createTimestamp(): ... +def file_guid_map(*args): ... +def file_traverse(instance, max_level): ... +def file_traverse_breadth_first(instance, max_level): ... +def flatten(deep): ... +def get_feature(x): ... +def get_info_cpp(v, include_identifier): ... +def get_log(): ... +def helmert_curve_point(A0, A1, A2, s): ... +def kind_to_string(k): ... +def less(arg1, arg2): ... +def line_segments_to_polygons(s, eps, segments): ... +def map_shape(settings, instance): ... +def nary_union(sequence): ... +def new_IfcBaseClass(schema_identifier, name): ... +def open(fn): ... +def parse_ifcxml(filename): ... +def polygons_to_svg(*args): ... +def read(data): ... +def register_schema(arg1): ... +def schema_by_name(arg1): ... +def schema_names(): ... +def serialise(schema_name, shape_str, advanced): ... +def set_feature(x, v): ... +def set_log_format_json(): ... +def set_log_format_text(): ... +def svg_to_line_segments(data, class_name): ... +def svg_to_polygons(data, class_name): ... +def taxonomy_item_repr(i): ... +def tesselate(schema_name, shape_str, d): ... +def tree_is_manifold(fs): ... +def tree_vector_to_list(ps): ... +def turn_off_detailed_logging(): ... +def turn_on_detailed_logging(): ... +def version(): ... diff --git a/src/ifcopenshell-python/ifcopenshell/util/scripts/validate_stub.py b/src/ifcopenshell-python/ifcopenshell/util/scripts/validate_stub.py new file mode 100644 index 0000000000..3b90fc1c03 --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/util/scripts/validate_stub.py @@ -0,0 +1,235 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2021 Thomas Krijnen +# +# 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 . + +"""Script to ensure ifcopenshell_wrapper.pyi and ifcopenshell_wrapper.py work in sync. + +Things we do check: +- all symbols from the wrapper present in the stub and vice versa +- functions and methods signatures +- read-only and settable properties, staticmethods +- class hierarchy +""" + + +import ast +import difflib +from pathlib import Path +from typing import Union +from typing_extensions import assert_never + + +def format_diff(lines: list[str]) -> None: + RED = "\033[91m" + GREEN = "\033[92m" + CYAN = "\033[96m" + RESET = "\033[0m" + for line in lines: + if line.startswith("+") and not line.startswith("+++"): + print(f"{GREEN}{line}{RESET}") + elif line.startswith("-") and not line.startswith("---"): + print(f"{RED}{line}{RESET}") + elif line.startswith("@@"): + print(f"{CYAN}{line}{RESET}") + else: + print(line) + + +SubnameType = Union[str, tuple[str, str]] + + +def get_function_node_name(node: ast.FunctionDef) -> Union[SubnameType, None]: + """ + :return: Function node name as ``SubnameType`` or ``None``, if function wasn't processed and can be skipped. + """ + node_name = node.name + if node_name.startswith("_"): + return None + args = [a.arg for a in node.args.args] + if node.args.vararg: + args.append("*args") + + node_name = f"def {node.name}" + node_name = f"{node_name}({', '.join(args)}): ..." + + decorators = tuple(f"@{d.id}" for d in node.decorator_list if isinstance(d, ast.Name)) + if len(decorators) == 1: + return decorators + (node_name,) + return node_name + + +def get_names_tree_lines(tree: ast.Module) -> list[str]: + # Get class tree. + names_tree: dict[str, set[SubnameType]] = {} + for node in tree.body: + subnames: set[SubnameType] = set() + node_name = None + if isinstance(node, ast.ClassDef): + # Skip `object_` as it's just a reference to `object`, + # which is implied by default. + bases = [b.id for b in node.bases if isinstance(b, ast.Name) and b.id != "_object"] + bases_str = f"({', '.join(bases)})" if bases else "" + node_name = f"class {node.name}{bases_str}:" + + for subnode in node.body: + subname = None + + if isinstance(subnode, ast.AnnAssign): + target = subnode.target + assert isinstance(target, ast.Name) + subname = target.id + + elif isinstance(subnode, ast.FunctionDef): + subname = get_function_node_name(subnode) + + elif isinstance(subnode, ast.Assign): + targets = subnode.targets + if not len(targets) == 1 or not isinstance(target := targets[0], ast.Name): + continue + subname_ = target.id + + if subname_.startswith("_"): + continue + + value = subnode.value + # Catching wrappers like: + # - `matrix = property(matrix_getter)` + # - `matrix = property(matrix_getter, matrix_setter)` + # - `operation_str = staticmethod(operation_str)` + if isinstance(value, ast.Call): + func = value.func + if not isinstance(func, ast.Name) or ((func_id := func.id) not in ("property", "staticmethod")): + continue + args = [arg.id for arg in value.args if isinstance(arg, ast.Name)] + len_args = len(args) + assert len_args in (1, 2) + + def find_method_by_name(name: str) -> Union[str, None]: + function_def = f"def {name}(" + return next( + ( + func_ + for func_ in subnames + if isinstance(func_, str) and func_.startswith(function_def) + ), + None, + ) + + # Use `set` for cases like `description = property(description, description)`. + wrapped_function = None + for arg in set(args): + assert (wrapped_function := find_method_by_name(arg)) + subnames.remove(wrapped_function) + + # TODO: sort it out in wrapper.py + # There's one annoying case in Element.product + # when property is overriding existing function, without using it. + # We should probably just exclude that function from the wrapper. + overridden_name = find_method_by_name(subname_) + if overridden_name: + subnames.remove(overridden_name) + + if len_args == 2: + # Has both getter and setter, can be defined as a simple attribute. + subname = subname_ + elif len_args == 1: + if func_id == "property": + # Has just getter, read-only, need to define it using a wrapper. + subname = (f"@{func_id}", f"def {subname_}(self): ...") + elif func_id == "staticmethod": + assert wrapped_function is not None + subname = (f"@{func_id}", f"def {subname_}({wrapped_function.split('(')[1]}") + else: + assert_never(func_id) + else: + assert_never(len_args) + else: + subname = subname_ + + if subname is not None: + subnames.add(subname) + if not subnames: + node_name += " ..." + + elif isinstance(node, ast.FunctionDef): + if node.name.startswith("_"): + continue + node_name = get_function_node_name(node) + assert isinstance(node_name, str) + + if node_name is not None: + names_tree[node_name] = subnames + + # Convert names tree to lines. + lines: list[str] = [] + indent = " " * 4 + + def subname_sort(subname: SubnameType) -> str: + if isinstance(subname, str): + if subname.startswith("def "): + return subname.split("(")[0].removeprefix("def ") + return subname + return subname_sort(subname[1]) + + for name, subnames in sorted(names_tree.items(), key=lambda x: x[0]): + lines.append(name) + for subname in sorted(subnames, key=subname_sort): + subitems = (subname,) if isinstance(subname, str) else subname + for item in subitems: + lines.append(f"{indent}{item}") + + return lines + + +def main() -> None: + package = Path(__file__).parent.parent.parent + stub_path = package / "ifcopenshell_wrapper.pyi" + wrapper_path = package / "ifcopenshell_wrapper.py" + + # Parse files + stub_tree = ast.parse(stub_path.read_text()) + wrapper_tree = ast.parse(wrapper_path.read_text()) + + # Extract class names + stub_classes = get_names_tree_lines(stub_tree) + wrapper_classes = get_names_tree_lines(wrapper_tree) + + # Use difflib to create a unified diff of class names + diff = difflib.unified_diff( + stub_classes, + wrapper_classes, + fromfile="stub.pyi classes", + tofile="wrapper.py classes", + lineterm="", + ) + diff = list(diff) + + format_diff(diff) + diff_no_header = diff[2:] + added = len([l for l in diff_no_header if l.startswith("+")]) + removed = len([l for l in diff_no_header if l.startswith("-")]) + + if added or removed: + print(f"Added lines: {added}") + print(f"Removed lines: {removed}") + raise Exception("Found discrepancies between stub and wrapper.") + else: + print(f"All good, no discrepancies between stub and wrapper. 🎉🎉") + + +if __name__ == "__main__": + main() diff --git a/src/ifcopenshell-python/test/util/scripts/test_validate_stub.py b/src/ifcopenshell-python/test/util/scripts/test_validate_stub.py new file mode 100644 index 0000000000..86d18bd356 --- /dev/null +++ b/src/ifcopenshell-python/test/util/scripts/test_validate_stub.py @@ -0,0 +1,25 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2021 Thomas Krijnen +# +# 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 . + +import pytest +import ifcopenshell.util.scripts.validate_stub as subject + + +class TestValidateStub: + def test_run(self): + subject.main()