Skip to content

Commit

Permalink
Fix #1149 - bytes, bytearray types managed
Browse files Browse the repository at this point in the history
  • Loading branch information
Nelson-numerical-software committed Apr 9, 2024
1 parent 5488490 commit 1c8033b
Show file tree
Hide file tree
Showing 40 changed files with 1,394 additions and 450 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Expand Up @@ -9,9 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- [#1141](http://github.com/nelson-lang/nelson/issues/1141) Help about Managing Data between Python and Nelson.
- Python interface (part 2):

- [#1141](http://github.com/nelson-lang/nelson/issues/1141) Help about Managing Data between Python and Nelson.
- [#1149](https://github.com/nelson-lang/nelson/issues/1149) python bytes, and bytearray types were not managed.
- `pyenv`: can use environment variables to set values.

- `getenv`: Retrieve the values of several environment variables.
- `pyenv`: can use environment variables to set values.

### Changed

Expand All @@ -21,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- [#1144](http://github.com/nelson-lang/nelson/issues/1144) test_run markdown help file had a typo.
- [#1143](http://github.com/nelson-lang/nelson/issues/1143) Linux Snapcraft version did not allow to use python.
- `single(int64([1 2; 3 4]))` returned a wrong value.
- `py.tuple`, `py.list` compatibility increased.

## 1.3.0 (2024-03-30)

Expand Down
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/char.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = char(obj)
r = obj.char();
if ismethod(obj, 'char')
r = obj.char();
else
error([_('Wrong value for #2 argument.'), ' ', 'char']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/double.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = double(obj)
r = obj.double();
if ismethod(obj, 'double')
r = obj.double();
else
error([_('Wrong value for #2 argument.'), ' ', 'double']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/int16.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = int16(obj)
r = obj.int16();
if ismethod(obj, 'int16')
r = obj.int16();
else
error([_('Wrong value for #2 argument.'), ' ', 'int16']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/int32.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = int32(obj)
r = obj.int32();
if ismethod(obj, 'int32')
r = obj.int32();
else
error([_('Wrong value for #2 argument.'), ' ', 'int32']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/int64.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = int64(obj)
r = obj.int64();
if ismethod(obj, 'int64')
r = obj.int64();
else
error([_('Wrong value for #2 argument.'), ' ', 'int64']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/int8.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = int8(obj)
r = obj.int8();
if ismethod(obj, 'int8')
r = obj.int8();
else
error([_('Wrong value for #2 argument.'), ' ', 'int8']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/logical.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = logical(obj)
r = obj.logical();
if ismethod(obj, 'logical')
r = obj.logical();
else
error([_('Wrong value for #2 argument.'), ' ', 'logical']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/single.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = single(obj)
r = obj.single();
if ismethod(obj, 'single')
r = obj.single();
else
error([_('Wrong value for #2 argument.'), ' ', 'single']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/string.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = string(obj)
r = obj.string();
if ismethod(obj, 'string')
r = obj.string();
else
error([_('Wrong value for #2 argument.'), ' ', 'string']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/uint16.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = uint16(obj)
r = obj.uint16();
if ismethod(obj, 'uint16')
r = obj.uint16();
else
error([_('Wrong value for #2 argument.'), ' ', 'uint16']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/uint32.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = uint32(obj)
r = obj.uint32();
if ismethod(obj, 'uint32')
r = obj.uint32();
else
error([_('Wrong value for #2 argument.'), ' ', 'uint32']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/uint64.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = uint64(obj)
r = obj.uint64();
if ismethod(obj, 'uint64')
r = obj.uint64();
else
error([_('Wrong value for #2 argument.'), ' ', 'uint64']);
end
end
%=============================================================================
6 changes: 5 additions & 1 deletion modules/python_engine/functions/@py/uint8.m
Expand Up @@ -8,6 +8,10 @@
% LICENCE_BLOCK_END
%=============================================================================
function r = uint8(obj)
r = obj.uint8();
if ismethod(obj, 'uint8')
r = obj.uint8();
else
error([_('Wrong value for #2 argument.'), ' ', 'uint8']);
end
end
%=============================================================================
3 changes: 3 additions & 0 deletions modules/python_engine/help/en_US/xml/pyrun.xml
Expand Up @@ -87,6 +87,9 @@ r = pyrun('d = a + c', 'd')]]>
<see_also_item>
<link linkend="${python_engine}pyenv">pyenv</link>
</see_also_item>
<see_also_item>
<link linkend="${python_engine}python_types">Python types supported</link>
</see_also_item>
</see_also>

<history>
Expand Down
4 changes: 4 additions & 0 deletions modules/python_engine/help/en_US/xml/python_types.xml
Expand Up @@ -55,6 +55,10 @@
<td>py.bytes</td><td
>double, single, int8, uint8, int16, uint16, int32, uint32, int64, uint64, logical</td>
</tr>
<tr>
<td>py.bytearray</td><td
>double, single, int8, uint8, int16, uint16, int32, uint32, int64, uint64, logical</td>
</tr>
<tr>
<td>py.array.array</td><td
>double, single, int8, uint8, int16, uint16, int32, uint32, int64, uint64</td>
Expand Down
97 changes: 77 additions & 20 deletions modules/python_engine/src/cpp/PyObjectHelpers.cpp
Expand Up @@ -12,6 +12,76 @@
//=============================================================================
namespace Nelson {
//=============================================================================
PythonType
getPythonType(PyObject* po)
{
if (po == nullptr) {
return PythonType::PY_NOT_MANAGED;
}

PyTypeObject* pyTypeObject = Py_TYPE(po);

if (pyTypeObject == PyFloat_TypePtr) {
return PythonType::PY_FLOAT_TYPE;
}
if (pyTypeObject == PyBool_TypePtr) {
return PythonType::PY_BOOL_TYPE;
}
if (pyTypeObject == PyComplex_TypePtr) {
return PythonType::PY_COMPLEX_TYPE;
}
if (pyTypeObject == PyLong_TypePtr) {
return PythonType::PY_LONG_TYPE;
}
if (pyTypeObject == PyBytes_TypePtr) {
return PythonType::PY_BYTES_TYPE;
}
if (pyTypeObject == PyByteArray_TypePtr) {
return PythonType::PY_BYTE_ARRAY_TYPE;
}

std::wstring typeName = TypeName(po);
if (typeName == L"NoneType") {
return PythonType::PY_NONE_TYPE;
}
if (typeName == L"memoryview") {
return PythonType::PY_MEMORY_VIEW_TYPE;
}
if (typeName == L"list") {
return PythonType::PY_LIST_TYPE;
}
if (typeName == L"tuple") {
return PythonType::PY_TUPLE_TYPE;
}
if (typeName == L"dict") {
return PythonType::PY_DICT_TYPE;
}
if (typeName == L"str") {
return PythonType::PY_STR_TYPE;
}

std::wstring numpyPrefix = L"numpy.";
if (typeName.compare(0, numpyPrefix.length(), numpyPrefix) == 0) {
return PythonType::PY_NUMPY_TYPE;
}

PyObject* arrayModule = NLSPyImport_ImportModule("array");
if (arrayModule) {
PyObject* arrayType = NLSPyObject_GetAttrString(arrayModule, "array");
if (arrayType) {
if (NLSPyObject_IsInstance(po, arrayType)) {
NLSPy_XDECREF(arrayType);
NLSPy_XDECREF(arrayModule);
return PythonType::PY_ARRAY_ARRAY_TYPE;
}
NLSPy_XDECREF(arrayType);
}
NLSPy_XDECREF(arrayModule);
}

return PythonType::PY_NOT_MANAGED;
}
//=============================================================================
std::wstring
PyObjectToStringRepresentation(PyObject* po)
{
Expand Down Expand Up @@ -48,7 +118,6 @@ getPyObjectMethods(PyObject* po, bool withUnderscoreMethods)
for (Py_ssize_t i = 0; i < size; ++i) {
PyObject* item = NLSPyList_GetItem(dir_result, i);
if (item != NULL) {

const char* attr_name = NLSPyUnicode_AsUTF8(item);
if (attr_name) {
PyObject* method = NLSPyObject_GetAttrString(po, attr_name);
Expand Down Expand Up @@ -130,34 +199,17 @@ deepCopyPyObject(PyObject* obj)
const char*
getArrayArrayTypeCode(PyObject* pyObject)
{
PyObject* arrayModule = NLSPyImport_ImportModule("array");
if (!arrayModule) {
return nullptr;
}
PyObject* arrayType = NLSPyObject_GetAttrString(arrayModule, "array");
if (!arrayType) {
NLSPy_XDECREF(arrayModule);
return nullptr;
}
bool isInstanceArrayArray = NLSPyObject_IsInstance(pyObject, arrayType);
if (!isInstanceArrayArray) {
NLSPy_XDECREF(arrayType);
NLSPy_XDECREF(arrayModule);
return nullptr;
}

PyObject* typeChar = NLSPyObject_GetAttrString(pyObject, "typecode");
if (typeChar) {
PyObject* typeStr = NLSPyUnicode_AsUTF8String(typeChar);
if (typeStr) {
const char* typeCode = NLSPyBytes_AsString(typeStr);
NLSPy_DECREF(typeStr);
NLSPy_XDECREF(typeChar);
return typeCode;
}
}
NLSPy_XDECREF(typeChar);
NLSPy_XDECREF(arrayType);
NLSPy_XDECREF(arrayModule);

return nullptr;
}
Expand Down Expand Up @@ -252,6 +304,12 @@ PyTypecodeToNelsonType(const char* memoryViewType)
if (strcmp(memoryViewType, "I") == 0) {
return NLS_UINT32;
}
if (strcmp(memoryViewType, "l") == 0) {
return NLS_INT32;
}
if (strcmp(memoryViewType, "L") == 0) {
return NLS_UINT32;
}
if (strcmp(memoryViewType, "h") == 0) {
return NLS_INT16;
}
Expand All @@ -264,7 +322,6 @@ PyTypecodeToNelsonType(const char* memoryViewType)
if (strcmp(memoryViewType, "B") == 0) {
return NLS_UINT8;
}

return NLS_UNKNOWN;
}
//=============================================================================
Expand Down
22 changes: 22 additions & 0 deletions modules/python_engine/src/cpp/PyObjectHelpers.hpp
Expand Up @@ -15,6 +15,28 @@
//=============================================================================
namespace Nelson {
//=============================================================================
enum PythonType
{
PY_NONE_TYPE = 0,
PY_STR_TYPE,
PY_FLOAT_TYPE,
PY_BOOL_TYPE,
PY_COMPLEX_TYPE,
PY_LONG_TYPE,
PY_BYTES_TYPE,
PY_BYTE_ARRAY_TYPE,
PY_MEMORY_VIEW_TYPE,
PY_LIST_TYPE,
PY_TUPLE_TYPE,
PY_DICT_TYPE,
PY_ARRAY_ARRAY_TYPE,
PY_NUMPY_TYPE,
PY_NOT_MANAGED
};
//=============================================================================
PythonType
getPythonType(PyObject* po);
//=============================================================================
std::wstring
PyObjectToStringRepresentation(PyObject* po);
//=============================================================================
Expand Down

0 comments on commit 1c8033b

Please sign in to comment.