Skip to content
Snippets Groups Projects
Commit 3f81849b authored by Clément Jonglez's avatar Clément Jonglez
Browse files

big README.md overhaul, merge with pypi-README.md

parent 1d3bdc2d
Branches
Tags
1 merge request!9Minor improvements for release process
Pipeline #5652 passed
# orekit_jpype
An alternative implementation of orekit python wrapper based on jpype. The interface is largely similar to the original orekit version.
This is Work In Progress.
[![PyPI - Version](https://img.shields.io/pypi/v/orekit-jpype.svg)](https://pypi.org/project/orekit-jpype)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/orekit-jpype.svg)](https://pypi.org/project/orekit-jpype)
[![Pipeline passing](https://gitlab.orekit.org/Petrush/orekit_jpype/badges/master/pipeline.svg?ignore_skipped=true)](https://gitlab.orekit.org/Petrush/orekit_jpype/-/pipelines)
[![coverage](https://gitlab.orekit.org/Petrush/orekit_jpype/badges/main/coverage.svg)](https://gitlab.orekit.org/Petrush/orekit_jpype/-/graphs/master/charts)
The main orekit python wrapper is located at:
An alternative implementation of orekit python wrapper based on Jpype and stubs generated by stubgenj. The interface is largely similar to the original JCC wrapped orekit version which is a more capable wrapper as it can subclass java classes, which Jpype cannot. The Jpype version is however easy to install, use and for most purposes sufficient.
Orekit (https://www.orekit.org/) is a low level library for space flight dynamics and is written in Java. The java API is located at: https://www.orekit.org/site-orekit-12.0.2/apidocs/index.html
The original Orekit python wrapper based on JCC is located at:
https://gitlab.orekit.org/orekit-labs/python-wrapper/-/wikis/home
Please see the repository example notebooks and test cases for usage, as well as jpype documentation https://jpype.readthedocs.io/en/latest/index.html
Please see the [repository](https://gitlab.orekit.org/Petrush/orekit_jpype) example notebooks and test cases for usage, as well as jpype documentation https://jpype.readthedocs.io/en/latest/index.html
## Notes
The biggest difference between JCC and Jpype is that JCC is a static wrapping, creating c++ classes that are pre-defined when building the package, while JPype is dynamic and investigating the java machine on-the-fly.
# Installation
Each model has advantages and disadvantages.
* Requirements:
* JDK installed on your system (as Orekit is based on Java)
* Or alternatively [jdk4py](https://pypi.org/project/jdk4py/) can be used to provide JDK using pip, see usage instructions below
* Python >= 3.7 . Orekit Jpype is only tested for Python versions >= 3.9 because the CI pipeline depends on `jdk4py`, but Python 3.7 and 3.8 should work.
* `pip`
* Recommended: a `venv`
To install from PyPi:
```bash
pip install orekit-jpype
```
### JCC Pro's
- Can (probably) implement anything that is doable in Java in Python using the special classes (subclassing, interfaces)
- Stable when a compiled version has been created
- Well tested with orekit
- Good support for JCC but mainly one person who maintains and understand the code.
- Easier to add custom java code to the system
To install from source:
```bash
git clone https://gitlab.orekit.org/Petrush/orekit_jpype.git
pip install . -vv
```
Or alternatively:
```bash
pip install git+https://gitlab.orekit.org/Petrush/orekit_jpype.git
```
### JCC Con's
- Special classes for subclassing.
- Special classes for interfaces
- Casting of types for classes with multiple inheritance
- Can be tricky to get it to compile (but when it does it is stable)
- Poor docstring support
- Very hard to understand the inner working of the wrapping code
- Need to recompile to add user java code pieces
To install the required orekit data from pip:
```bash
pip install git+https://gitlab.orekit.org/orekit/orekit-data.git
```
### JPype Pro's
- Support for docstrings, reasonable rendering of javadoc
- Automatic adaptors enabling things like automatic translation between python datetime and AbsoluteDate.
- Well documented
- Medium hard to understand the wrapping code
- The wrapping is separate from the orekit part, maybe less issues with compiling (using conda)
- Easy to add user java code pieces as separate jars
- Direct mapping of numpy arrays to java arrays
### JPype Cons
- No subclassing of Java classes (Abstract classes in orekit cannot be used)
- Issues with restarting the JVM
- The unknown issues we don't know.
- Seems to have a slight performance hit (~10% increase in time in some very basic tests)
# usage
# Installation
See the example notebooks (`examples` folder) and the package `test` folder (only available in the source distribution or in the [git repo](https://gitlab.orekit.org/Petrush/orekit_jpype)) for examples.
if using mamba/conda:
## Usage difference from JCC based wrapper
mamba install -c conda-forge jpype1
### Casting
In the JCC version there is sometimes needed a .cast_() method to cast the object to the correct type. This is not needed in the JPype version.
### Implementation of Orekit interfaces
In the JCC version, the interfaces are implemented as special classes named PythonClassName that is then subclassed in Python. In the JPype version, the interfaces are implemented as python classes and marked with decorators, @JImplements and @JOverride, see https://jpype.readthedocs.io/en/latest/userguide.html#proxy-method-overloading
### Subclassing of Orekit abstract classes
In the JCC version of Orekit it is possible to subclass classes from the set of PythonClassName classes. This is not possible in the Jpype version of Orekit, which is limited to implementation of interfaces only. But instead it is possible to subclass abstract classes in Java, compile the JAR, and add the JAR to Orekit JPype, see section below.
git clone https://gitlab.orekit.org/Petrush/orekit_jpype.git
pip install . -vv
### Using custom JARs
The pip will also install the orekitdata package from the orekitdata git respotory.
You can add your own JARs to Orekit Jpype. For that, you can pass a list of classpaths via the argument `additional_classpaths` to the method `orekit_jpype.initVM`. An example can be found in the test case `tests-jvm/orekit_jpype_test_init_vm_with_extra_jars.py`.
### Java imports require the JVM to be started
# Development
As jpype loads the Java classes from JAR files on-the-fly, it cannot know which Java packages/classes exist before the JVM is started. Therefore the Java packages/classes can only be imported after the JVM is started.
To generate stub files, use the stubgenj package
https://gitlab.cern.ch/scripting-tools/stubgenj
Hence, the following will not work:
and command line:
python -m stubgenj --convert-strings --classpath "orekit_jpype/jars/*.jar" org.orekit org.hipparchus java
```python
from java.util import ArrayList
from org.orekit.data import DirectoryCrawler, DataContext
import orekit_jpype as orekit
To build the wheel:
if __name__ == '__main__':
orekit.initVM()
```
python -m build
Instead you should do the following:
To upload to pypi:
```python
import orekit_jpype as orekit
orekit.initVM()
python3 -m twine upload --repository testpypi dist/*
from java.util import ArrayList
from org.orekit.data import DirectoryCrawler, DataContext
To install (something like):
if __name__ == '__main__':
# do stuff
```
pip install -i https://test.pypi.org/simple/ orekit-jpype==12.0.2.dev2
The imports after the `orekit.initVM()` call will probably trigger PEP8 E402 warnings from `flake8` or `pylint`. As a workaround, you can add the following comment after the import to ignore these warnings:
# usage
See the example notebooks and the package test folder for examples.
```python
from java.util import ArrayList # noqa: E402
```
### The JVM cannot be restarted
## Usage difference from JCC based wrapper
If you call the `jpype.shutdownJVM()` method, you won't be able to restart the JVM afterwards by calling `jpype.startJVM()` or `orekit_jpype.initVM()`. This is a known limitation of the JNI used by `jpype`: https://github.com/jpype-project/jpype/issues/959
### Casting
In the JCC version there is sometimes needed a .cast_() method to cast the object to the correct type. This is not needed in the JPype version.
### No JDK is provided
### Implementation of Orekit interfaces
In the JCC version, the interfaces are implemented as special classes named PythonClassName that is then subclassed in Python. In the JPype version, the interfaces are implemented as python classes and marked with decorators, @JImplements and @JOverride, see https://jpype.readthedocs.io/en/latest/userguide.html#proxy-method-overloading
Installing Orekit JCC via conda also installed an OpenJDK8. Instead, when installing Orekit Jpype via pip, no JDK is installed, so it's up to the user to install JDK on their machine.
### Subclassing of Orekit abstract classes
In the JCC version of Orekit it is possible to subclass classes from the set of PythonClassName classes. This is not possible in the Jpype version of Orekit, which is limited to implementation of interfaces only.
Another solution could be installing a JDK with pip thanks to the [jdk4py project](https://pypi.org/project/jdk4py/), and passing the path to the libjvm file to jpype by using the following syntax (taken from the test case `tests-jvm/orekit_jpype_test_init_vm_jdk4py.py`):
```python
import orekit_jpype as orekit
import os
import jdk4py
libjvm_path = os.path.join(jdk4py.JAVA_HOME, "lib", "server", "libjvm.so")
orekit.initVM(jvmpath=libjvm_path)
```
Alternatively, you can just set the `JAVA_HOME` environment variable from `jdk4py`:
```python
import orekit_jpype as orekit
import os
import jdk4py
os.environ["JAVA_HOME"] = str(jdk4py.JAVA_HOME)
orekit.initVM()
```
However, using `jpype` together with `jdk4py` seems to cause trouble in Windows: https://github.com/jpype-project/jpype/issues/1151
# Packaging a project with `pyinstaller`
......@@ -138,3 +175,123 @@ python -m PyInstaller.utils.run_tests --include_only orekit_jpype._pyinstaller
This will package a minimal executable containing orekit_jpype, orekitdata and run the test case `test/OrekitDataLoadOnlyLibTest.py` to test that everything works as expected.
TODO: include this test procedure in a CI pipeline.
# Notes on differences between the original JCC-based Orekit Python wrapper and this jpype-based wrapper
The biggest difference between JCC and Jpype is that JCC is a static wrapping, creating c++ classes that are pre-defined when building the package, while JPype is dynamic and investigating the java machine on-the-fly.
Each model has advantages and disadvantages.
### JCC Pro's
- Can (probably) implement anything that is doable in Java in Python using the special classes (subclassing, interfaces)
- Stable when a compiled version has been created
- Well tested with orekit
- Good support for JCC but mainly one person who maintains and understand the code.
- Easier to add custom java code to the system
### JCC Con's
- Special classes for subclassing.
- Special classes for interfaces
- Casting of types for classes with multiple inheritance
- Can be tricky to get it to compile (but when it does it is stable)
- Poor docstring support
- Very hard to understand the inner working of the wrapping code
- Need to recompile to add user java code pieces
### JPype Pro's
- Support for docstrings, reasonable rendering of javadoc
- Automatic adaptors enabling things like automatic translation between python datetime and AbsoluteDate.
- Well documented
- Medium hard to understand the wrapping code
- The wrapping is separate from the orekit part, maybe less issues with compiling (using conda)
- Easy to add user java code pieces as separate jars
- Direct mapping of numpy arrays to java arrays
### JPype Cons
- No subclassing of Java classes (Abstract classes in orekit cannot be used)
- Issues with restarting the JVM
- The unknown issues we don't know.
- Seems to have a slight performance hit (~10% increase in time in some very basic tests)
# Development
## Creating a venv
Using a Python virtual environment is highly recommended, do not install packages in your global python environment. To do so (in this example the venv will be located in the root of this git folder, but no worries, it is git-ignored):
```bash
python3 -m pip install virtualenv
python3 -m venv .orekitvenv
```
Activate the venv using:
```bash
source .orekitvenv/bin/activate
```
## Downloading JAR files and generating Python stubs
When a new version of one of the Java dependencies is available, the new JAR files must be downloaded and the stubs re-generated:
Downloading JARs requires having `maven` installed on your system.
And to generate stub files, the `stubgenj` package is required, it should be installed via pip together with the other dependencies of `orekit_jpype` (https://gitlab.cern.ch/scripting-tools/stubgenj)
* change the version of the corresponding artifact in `pom.xml`
* The following Python script will download new JARs and re-generate the stubs:
```bash
python3 dl_jars_and_render_stubs.py
```
## Checklist before uploading a new package version
* Open a merge request from your private branch into the `master` branch, containing:
* your changes, for instance newer versions of the Orekit JARs, changes to stubs, changes to test suites, etc.
* bump the package version in `pyproject.toml`.
* The package version should follow the Orekit versions: for example if based on Orekit `12.0.2`, the `orekit_jpype` package version should start with `12.0.2`, for instance `12.0.2.0`
* Follow the [Python version specifiers conventions](https://packaging.python.org/en/latest/specifications/version-specifiers/#version-specifiers)
* The merge request should be merged only if the CI pipeline passes. In particular, major releases of Orekit introduce breaking changes so it's likely that unit tests will fail and need to be modified
* After your branch is merged into the `master` branch, switch to the `master` branch and create a tag with the same name as the package version, for example `12.0.2.0`
* Stay in the `master` branch in the same tagged commit, and follow the instructions below to build and upload the wheel to PyPi
## Building wheel
* Make sure you have the latest version of PyPA’s [build](https://packaging.python.org/en/latest/key_projects/#build) installed:
```bash
python3 -m pip install --upgrade build
```
* To build the wheel:
```bash
python3 -m build
```
## Uploading wheel
Make sure you have the latest version of `twine`:
```bash
python3 -m pip install --upgrade twine
```
### Uploading wheel to test PyPi server
* To upload to the PyPi test server:
```bash
python3 -m twine upload --repository testpypi dist/*
```
* To try to install the newly uploaded wheel from the PyPi test server (in this example for version `12.0.2.0`):
```bash
python3 -m pip install -i https://test.pypi.org/simple/ orekit-jpype==12.0.2.0
```
### Uploading wheel to the real PyPi server
* To upload the wheel to PyPi:
```bash
python3 -m twine upload dist/*
```
* To install `orekit_jpype` from PyPi:
```bash
python3 -m pip install --upgrade orekit-jpype
```
# orekit_jpype
An alternative implementation of orekit python wrapper based on Jpype and stubs generated by stubgenj. The interface is largely similar to the original JCC wrapped orekit version which is a more capable wrapper as it can subclass java classes, which Jpype cannot. The Jpype version is however easy to install, use and for most purposes sufficient.
Orekit (https://www.orekit.org/) is a low level library for space flight dynamics and is written in Java. The java API is located at: https://www.orekit.org/site-orekit-12.0.2/apidocs/index.html
# Installation
pip install orekit_jpype
The library also needs a dataset of varioud parameters, which can be installed with:
pip install git+https://gitlab.orekit.org/orekit/orekit-data.git
# usage
See the example notebooks and the package test folder for examples.
......@@ -9,7 +9,7 @@ allow-direct-references = true
name = "orekit_jpype"
version = "12.0.2.0"
description = "A space dynamics library. This package is a jpype wrapping of the original orekit java code."
readme = "pypi-README.md"
readme = "README.md"
authors = [{name = "Petrus Hyvönen", email = "petrus.hyvonen@gmail.com"}]
license = {text = "License :: OSI Approved :: Apache Software License"}
requires-python = ">=3.7"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment