diff --git a/CHANGES.rst b/CHANGES.rst index bdcdcf00..789d4c3c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,14 @@ Changes ======= +0.0.5 (2017-11-13) +------------------ + +* Added support for light-weight pointers (``ctypes.byref``) +* FIX: Elements within structures are properly synchronized even if they are not a pointer on their own. +* FIX: Structure objects in arrays of structures are properly initialized. +* FIX: Links in README.rst work when rendered on PyPI. + 0.0.4 (2017-11-05) ------------------ diff --git a/README.rst b/README.rst index f39f67fa..d926eaef 100644 --- a/README.rst +++ b/README.rst @@ -73,7 +73,7 @@ Prerequisites +--------------------+-------------------------------------------------------------------------------------------------------------+ | for usage + - `CPython`_ 3.x (tested with 3.{4,5,6}) - no additional Python packages required + -| + - `Wine`_ 2.x (tested with 2.{5,6,10,12,18,19} regular & `staging`_) - expected to be in the user's `PATH`_ + +| + - `Wine`_ 2.x (tested with 2.{5 to 19} regular & `staging`_) - expected to be in the user's `PATH`_ + +--------------------+-------------------------------------------------------------------------------------------------------------+ | for tests + - `pytest`_ + | + - `mingw cross-compiler`_ - for building DLLs against which examples and tests can be run + @@ -122,17 +122,17 @@ A lot of code, which was written with ``ctypes``' ``cdll``, ``windll`` or ``oled in mind and which runs under Windows, should run just fine with zugbruecke on Unix (assuming it does not use Windows features not supported by Wine). -.. _examples: docs/examples.rst +.. _examples: http://zugbruecke.readthedocs.io/en/stable/examples.html .. _ctypes' documentation: https://docs.python.org/3/library/ctypes.html Speed ===== zugbruecke performs reasonably well given its complexity with **less than 0.2 µs -overhead per call** in average on modern hardware. Check the latest `benchmarks`_ -for more details. +overhead per call** in average on modern hardware. It is not (yet) optimized for +speed. Check the latest `benchmarks`_ for more details. -.. _benchmarks: docs/benchmarks.rst +.. _benchmarks: http://zugbruecke.readthedocs.io/en/stable/benchmarks.html Security ======== @@ -141,13 +141,12 @@ zugbruecke is **notoriously insecure**. Never, ever, run it with root / super users privileges! Do not use it where security matters! For details, check the section on `security`_ in the documentation. -.. _security: docs/security.rst +.. _security: http://zugbruecke.readthedocs.io/en/stable/security.html Need help? ========== Feel free to post questions in the `GitHub issue tracker`_ of this project. -Make sure to label them as `question`_. .. _question: https://github.com/pleiszenburg/zugbruecke/labels/question @@ -163,7 +162,7 @@ Make sure you have read the chapter on `bugs`_ in zugbruecke's documentation. .. _GitHub issue tracker: https://github.com/pleiszenburg/zugbruecke/issues .. _Python tracker: https://bugs.python.org/ .. _WineHQ Bug Tracking System: https://bugs.winehq.org/ -.. _bugs: docs/bugs.rst +.. _bugs: http://zugbruecke.readthedocs.io/en/stable/bugs.html Miscellaneous ============= @@ -177,16 +176,18 @@ Miscellaneous - `Contributing`_ (**Contributions are highly welcomed!**) - `FAQ`_ - `Authors`_ +- `Changes`_ - `Missing features`_ (for full ctypes compatibility) - `Long-term ideas`_ - `Upstream issues`_ (relevant bugs in dependencies) .. _Read the Docs: http://zugbruecke.readthedocs.io/en/latest/ .. _zugbruecke repository: docs/index.rst -.. _License: LICENSE -.. _Contributing: CONTRIBUTING.rst -.. _FAQ: docs/faq.rst -.. _Authors: AUTHORS.rst +.. _License: https://github.com/pleiszenburg/zugbruecke/blob/master/LICENSE +.. _Contributing: https://github.com/pleiszenburg/zugbruecke/blob/master/CONTRIBUTING.rst +.. _FAQ: http://zugbruecke.readthedocs.io/en/stable/faq.html +.. _Authors: https://github.com/pleiszenburg/zugbruecke/blob/master/AUTHORS.rst +.. _Changes: https://github.com/pleiszenburg/zugbruecke/blob/master/CHANGES.rst .. _Missing features: https://github.com/pleiszenburg/zugbruecke/issues?q=is%3Aissue+is%3Aopen+label%3A%22missing+ctypes+feature%22 .. _Long-term ideas: https://github.com/pleiszenburg/zugbruecke/milestone/2 .. _Upstream issues: https://github.com/pleiszenburg/zugbruecke/issues?q=is%3Aissue+is%3Aopen+label%3Aupstream diff --git a/demo_dll/demo_dll.c b/demo_dll/demo_dll.c index 927316ac..25ea686f 100644 --- a/demo_dll/demo_dll.c +++ b/demo_dll/demo_dll.c @@ -116,7 +116,6 @@ double __stdcall DEMODLL cookbook_distance( // zugbruecke demo // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -/* Average values in an array */ void __stdcall DEMODLL bubblesort( float *a, int n @@ -203,11 +202,22 @@ void __stdcall DEMODLL complex_demo_routine( struct test *param_struct_test_p ) { - printf("el_int8t = '%d' \n", (*param_struct_test_p).el_int8t); - printf("el_int8t_4[0] = '%d' \n", (*param_struct_test_p).el_int8t_4[0]); - printf("el_int8t_4[1] = '%d' \n", (*param_struct_test_p).el_int8t_4[1]); - printf("el_int8t_4[2] = '%d' \n", (*param_struct_test_p).el_int8t_4[2]); - printf("el_int8t_4[3] = '%d' \n", (*param_struct_test_p).el_int8t_4[3]); + + int8_t i, j; + + for(i = 0; i < 4; i++) + { + (*param_struct_test_p).el_int8t_4[i] *= i; + } + + for(i = 0; i < 3; i++) + { + for(j = 0; j < 2; j++) + { + (*param_struct_test_p).el_int8t_2x3[i][j] += i + j; + } + } + } diff --git a/docs/benchmarks.rst b/docs/benchmarks.rst index 6cec3cac..780fe064 100644 --- a/docs/benchmarks.rst +++ b/docs/benchmarks.rst @@ -12,7 +12,8 @@ Benchmarks ========== *zugbruecke* performs reasonably well given its complexity with **less than 0.2 µs -overhead per call** in average on modern hardware. +overhead per call** in average on modern hardware. It is not (yet) optimized for +speed. The inter-process communication via *multiprocessing connection* adds overhead to every function call. Because *zugbruecke* takes care of packing and unpacking of diff --git a/docs/memsync.rst b/docs/memsync.rst index 629ae8c4..a3ccb707 100644 --- a/docs/memsync.rst +++ b/docs/memsync.rst @@ -27,7 +27,6 @@ Consider the following example DLL routine in C: .. code:: C - /* Average values in an array */ void __stdcall __declspec(dllimport) bubblesort( float *a, int n diff --git a/examples/demo_call_win.py b/examples/demo_call_win.py index f64d3da4..f16d2dc8 100755 --- a/examples/demo_call_win.py +++ b/examples/demo_call_win.py @@ -32,8 +32,11 @@ # IMPORT # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -import ctypes +from sys import platform +if any([platform.startswith(os_name) for os_name in ['linux', 'darwin', 'freebsd']]): + import zugbruecke as ctypes +elif platform.startswith('win'): + import ctypes # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -59,7 +62,7 @@ class type_test_struct(ctypes.Structure): # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -class demo_routine_caller_class(): +class sample_class(): def __init__(self): @@ -77,7 +80,7 @@ def __init__(self): self._call_demo_routine_.restype = ctypes.c_void_p - def call(self, param_char, param_int, param_type_test): + def complex_demo_routine(self, param_char, param_int, param_type_test): # Call routine in DLL self._call_demo_routine_( @@ -86,9 +89,6 @@ def call(self, param_char, param_int, param_type_test): ctypes.byref(param_type_test) ) - print('Called!') - return True - # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # MAKE A CALL @@ -99,7 +99,9 @@ def call(self, param_char, param_int, param_type_test): # Initialize some test parameters sample_param_char = ctypes.c_char(7) sample_param_int = ctypes.c_int(42) + # Initialize a test structure sample_type_test = type_test_struct() + # Fill test structure with data sample_type_test.el_char = ctypes.c_char(5) sample_type_test.el_int8t = ctypes.c_int8(17) sample_type_test.el_int16t = ctypes.c_int16(25874) @@ -111,7 +113,14 @@ def call(self, param_char, param_int, param_type_test): sample_type_test.el_int8t_2x3 = (ctypes.c_int8 * len(el_int8t_2x3[0]) * len(el_int8t_2x3))(*(tuple(i) for i in el_int8t_2x3)) # Initialize caller - demo_routine_caller = demo_routine_caller_class() + samples = sample_class() # Call - demo_routine_caller.call(sample_param_char, sample_param_int, sample_type_test) + samples.complex_demo_routine(sample_param_char, sample_param_int, sample_type_test) + + # Print result + print([0, 2, 6, 12], sample_type_test.el_int8t_4[:]) + print( + [[1, 3], [3, 5], [7, 6]], + [e[:] for e in sample_type_test.el_int8t_2x3[:]] + ) diff --git a/examples/test_zugbruecke.py b/examples/test_zugbruecke.py index cbefcb2c..c66e7242 100755 --- a/examples/test_zugbruecke.py +++ b/examples/test_zugbruecke.py @@ -43,8 +43,7 @@ f.write('{"log_level": 10}') f.close() - import zugbruecke - ctypes = zugbruecke + import zugbruecke as ctypes elif platform.startswith('win'): diff --git a/examples/test_zugbruecke_perf.py b/examples/test_zugbruecke_perf.py index 684cedaa..c0385742 100755 --- a/examples/test_zugbruecke_perf.py +++ b/examples/test_zugbruecke_perf.py @@ -44,8 +44,7 @@ f.write('{}') f.close() - import zugbruecke - ctypes = zugbruecke + import zugbruecke as ctypes elif platform.startswith('win'): diff --git a/setup.py b/setup.py index 8ac1d708..3e0bbc3b 100644 --- a/setup.py +++ b/setup.py @@ -46,7 +46,7 @@ # Bump version HERE! -_version_ = '0.0.4' +_version_ = '0.0.5' # List all versions of Python which are supported diff --git a/src/zugbruecke/core/arg_contents.py b/src/zugbruecke/core/arg_contents.py index 501c3bec..7547ac0c 100644 --- a/src/zugbruecke/core/arg_contents.py +++ b/src/zugbruecke/core/arg_contents.py @@ -75,8 +75,13 @@ def arg_list_sync(self, old_arguments_list, new_arguments_list, argtypes_list): def __item_pointer_strip__(self, arg_in): + # Handle pointer object if hasattr(arg_in, 'contents'): return arg_in.contents + # Handle reference (byref) 'light pointer' + elif hasattr(arg_in, '_obj'): + return arg_in._obj + # Object was likely not provided as a pointer else: return arg_in @@ -166,8 +171,8 @@ def __pack_item_struct__(self, struct_raw, struct_def_dict): def __sync_item__(self, old_arg, new_arg, arg_def_dict): - # Grep the simple case first, pointers to scalars - if arg_def_dict['s'] and len(arg_def_dict['f']) > 0: + # Grep the simple case first, scalars + if arg_def_dict['s']: # Strip away the pointers ... (all flags are pointers in this case) for flag in arg_def_dict['f']: @@ -177,14 +182,17 @@ def __sync_item__(self, old_arg, new_arg, arg_def_dict): new_arg = self.__item_pointer_strip__(new_arg) if arg_def_dict['g'] == GROUP_FUNDAMENTAL: - old_arg.value = new_arg.value + if hasattr(old_arg, 'value'): + old_arg.value = new_arg.value + else: + pass # only relevant within structs or for actual pointers to scalars elif arg_def_dict['g'] == GROUP_STRUCT: return self.__sync_item_struct__(old_arg, new_arg, arg_def_dict) else: pass # DO NOTHING? - # The non-trivial case, pointers to arrays - elif not arg_def_dict['s'] and arg_def_dict['p']: + # The non-trivial case, arrays + elif not arg_def_dict['s']: self.__sync_item_array__(old_arg, new_arg, arg_def_dict) @@ -324,7 +332,7 @@ def __unpack_item_array__(self, arg_in, arg_def_dict, flag_index = 0): arg_type = getattr(ctypes, arg_def_dict['t']) * flag arg_in = arg_type(*arg_in) elif arg_def_dict['g'] == GROUP_STRUCT: - arg_type = self.struct_type_dict[struct_def_dict['t']] * flag + arg_type = self.struct_type_dict[arg_def_dict['t']] * flag arg_in = arg_type(*(self.__unpack_item_struct__(e, arg_def_dict) for e in arg_in)) else: raise # TODO diff --git a/tests/test_avg.py b/tests/test_avg.py index 2756c20e..62657139 100644 --- a/tests/test_avg.py +++ b/tests/test_avg.py @@ -35,8 +35,7 @@ from sys import platform if any([platform.startswith(os_name) for os_name in ['linux', 'darwin', 'freebsd']]): - import zugbruecke - ctypes = zugbruecke + import zugbruecke as ctypes elif platform.startswith('win'): import ctypes diff --git a/tests/test_bubblesort.py b/tests/test_bubblesort.py index 4e9ab9f6..bf58453b 100644 --- a/tests/test_bubblesort.py +++ b/tests/test_bubblesort.py @@ -35,8 +35,7 @@ from sys import platform if any([platform.startswith(os_name) for os_name in ['linux', 'darwin', 'freebsd']]): - import zugbruecke - ctypes = zugbruecke + import zugbruecke as ctypes elif platform.startswith('win'): import ctypes diff --git a/tests/test_devide.py b/tests/test_devide.py index 8f19fd3b..c5c8f8eb 100644 --- a/tests/test_devide.py +++ b/tests/test_devide.py @@ -35,8 +35,7 @@ from sys import platform if any([platform.startswith(os_name) for os_name in ['linux', 'darwin', 'freebsd']]): - import zugbruecke - ctypes = zugbruecke + import zugbruecke as ctypes elif platform.startswith('win'): import ctypes diff --git a/tests/test_distance.py b/tests/test_distance.py index 83815f0a..84c652c2 100644 --- a/tests/test_distance.py +++ b/tests/test_distance.py @@ -35,8 +35,7 @@ from sys import platform if any([platform.startswith(os_name) for os_name in ['linux', 'darwin', 'freebsd']]): - import zugbruecke - ctypes = zugbruecke + import zugbruecke as ctypes elif platform.startswith('win'): import ctypes diff --git a/tests/test_gdc.py b/tests/test_gdc.py index 52991ac4..1c016d52 100644 --- a/tests/test_gdc.py +++ b/tests/test_gdc.py @@ -35,8 +35,7 @@ from sys import platform if any([platform.startswith(os_name) for os_name in ['linux', 'darwin', 'freebsd']]): - import zugbruecke - ctypes = zugbruecke + import zugbruecke as ctypes elif platform.startswith('win'): import ctypes diff --git a/tests/test_in_mantel.py b/tests/test_in_mantel.py index 6ad1b8be..7ad48e54 100644 --- a/tests/test_in_mantel.py +++ b/tests/test_in_mantel.py @@ -35,8 +35,7 @@ from sys import platform if any([platform.startswith(os_name) for os_name in ['linux', 'darwin', 'freebsd']]): - import zugbruecke - ctypes = zugbruecke + import zugbruecke as ctypes elif platform.startswith('win'): import ctypes