Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 51 additions & 43 deletions extension/wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ typedef struct {
elsetrec satrec[0];
} SatrecArrayObject;

static PyObject* SatrecType = NULL;
static PyObject* SatrecArrayType = NULL;

/* Support routine that is used to support NumPy array broadcasting for
both individual satellite objects and also arrays. */

Expand Down Expand Up @@ -121,7 +124,8 @@ Satrec_twoline2rv(PyTypeObject *cls, PyObject *args)
line2[68] = '\0';

/* Allocate the new object. */
SatrecObject *self = (SatrecObject*) cls->tp_alloc(cls, 0);
allocfunc alloc_func = (allocfunc)PyType_GetSlot(cls, Py_tp_alloc);
SatrecObject *self = (SatrecObject*)alloc_func(cls, 0);
if (!self)
return NULL;

Expand Down Expand Up @@ -424,7 +428,7 @@ get_intldesg(SatrecObject *self, void *closure)
static int
set_intldesg(SatrecObject *self, PyObject *value, void *closure)
{
const char *s = PyUnicode_AsUTF8(value);
const char *s = PyUnicode_AsUTF8AndSize(value, NULL);
if (!s)
return -1;
strncpy(self->satrec.intldesg, s, 10);
Expand Down Expand Up @@ -460,7 +464,7 @@ get_satnum_str(SatrecObject *self, void *closure)
static int
set_satnum_str(SatrecObject *self, PyObject *value, void *closure)
{
const char *s = PyUnicode_AsUTF8(value);
const char *s = PyUnicode_AsUTF8AndSize(value, NULL);
if (!s)
return -1;
strncpy(self->satrec.satnum, s, 5);
Expand All @@ -483,22 +487,13 @@ static PyGetSetDef Satrec_getset[] = {
{NULL},
};

static PyTypeObject SatrecType = {
PyVarObject_HEAD_INIT(NULL, 0)
/* See the module initialization function at the bottom of this file. */
};

/* Details of the SatrecArray. */

static Py_ssize_t
Satrec_len(PyObject *self) {
return ((SatrecArrayObject*)self)->ob_base.ob_size;
}

static PySequenceMethods SatrecArray_as_sequence = {
Satrec_len
};

static PyObject *
SatrecArray_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
Expand All @@ -510,7 +505,9 @@ SatrecArray_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (length == -1)
return NULL;

return type->tp_alloc(type, length);
allocfunc alloc_func = (allocfunc)PyType_GetSlot(type, Py_tp_alloc);
PyObject *ret = alloc_func(type, length);
return ret;
}


Expand All @@ -529,7 +526,7 @@ SatrecArray_init(SatrecArrayObject *self, PyObject *args, PyObject *kwds)
PyObject *item = PySequence_GetItem(sequence, i);
if (!item)
return -1;
if (!PyObject_IsInstance(item, (PyObject*) &SatrecType)) {
if (!PyObject_IsInstance(item, (PyObject*) SatrecType)) {
PyErr_Format(PyExc_ValueError, "every item must be a Satrec,"
" but element %d is: %R", i, item);
Py_DECREF(item);
Expand Down Expand Up @@ -557,9 +554,40 @@ static PyMethodDef SatrecArray_methods[] = {
{NULL, NULL}
};

static PyTypeObject SatrecArrayType = {
PyVarObject_HEAD_INIT(NULL, sizeof(elsetrec))
/* See the module initialization function at the bottom of this file. */
static char doc_SatRecType[23] = "SGP4 satellite record.";
static PyType_Slot SatrecType_slots[] = {
{Py_tp_doc, doc_SatRecType},
{Py_tp_methods, Satrec_methods},
{Py_tp_members, Satrec_members},
{Py_tp_getset, Satrec_getset},
{Py_tp_new, (void *)PyType_GenericNew},
{0, NULL},
};

static PyType_Spec SatrecType_spec = {
.name = "sgp4.vallado_cpp.Satrec",
.basicsize = sizeof(SatrecObject),
.itemsize = 0,
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_IMMUTABLETYPE,
.slots = SatrecType_slots,
};

static char doc_SatRecArrayType[26] = "SGP4 array of satellites.";
static PyType_Slot SatrecArrayType_slots[] = {
{Py_tp_doc, doc_SatRecArrayType},
{Py_tp_methods, SatrecArray_methods},
{Py_tp_init, (void *)SatrecArray_init},
{Py_tp_new, (void *)SatrecArray_new},
{Py_sq_length, (void *)Satrec_len},
{0, NULL},
};

static PyType_Spec SatrecArrayType_spec = {
.name = "sgp4.vallado_cpp.SatrecArray",
.basicsize = sizeof(SatrecArrayObject),
.itemsize = sizeof(elsetrec),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_IMMUTABLETYPE,
.slots = SatrecArrayType_slots,
};

/* The module that ties it all together. */
Expand All @@ -575,45 +603,25 @@ static PyModuleDef module = {
PyMODINIT_FUNC
PyInit_vallado_cpp(void)
{
SatrecType.tp_name = "sgp4.vallado_cpp.Satrec";
SatrecType.tp_basicsize = sizeof(SatrecObject);
SatrecArrayType.tp_itemsize = 0;
SatrecType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
SatrecType.tp_doc = "SGP4 satellite record.";
SatrecType.tp_methods = Satrec_methods;
SatrecType.tp_members = Satrec_members;
SatrecType.tp_getset = Satrec_getset;
SatrecType.tp_new = PyType_GenericNew;

if (PyType_Ready(&SatrecType) < 0)
SatrecType = PyType_FromSpec(&SatrecType_spec);
if (SatrecType == NULL)
return NULL;

SatrecArrayType.tp_name = "sgp4.vallado_cpp.SatrecArray";
SatrecArrayType.tp_basicsize = sizeof(SatrecArrayObject);
SatrecArrayType.tp_itemsize = sizeof(elsetrec);
SatrecArrayType.tp_as_sequence = &SatrecArray_as_sequence;
SatrecArrayType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
SatrecArrayType.tp_doc = "SGP4 array of satellites.";
SatrecArrayType.tp_methods = SatrecArray_methods;
SatrecArrayType.tp_init = (initproc) SatrecArray_init;
SatrecArrayType.tp_new = SatrecArray_new;

if (PyType_Ready(&SatrecArrayType) < 0)
SatrecArrayType = PyType_FromSpec(&SatrecArrayType_spec);
if (SatrecArrayType == NULL)
return NULL;

PyObject *m = PyModule_Create(&module);
if (m == NULL)
return NULL;

Py_INCREF(&SatrecType);
if (PyModule_AddObject(m, "Satrec", (PyObject *) &SatrecType) < 0) {
if (PyModule_AddObject(m, "Satrec", SatrecType) < 0) {
Py_DECREF(&SatrecType);
Py_DECREF(m);
return NULL;
}

Py_INCREF(&SatrecArrayType);
if (PyModule_AddObject(m, "SatrecArray", (PyObject *) &SatrecArrayType) < 0) {
if (PyModule_AddObject(m, "SatrecArray", SatrecArrayType) < 0) {
Py_DECREF(&SatrecArrayType);
Py_DECREF(&SatrecType);
Py_DECREF(m);
Expand Down
26 changes: 25 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,26 @@

import os
import sys
import sysconfig
from distutils.ccompiler import get_default_compiler
from distutils.core import setup, Extension

PYTHON_SGP4_COMPILE = os.environ.get('PYTHON_SGP4_COMPILE', '')

USE_PY_LIMITED_API = (
# Py_buffer is required
sys.version_info >= (3, 11)
# LIMITED_API is not compatible with free-threading (as of CPython 3.14)
and not sysconfig.get_config_var("Py_GIL_DISABLED")
)
ABI3_TARGET_VERSION = "".join(str(_) for _ in sys.version_info[:2])
ABI3_TARGET_HEX = hex(sys.hexversion & 0xFFFF00F0)

ext_modules = []
define_macros = []

if USE_PY_LIMITED_API:
define_macros.append(("Py_LIMITED_API", ABI3_TARGET_HEX))

if sys.version_info[0] == 3 and PYTHON_SGP4_COMPILE != 'never':

Expand All @@ -33,13 +49,18 @@
'extension/SGP4.cpp',
'extension/wrapper.cpp',
],
define_macros=define_macros,
py_limited_api=USE_PY_LIMITED_API,

# TODO: can we safely figure out how to use a pair of options
# like these, adapted to as many platforms as possible, to use
# multiple processors when available?
# extra_compile_args=['-fopenmp'],
# extra_link_args=['-fopenmp'],
extra_compile_args=['-ffloat-store'],
extra_compile_args=[
'-ffloat-store',
"-std=c++20" if get_default_compiler() != "msvc" else "/std:c++20",
],
))

# Read the package's docstring and "__version__" without importing it.
Expand Down Expand Up @@ -89,4 +110,7 @@
package_data = {'sgp4': ['SGP4-VER.TLE', 'sample*', 'tcppver.out']},
provides = ['sgp4'],
ext_modules = ext_modules,
options={
"bdist_wheel": {"py_limited_api": "cp%s" % ABI3_TARGET_VERSION}
} if USE_PY_LIMITED_API else {},
)
Loading