From 228601aa1f6efba0f2443f0621cd8bf8dc939a31 Mon Sep 17 00:00:00 2001 From: alfonso Date: Mon, 30 Sep 2024 17:15:35 +0200 Subject: [PATCH] Submodules & docstrings: v1.0 --- _CMakeLists.txt | 139 ----------------------- expose_kernel_module.py | 245 +++++++++++++++++++++++----------------- stubs.py | 2 + 3 files changed, 146 insertions(+), 240 deletions(-) delete mode 100644 _CMakeLists.txt diff --git a/_CMakeLists.txt b/_CMakeLists.txt deleted file mode 100644 index 0e761a2c..00000000 --- a/_CMakeLists.txt +++ /dev/null @@ -1,139 +0,0 @@ -cmake_minimum_required(VERSION 3.25) - -# Updating CMP0048 policy no longer needed -# https://cmake.org/cmake/help/latest/policy/CMP0048.html - -# Get version + label from file -file(STRINGS "version" tudatpy_VERSION_LABEL) -list(GET tudatpy_VERSION_LABEL 0 tudatpy_VERSION_LABEL) -string( - REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" - tudatpy_VERSION "${tudatpy_VERSION_LABEL}" -) - -# Project declaration. -project(tudatpy VERSION "${tudatpy_VERSION}" LANGUAGES CXX C) - -# Initial log -################################################# -message("") -message(STATUS "<< ${PROJECT_NAME} (${CMAKE_BUILD_TYPE} - ${PROJECT_VERSION}) >>") -message(STATUS "System name: ${CMAKE_SYSTEM_NAME}") -message("") - - -# Add cmake modules -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") - - -# Additional compiler configuration -if (_ENABLE_EXTENDED_ALIGNED_STORAGE) - add_definitions("-D_ENABLE_EXTENDED_ALIGNED_STORAGE") -endif () -# `PyLong_Type' can not be used when making a shared object; recompile with -fPIC -#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") - -if (MINGW) - # https://github.com/tudat-team/tudatpy-feedstock/issues/3 - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_hypot=hypot") - # https://stackoverflow.com/questions/16596876/object-file-has-too-many-sections - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj") - # https://sourceforge.net/p/mingw-w64/mailman/message/33154210/ - # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--large-address-aware") -endif () - -if (MSVC) - # https://docs.microsoft.com/en-us/cpp/build/reference/bigobj-increase-number-of-sections-in-dot-obj-file?view=vs-2019 - # This is equivalent to the big-obj for MinGW, this should stop error C1128. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") -endif () - -# Build configuration -set(Boost_USE_STATIC_LIBS OFF) -set(Boost_USE_STATIC_RUNTIME OFF) -add_definitions(-DTUDAT_BUILD_WITH_SPICE_INTERFACE=1) - -# Possibly deprecated -if (TUDAT_INSTALL) - add_definitions(-DTUDAT_INSTALL=1) -endif () -if (TUDAT_CONDA_INSTALL) - add_definitions(-DTUDAT_CONDA_INSTALL=1) -endif () -if (TUDAT_TEST_INSTALL) - add_definitions(-DTUDAT_TEST_INSTALL=1) -endif () - -# Dependencies -###################################### - -# Boost -find_package( - Boost 1.78.0 - COMPONENTS thread date_time system unit_test_framework filesystem regex - REQUIRED -) - -# Eigen -# Second line allows to include instead of -find_package(Eigen3 REQUIRED) -include_directories(AFTER SYSTEM ${EIGEN3_INCLUDE_DIR}) - -# SPICE -if (${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) - find_package(CSpice REQUIRED 1.0.0) -else () - set(CSpice_INCLUDE_DIRS ${CSpice_BUILD_INCLUDE_DIRS}) -endif () - -# Sofa dependency. -if (${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME}) - find_package(Sofa 1.0.0 REQUIRED) -else () - set(Sofa_INCLUDE_DIRS ${Sofa_BUILD_INCLUDE_DIRS}) -endif () - -# NRLMSISE-00 -find_package(NRLMSISE00 0.1 REQUIRED) - -# Tudat -if (NOT Tudat_FOUND) - find_package(Tudat REQUIRED) - add_definitions(${Tudat_DEFINITIONS}) -else () - set(Tudat_INCLUDE_DIRS ${Tudat_BUILD_INCLUDE_DIRS}) -endif () - -# Python and Pybind11 -# Find Python and pybind11. -if (NOT pybind11_FOUND) - set(PYBIND11_FINDPYTHON ON) - find_package(pybind11 CONFIG REQUIRED) -else() - set(pybind11_INCLUDE_DIRS ${pybind11_BUILD_INCLUDE_DIRS}) -endif() - -################################################ - -# Misc -set(POSITION_INDEPENDENT_CODE True) -enable_testing() - -# # Get relative path to Python installation prefix -# string(REPLACE "/include" "" BASE_DIR ${pybind11_INCLUDE_DIR}) -# file(RELATIVE_PATH PYTHON_INSTALL_PREFIX ${BASE_DIR} ${Python_SITELIB}) - -# Define tudatpy's source directory -set(TUDATPY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/tudatpy) - -# Create an alias for all the extension modules -add_custom_target(kernel) - -# Docs -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/docs DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) - - -# Tudatpy subdirectory -include_directories(include) -add_subdirectory(src/tudatpy) diff --git a/expose_kernel_module.py b/expose_kernel_module.py index 5608417e..e6b326a2 100644 --- a/expose_kernel_module.py +++ b/expose_kernel_module.py @@ -1,4 +1,4 @@ -''' +""" Copyright (c) 2010-2023, Delft University of Technology All rigths reserved @@ -7,7 +7,7 @@ under the terms of the Modified BSD license. You should have received a copy of the license with this file. If not, please or visit: http://tudat.tudelft.nl/LICENSE. -''' +""" # General imports import os @@ -16,9 +16,12 @@ import argparse from pathlib import Path -#-------------------------------------------------------------------- -#%% FUNCTION TO OBTAIN LIST CONTAINING ALL KERNEL MODULES AND SUBMODULES -#-------------------------------------------------------------------- +raise DeprecationWarning("This script is deprecated!") + +# -------------------------------------------------------------------- +# %% FUNCTION TO OBTAIN LIST CONTAINING ALL KERNEL MODULES AND SUBMODULES +# -------------------------------------------------------------------- + def recursively_find_children(module): """ @@ -28,26 +31,33 @@ def recursively_find_children(module): children = inspect.getmembers(module, inspect.ismodule) if children: - for (name, child) in children: + for name, child in children: children += recursively_find_children(child) return children else: return [] -#-------------------------------------------------------------------- -#%% FUNCTION TO EXPLICITLY IMPORT ALL KERNEL MODULE MEMBERS FOR AUTOCOMPLETION -#-------------------------------------------------------------------- + +# -------------------------------------------------------------------- +# %% FUNCTION TO EXPLICITLY IMPORT ALL KERNEL MODULE MEMBERS FOR AUTOCOMPLETION +# -------------------------------------------------------------------- module_methods = lambda module: inspect.getmembers(module, inspect.isroutine) module_objects = lambda module: [ - (name, value) for name, value in inspect.getmembers(module) - if (not inspect.isroutine(value) and not inspect.ismodule(value) and not name.startswith('__')) + (name, value) + for name, value in inspect.getmembers(module) + if ( + not inspect.isroutine(value) + and not inspect.ismodule(value) + and not name.startswith("__") + ) ] + def create_import_statement_to_import_all_module_members(module): - module_path = module.__name__ + module_path = module.__name__ import_block_title = lambda title: f"# {'-'*40}\n# {title:^40}\n# {'-'*40}" @@ -56,174 +66,207 @@ def create_import_statement_to_import_all_module_members(module): # Import methods if module_methods(module): import_statement += [ - import_block_title('METHODS'), - f'from {module_path} import \\', - ] + [ - f' {name}' + (", \\" if i != len(module_methods(module)) - 1 else "") for i, (name, _) in enumerate(module_methods(module)) - ] + import_block_title("METHODS"), + f"from {module_path} import \\", + ] + [ + f" {name}" + (", \\" if i != len(module_methods(module)) - 1 else "") + for i, (name, _) in enumerate(module_methods(module)) + ] # Import objects if module_objects(module): import_statement += [ - import_block_title('OBJECTS'), - f'from {module_path} import \\' - ] + [ - f' {name}' + (", \\" if i != len(module_objects(module)) - 1 else "") for i, (name, _) in enumerate(module_objects(module)) - ] + import_block_title("OBJECTS"), + f"from {module_path} import \\", + ] + [ + f" {name}" + (", \\" if i != len(module_objects(module)) - 1 else "") + for i, (name, _) in enumerate(module_objects(module)) + ] # Join import statement if import_statement: - import_statement = '\n'.join(import_statement) + import_statement = "\n".join(import_statement) return import_statement def create_file_to_import_all_module_members(module): - module_path = module.__name__ - module_name = module_path[len('tudatpy.kernel.'):] - module_name = module_path[len('tudatpy.kernel.'):] + module_path = module.__name__ + module_name = module_path[len("tudatpy.kernel.") :] + module_name = module_path[len("tudatpy.kernel.") :] # Automatic creation warning - warning = \ -f"""# ==================================================================== + warning = f"""# ==================================================================== # WARNING: DO NOT MANUALLY CHANGE THIS FILE! # ==================================================================== -# +# # This file is automatically generated before every `tudatpy` release. -# The purpose of this file is manually import all members of -# +# The purpose of this file is manually import all members of +# # tudatpy.{module_name} -# +# # to make autocompletion suggestions of C++ tudatpy modules possible. """ # Hybrid module path hybrid_module_path = Path(f"tudatpy/{module_name.replace('.', '/')}") hybrid_module_path.mkdir(parents=True, exist_ok=True) - kernel_member_import_file_path = hybrid_module_path / '_import_all_kernel_members.py' + kernel_member_import_file_path = ( + hybrid_module_path / "_import_all_kernel_members.py" + ) # Create import statement import_statement = create_import_statement_to_import_all_module_members(module) # Write warning and import statement to `_import_all_kernel_members.py` if import_statement: - with open(kernel_member_import_file_path, 'w') as f: - f.write(f'{warning}\n{import_statement}') + with open(kernel_member_import_file_path, "w") as f: + f.write(f"{warning}\n{import_statement}") + -#-------------------------------------------------------------------- -#%% FUNCTION TO SET UP THE __init__.py FILE OF ALL HYBRID MODULES -#-------------------------------------------------------------------- +# -------------------------------------------------------------------- +# %% FUNCTION TO SET UP THE __init__.py FILE OF ALL HYBRID MODULES +# -------------------------------------------------------------------- -explanation_of_module_exposure_process = lambda module_name: \ -f"""# This file, by virtue of the import statement below, merges +explanation_of_module_exposure_process = ( + lambda module_name: f"""# This file, by virtue of the import statement below, merges # the Tudat kernel module `tudatpy.kernel.{module_name}` with # its Python extensions defined in `tudatpy/{module_name.replace('.', '/')}`. -# -# This allows the import of all the C++ and Python submodules of the +# +# This allows the import of all the C++ and Python submodules of the # `{module_name}` kernel module directly from tudatpy: -# +# # from tudatpy.{module_name} import -# +# # Without the statement below, importing the `{module_name}` kernel module # would only be possible as follows, and hybrid Python/C++ modules would not # be posible in tudatpy. -# +# # from tudatpy.kernel.{module_name} import -# -# The reason why C++ kernel modules can only be imported as written above +# +# The reason why C++ kernel modules can only be imported as written above # is an issue with the `def_submodule` function of pybind11. The issue is discussed -# [here](https://github.com/pybind/pybind11/issues/2639). -# -# We circumvent the issue by, for each module and submodule, -# -# 1. Creating a Python module (an empty directory with an `__init__.py` file) +# [here](https://github.com/pybind/pybind11/issues/2639). +# +# We circumvent the issue by, for each module and submodule, +# +# 1. Creating a Python module (an empty directory with an `__init__.py` file) # inside `tudatpy` with the same name -# 2. Adding the import statement below to the Python module's `__init__.py` +# 2. Adding the import statement below to the Python module's `__init__.py` # (this file), thereby making the kernel module or submodule from the Python module. -# +# # This workaround was proposed in [this comment](https://github.com/pybind/pybind11/issues/2639#issuecomment-721238757). -# -# An added benefit of this method is that it makes it possible to write Python extensions -# and add them to the kernel modules simply by placing them inside the newly created Python -# module (at the same level as this file), which is not possible with the `def_submodule` +# +# An added benefit of this method is that it makes it possible to write Python extensions +# and add them to the kernel modules simply by placing them inside the newly created Python +# module (at the same level as this file), which is not possible with the `def_submodule` # function of pybind11. -# An added benefit of this method is that it makes it possible to write Python extensions +# An added benefit of this method is that it makes it possible to write Python extensions # and add them to the kernel modules simply by placing them inside this module! """ +) + def set_up__init__(module): """ Expose all Tudat kernel modules as hybrid C++/Python tudatpy modules. """ - module_path = module.__name__ - module_name = module_path[len('tudatpy.kernel.'):] - module_depth = max(len(module_name.split('.')) - 3, 0) + module_path = module.__name__ + module_name = module_path[len("tudatpy.kernel.") :] + module_depth = max(len(module_name.split(".")) - 3, 0) # Hybrid module path hybrid_module_path = Path(f"tudatpy/{module_name.replace('.', '/')}") hybrid_module_path.mkdir(parents=True, exist_ok=True) # __init__.py - import_statement = '\n'.join([ - # Kernel module import statement - f"from {module_path} import *", - ] + ([ - # If there's any module members to import, they will be manually imported in - # `/_import_all_kernel_members.py`. If that is the case, - # we import everything in `_import_all_kernel_members.py`. - # This enables autocomplete suggestions for all members of all kernel modules. - f"from tudatpy.{module_name + '.' if module_name else ''}_import_all_kernel_members import *" - ] if create_import_statement_to_import_all_module_members(module) else []) - ) - disclaimer_text = explanation_of_module_exposure_process(module_name) - init_file_path = hybrid_module_path / '__init__.py' + import_statement = "\n".join( + [ + # Kernel module import statement + f"from {module_path} import *", + ] + + ( + [ + # If there's any module members to import, they will be manually imported in + # `/_import_all_kernel_members.py`. If that is the case, + # we import everything in `_import_all_kernel_members.py`. + # This enables autocomplete suggestions for all members of all kernel modules. + f"from tudatpy.{module_name + '.' if module_name else ''}_import_all_kernel_members import *" + ] + if create_import_statement_to_import_all_module_members(module) + else [] + ) + ) + disclaimer_text = explanation_of_module_exposure_process(module_name) + init_file_path = hybrid_module_path / "__init__.py" if not os.path.isfile(init_file_path): # If __init__.py does not exist, create it directly - with open(init_file_path, 'w') as f: + with open(init_file_path, "w") as f: f.write(f"{disclaimer_text}\n{import_statement}") else: # Otherwise, if the import statement is not already present in __init__.py, # append the explanation of the module exposure process and import statement to __init__.py - with open(init_file_path, 'r') as f: + with open(init_file_path, "r") as f: contents = f.read() if re.search(re.escape(import_statement), contents): # import_statement is already present in __init__.py pass else: - with open(init_file_path, 'a') as f: + with open(init_file_path, "a") as f: f.write(f"\n\n{disclaimer_text}\n{import_statement}") -#-------------------------------------------------------------------- -#%% USER INPUT -#-------------------------------------------------------------------- - -parser = argparse.ArgumentParser(description='Expose hybrid kernel modules.') -parser.add_argument('modules', metavar='module', type=str, nargs='+', - help='a list of hybrid kernel modules to expose') -parser.add_argument('--build-dir', metavar='build_dir', type=str, - help='the name tudatpy build directory') -parser.add_argument('-i', '--init', action=argparse.BooleanOptionalAction, - help='whether to generate the __init__.py files of all kernel modules') -parser.add_argument('-v', '--verbose', action=argparse.BooleanOptionalAction, - help='whether to announce the module and submodule being exposed') +# -------------------------------------------------------------------- +# %% USER INPUT +# -------------------------------------------------------------------- + +parser = argparse.ArgumentParser(description="Expose hybrid kernel modules.") +parser.add_argument( + "modules", + metavar="module", + type=str, + nargs="+", + help="a list of hybrid kernel modules to expose", +) +parser.add_argument( + "--build-dir", + metavar="build_dir", + type=str, + help="the name tudatpy build directory", +) +parser.add_argument( + "-i", + "--init", + action=argparse.BooleanOptionalAction, + help="whether to generate the __init__.py files of all kernel modules", +) +parser.add_argument( + "-v", + "--verbose", + action=argparse.BooleanOptionalAction, + help="whether to announce the module and submodule being exposed", +) args = parser.parse_args() -#-------------------------------------------------------------------- -#%% IMPORT COMPILED TUDATPY -#-------------------------------------------------------------------- +# -------------------------------------------------------------------- +# %% IMPORT COMPILED TUDATPY +# -------------------------------------------------------------------- # Use custom compiled Tudat version import sys -sys.path.insert(0, f'/mnt/e/studio/professional/work/2023-2024 Tudat/repos/tudat-bundle/{args.build_dir}/tudatpy/') + +sys.path.insert( + 0, + f"/mnt/e/studio/professional/work/2023-2024 Tudat/repos/tudat-bundle/{args.build_dir}/tudatpy/", +) # Import Tudat kernel import tudatpy.kernel as kernel -#-------------------------------------------------------------------- -#%% KERNEL MODULE EXPOSURE -#-------------------------------------------------------------------- +# -------------------------------------------------------------------- +# %% KERNEL MODULE EXPOSURE +# -------------------------------------------------------------------- for module_name in args.modules: @@ -232,11 +275,11 @@ def set_up__init__(module): # Set up __init__.py files for the kernel and its submodules if args.init: set_up__init__(module) - for (submodule_name, submodule) in recursively_find_children(module): + for submodule_name, submodule in recursively_find_children(module): set_up__init__(submodule) # Update autocompletion files for the kernel and its submodules create_file_to_import_all_module_members(module) - for (submodule_name, submodule) in recursively_find_children(module): + for submodule_name, submodule in recursively_find_children(module): # Update autocompletion files - create_file_to_import_all_module_members(submodule) \ No newline at end of file + create_file_to_import_all_module_members(submodule) diff --git a/stubs.py b/stubs.py index 24db7c59..9f1e7a05 100644 --- a/stubs.py +++ b/stubs.py @@ -4,6 +4,8 @@ import subprocess import argparse +raise NotImplementedError("This script is not yet ready for use") + # Globals TUDATPY_ROOT = Path(__file__).parent / "src/tudatpy" STUBS_ROOT = Path(__file__).parent / "src/tudatpy-stubs"