1
1
// this is included first so that we do include without NO_IMPORT_ARRAY defined, which is done in NumpyConversions.h
2
2
#include < numpy/ndarrayobject.h>
3
+ #include < numpy/npy_2_compat.h>
3
4
4
5
5
6
#include < csp/core/Time.h>
8
9
#include < locale>
9
10
#include < codecvt>
10
11
12
+ static int _npy_inited = PyArray_ImportNumPyAPI();
13
+
11
14
namespace csp ::python
12
15
{
13
16
14
- static bool numpy_initialized = false ;
15
-
16
17
PyObject * valuesAtIndexToNumpy ( ValueType valueType, const csp::TimeSeriesProvider * ts, int32_t startIndex, int32_t endIndex,
17
18
autogen::TimeIndexPolicy startPolicy, autogen::TimeIndexPolicy endPolicy,
18
19
DateTime startDt, DateTime endDt )
19
20
{
20
- if ( !numpy_initialized )
21
- {
22
- import_array ()
23
- numpy_initialized = true ;
24
- }
25
-
26
21
return switchCspType ( ts -> type (),
27
22
[ valueType, ts, startIndex, endIndex, startPolicy, endPolicy, startDt, endDt ]( auto tag )
28
23
{
@@ -35,40 +30,78 @@ int64_t scalingFromNumpyDtUnit( NPY_DATETIMEUNIT base )
35
30
{
36
31
switch ( base )
37
32
{
38
- case NPY_FR_ns:
39
- return 1 ;
40
- case NPY_FR_us:
41
- return csp::TimeDelta::fromMicroseconds (1 ).asNanoseconds ();
42
- case NPY_FR_ms:
43
- return csp::TimeDelta::fromMilliseconds (1 ).asNanoseconds ();
44
- case NPY_FR_s:
45
- return csp::TimeDelta::fromSeconds (1 ).asNanoseconds ();
46
- case NPY_FR_m:
47
- return csp::TimeDelta::fromMinutes (1 ).asNanoseconds ();
48
- case NPY_FR_h:
49
- return csp::TimeDelta::fromHours (1 ).asNanoseconds ();
50
- case NPY_FR_D:
51
- return csp::TimeDelta::fromDays (1 ).asNanoseconds ();
33
+ // https://github.com/numpy/numpy/blob/v2.0.0/numpy/__init__.pxd#L794
34
+ case NPY_FR_Y:
35
+ return csp::TimeDelta::fromDays (365 ).asNanoseconds ();
36
+ case NPY_FR_M:
37
+ return csp::TimeDelta::fromDays (30 ).asNanoseconds ();
52
38
case NPY_FR_W:
53
39
return csp::TimeDelta::fromDays (7 ).asNanoseconds ();
40
+ #ifdef NPY_FR_B
41
+ case NPY_FR_B:
42
+ return csp::TimeDelta::fromDays (5 ).asNanoseconds ();
43
+ #endif
44
+ case NPY_FR_D:
45
+ return csp::TimeDelta::fromDays (1 ).asNanoseconds ();
46
+ case NPY_FR_h:
47
+ return csp::TimeDelta::fromHours (1 ).asNanoseconds ();
48
+ case NPY_FR_m:
49
+ return csp::TimeDelta::fromMinutes (1 ).asNanoseconds ();
50
+ case NPY_FR_s:
51
+ return csp::TimeDelta::fromSeconds (1 ).asNanoseconds ();
52
+ case NPY_FR_ms:
53
+ return csp::TimeDelta::fromMilliseconds (1 ).asNanoseconds ();
54
+ case NPY_FR_us:
55
+ return csp::TimeDelta::fromMicroseconds (1 ).asNanoseconds ();
56
+ case NPY_FR_ns:
57
+ return 1 ;
58
+ // unsupported or invalid units
59
+ // enumerated here for clarity in error messages
60
+ case NPY_FR_ps:
61
+ CSP_THROW (csp::NotImplemented, " datetime resolution not supported or invalid - saw NPY_DATETIMEUNIT value NPY_FR_ps" );
62
+ return 0 ;
63
+ case NPY_FR_fs:
64
+ CSP_THROW (csp::NotImplemented, " datetime resolution not supported or invalid - saw NPY_DATETIMEUNIT value NPY_FR_fs" );
65
+ return 0 ;
66
+ case NPY_FR_GENERIC:
67
+ CSP_THROW (csp::NotImplemented, " datetime resolution not supported or invalid - saw NPY_DATETIMEUNIT value NPY_FR_generic" );
68
+ return 0 ;
69
+ case NPY_FR_ERROR:
70
+ CSP_THROW (csp::NotImplemented, " datetime resolution not supported or invalid - saw NPY_DATETIMEUNIT value NPY_FR_error" );
71
+ return 0 ;
54
72
default :
55
- CSP_THROW (csp::NotImplemented, " datetime resolution not supported or invalid - saw NPY_DATETIMEUNIT value " << base );
56
- return 0 ; // never reached, but keeps compiler happy
73
+ if (static_cast <int >(base) == 3 ) {
74
+ // NPY_FR_B was removed in numpy 1.20
75
+ return csp::TimeDelta::fromDays (5 ).asNanoseconds ();
76
+ }
77
+ CSP_THROW (csp::NotImplemented, " datetime resolution not supported or invalid - saw NPY_DATETIMEUNIT value " << static_cast <int32_t >(base) );
78
+ return 0 ;
57
79
}
58
80
}
59
81
60
82
NPY_DATETIMEUNIT datetimeUnitFromDescr ( PyArray_Descr* descr )
61
83
{
62
- PyArray_DatetimeDTypeMetaData* dtypeMeta = (PyArray_DatetimeDTypeMetaData*)(descr -> c_metadata);
63
- PyArray_DatetimeMetaData* dtMeta = &(dtypeMeta -> meta);
64
- return dtMeta -> base;
84
+ if (PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION)
85
+ {
86
+ // NumPy 2.x way
87
+ PyArray_DatetimeDTypeMetaData* dtypeMeta = ( PyArray_DatetimeDTypeMetaData * ) ( ( (_PyArray_LegacyDescr *) descr ) -> c_metadata );
88
+ PyArray_DatetimeMetaData* dtMeta = &( dtypeMeta -> meta );
89
+ return dtMeta -> base;
90
+ }
91
+ else
92
+ {
93
+ // NumPy 1.x way
94
+ PyArray_DatetimeDTypeMetaData* dtypeMeta = ( PyArray_DatetimeDTypeMetaData * ) ( ( (PyArray_DescrProto *) descr ) -> c_metadata );
95
+ PyArray_DatetimeMetaData* dtMeta = &( dtypeMeta -> meta );
96
+ return dtMeta -> base;
97
+ }
65
98
}
66
99
67
100
static std::wstring_convert<std::codecvt_utf8<char32_t >, char32_t > wstr_converter;
68
101
69
102
void stringFromNumpyStr ( void * data, std::string& out, char numpy_type, int elem_size_bytes )
70
103
{
71
- // strings from numpy arrays are fixed width and zero filled.
104
+ // strings from numpy arrays are fixed width and zero filled.
72
105
// if the last char is 0, can treat as null terminated, else use full width
73
106
74
107
if ( numpy_type == NPY_UNICODELTR)
@@ -87,7 +120,7 @@ void stringFromNumpyStr( void* data, std::string& out, char numpy_type, int elem
87
120
out = wstr_converter.to_bytes ( wstr );
88
121
}
89
122
}
90
- else if ( numpy_type == NPY_STRINGLTR || numpy_type == NPY_STRINGLTR2 )
123
+ else if ( numpy_type == NPY_STRINGLTR )
91
124
{
92
125
const char * const raw_value = (const char *) data;
93
126
@@ -120,11 +153,11 @@ void validateNumpyTypeVsCspType( const CspTypePtr & type, char numpy_type_char )
120
153
case NPY_INTLTR:
121
154
case NPY_UINTLTR:
122
155
case NPY_LONGLTR:
156
+ case NPY_LONGLONGLTR:
123
157
if ( cspType != csp::CspType::Type::INT64 )
124
158
CSP_THROW ( ValueError, " numpy type " << numpy_type_char << " requires int output type" );
125
159
break ;
126
160
case NPY_ULONGLTR:
127
- case NPY_LONGLONGLTR:
128
161
case NPY_ULONGLONGLTR:
129
162
CSP_THROW ( ValueError, " numpy type " << numpy_type_char << " (int type that can't cleanly convert to long) not supported" );
130
163
case NPY_HALFLTR:
@@ -144,7 +177,6 @@ void validateNumpyTypeVsCspType( const CspTypePtr & type, char numpy_type_char )
144
177
// everything works as object
145
178
break ;
146
179
case NPY_STRINGLTR:
147
- case NPY_STRINGLTR2:
148
180
case NPY_UNICODELTR:
149
181
case NPY_CHARLTR:
150
182
if ( cspType != csp::CspType::Type::STRING )
0 commit comments