{ "info": { "author": "Jean-Michel Perraud", "author_email": "per202@csiro.au", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.6", "Topic :: Software Development", "Topic :: Software Development :: Object Brokering" ], "description": "# refcount\n\nA Python package for reference counting native resources\n\n[![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jmp75/pyrefcount/blob/devel/LICENSE.txt) ![status](https://img.shields.io/badge/status-alpha-blue.svg) master: [![Build status - master](https://ci.appveyor.com/api/projects/status/vmwq7xarxxj8s564/branch/master?svg=true)](https://ci.appveyor.com/project/jmp75/pyrefcount/branch/master) devel: [![Build status - devel](https://ci.appveyor.com/api/projects/status/vmwq7xarxxj8s564/branch/devel?svg=true)](https://ci.appveyor.com/project/jmp75/pyrefcount/branch/devel)\n\nThis package is primarily for managing resources in native libraries, written for instance in C++, from Python. While it boils down to \"simply\" maintaining a set of counters, it is practically complicated to properly do so and not end up with memory leak or crashes. This package aims to offer structured options for managing external native resources - I could not locate a pypi package doing just what I needed. Other use cases requiring reference counting, aside from native library resources, may benefit from reusing and extending classes in `refcount`.\n\n## License\n\nMIT-derived (see [License.txt](./LICENSE.txt))\n\n## Installation\n\n```sh\npip install refcount\n```\n\nFrom source:\n\n```sh\npip install -r requirements.txt\npython setup.py install\n```\n\n## Documentation\n\n### Example\n\nA canonical illustration of the use of this package, based on one of the unit tests. Say we have a C++ library with objects and a C API:\n\n```C++\n#define TEST_DOG_PTR testnative::dog*\n#define TEST_OWNER_PTR testnative::owner*\n#define TEST_COUNTED_PTR testnative::reference_counter*\n\ntestnative::dog* create_dog();\ntestnative::owner* create_owner(testnative::dog* d);\nvoid say_walk(testnative::owner* owner);\nvoid release(testnative::reference_counter* obj);\n// etc.\n```\n\nFrom the outside of the library the API is exported with opaque pointers `void*` (C structs pointers and native C99 types could be handled too).\n\n```C++\nvoid* create_dog();\nvoid* create_owner(void* d);\nvoid say_walk(void* owner);\nvoid release(void* obj);\n// etc.\n```\n\nStarting with the end in mind, from Python we want an API hiding the low level details close to the C API, in particular avoiding managing native memory via `release` C API calls, piggybacking the python GC instead.\n\n```py\ndog = Dog()\nowner = DogOwner(dog)\nowner.say_walk()\nprint(dog.position)\ndog = None # the \"native dog\" is still alive though, as the owner incremented the ref count\nowner = None\n```\n\nThis is doable with `refcount` and the `cffi` package. One possible design is:\n\n```py\nut_ffi = cffi.FFI()\n\nut_ffi.cdef('extern void* create_dog();')\nut_ffi.cdef('extern void* create_owner( void* d);')\nut_ffi.cdef('extern void say_walk( void* owner);')\nut_ffi.cdef('extern void release( void* obj);')\n# etc.\n\nut_dll = ut_ffi.dlopen('c:/path/to/test_native_library.dll', 1) # Lazy loading\n\nclass CustomCffiNativeHandle(CffiNativeHandle):\n def __init__(self, pointer, prior_ref_count = 0):\n super(CustomCffiNativeHandle, self).__init__(pointer, type_id='', prior_ref_count = prior_ref_count)\n\n def _release_handle(self):\n ut_dll.release(self.get_handle())\n return True\n\nclass Dog(CustomCffiNativeHandle):\n def __init__(self, pointer = None):\n if pointer is None:\n pointer = ut_dll.create_dog()\n super(Dog, self).__init__(pointer)\n # etc.\n\nclass DogOwner(CustomCffiNativeHandle):\n\n def __init__(self, dog):\n super(DogOwner, self).__init__(None)\n self._set_handle(ut_dll.create_owner(dog.get_handle()))\n self.dog = dog\n self.dog.add_ref() # Do note this important reference increment\n\n def say_walk(self):\n ut_dll.say_walk(self.get_handle())\n\n def _release_handle(self):\n super(DogOwner, self)._release_handle()\n # super(DogOwner, self)._release_handle()\n self.dog.release()\n return True\n```\n\n### Related work\n\n#### Ancestry\n\nThis python package `refcount` actually spawned from prior work for interoperability between C++, R and .NET. The port to Python was also influenced by work authored by Kevin Plastow and undertaken at the Australian Bureau of Meteorology for C/C++/Python interop using `cffi`.\n\nReaders may also want to look at:\n\n* a nuget package [dynamic-interop-dll](https://github.com/jmp75/dynamic-interop-dll) for .NET/native interop.\n* A set of mostly c++ software [tools for interop with C/C++](https://github.com/jmp75/rcpp-interop-commons)\n* A C# library for [generating interop glue code on top of C API glue code](https://github.com/jmp75/rcpp-wrapper-generation).\n\n#### Other python packages\n\nWhile this present package was authored in part because no existing prior (Python) work could quite fit the need, there are packages that may better address your particular need:\n\n* [infi.pyutils](https://pypi.org/project/infi.pyutils/) constains a reference counting class.\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/jmp75/pyrefcount", "keywords": "interop python native-libraries reference-counting handle cffi", "license": "", "maintainer": "", "maintainer_email": "", "name": "refcount", "package_url": "https://pypi.org/project/refcount/", "platform": "", "project_url": "https://pypi.org/project/refcount/", "project_urls": { "Bug Reports": "https://github.com/jmp75/pyrefcount/issues", "Homepage": "https://github.com/jmp75/pyrefcount", "Source": "https://github.com/jmp75/pyrefcount" }, "release_url": "https://pypi.org/project/refcount/0.6.2/", "requires_dist": [ "cffi" ], "requires_python": "", "summary": "A Python package for reference counting and interop with native pointers", "version": "0.6.2" }, "last_serial": 4654613, "releases": { "0.5.1": [ { "comment_text": "", "digests": { "md5": "e0c571d2eceb3406287054a8738fbb05", "sha256": "f4dfb91beb7bffd4a42d644e40fe15466d12c75739681ca9f5bb440c94f149d4" }, "downloads": -1, "filename": "refcount-0.5.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e0c571d2eceb3406287054a8738fbb05", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 9444, "upload_time": "2018-12-19T10:16:07", "url": "https://files.pythonhosted.org/packages/0a/50/1aaad578ac9eba12729d66afabc3d9d171ea22655eefc0a093e4d3ada3f6/refcount-0.5.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c714eb41a050e213b8135716778e2675", "sha256": "e8127549e100866c1bbc32d2b4fa46dddb1fdb30713f34a926af8b016103c9a2" }, "downloads": -1, "filename": "refcount-0.5.1.zip", "has_sig": false, "md5_digest": "c714eb41a050e213b8135716778e2675", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18211, "upload_time": "2018-12-19T10:16:09", "url": "https://files.pythonhosted.org/packages/b9/72/e7ca78710820bf55bba68763004a485cbefdeba8ee864eccd5170c432fbc/refcount-0.5.1.zip" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "c685d1bc2f64a78e6f02aae86c59095b", "sha256": "d0d442dfa441ad0949b6c1d211df9ce12272f0e84c1ba5e9826a5e20434d7c96" }, "downloads": -1, "filename": "refcount-0.6.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "c685d1bc2f64a78e6f02aae86c59095b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10398, "upload_time": "2019-01-02T23:11:12", "url": "https://files.pythonhosted.org/packages/47/a6/b51fdadc402a2d4312d5e3186c875f0b177cfb3a283722d552c5b7fd3b67/refcount-0.6.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "86bb576d29b6327c35c53d65ec1dd82f", "sha256": "85875298988746e5e12397ae7f225b17e99eacc7474023967e8749c8addff3cb" }, "downloads": -1, "filename": "refcount-0.6.0.zip", "has_sig": false, "md5_digest": "86bb576d29b6327c35c53d65ec1dd82f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17630, "upload_time": "2019-01-02T23:11:14", "url": "https://files.pythonhosted.org/packages/39/11/e9509a540d497d21b7aec5292daca7375dae47191f8249b35e9c3561e84c/refcount-0.6.0.zip" } ], "0.6.1.1": [ { "comment_text": "", "digests": { "md5": "c2fe51b09cf208c087a525961c7110b4", "sha256": "6d045714a5919e1bd1abf85272e0191d3b26efb8e4ce25c7fa194c76a359c611" }, "downloads": -1, "filename": "refcount-0.6.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "c2fe51b09cf208c087a525961c7110b4", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10444, "upload_time": "2019-01-03T00:30:20", "url": "https://files.pythonhosted.org/packages/22/86/415de83a4390c918d3f541d5b88bc54875cb7fe659bbd27f6bb6f6ef946c/refcount-0.6.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4d8ab648cdfabc0de2d60a662d6d637b", "sha256": "4cc44113169c2dac0e9a76441f15be6154d129d3ddbb378a379cf1db3cd42d2a" }, "downloads": -1, "filename": "refcount-0.6.1.1.zip", "has_sig": false, "md5_digest": "4d8ab648cdfabc0de2d60a662d6d637b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17779, "upload_time": "2019-01-03T00:30:22", "url": "https://files.pythonhosted.org/packages/a0/b2/6dc89160c98a7333ba660b8ed8049b65163df70005503432a4de8bf2c9f6/refcount-0.6.1.1.zip" } ], "0.6.2": [ { "comment_text": "", "digests": { "md5": "5e1b5af6c070e323d39ee519e1ab5a58", "sha256": "d6ef1eff17d410db5df925612c0d49e464e87813e3a0e5c20530d13a5ccafd25" }, "downloads": -1, "filename": "refcount-0.6.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "5e1b5af6c070e323d39ee519e1ab5a58", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10424, "upload_time": "2019-01-03T00:32:11", "url": "https://files.pythonhosted.org/packages/b1/56/af711ff733a7e85bbbd74cead55789815f7ed26dec4c997971714b846167/refcount-0.6.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "70afe207e2b8e7a4271aad66a8652c4d", "sha256": "73d13bc48610eb79713d5078f6934b09a64df7044dd1728bdfd2857de281be72" }, "downloads": -1, "filename": "refcount-0.6.2.zip", "has_sig": false, "md5_digest": "70afe207e2b8e7a4271aad66a8652c4d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17712, "upload_time": "2019-01-03T00:32:13", "url": "https://files.pythonhosted.org/packages/29/6c/dde15799a7dadab06f4dc422ff9c775e99c8661b6b8fed842404428ebef6/refcount-0.6.2.zip" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "5e1b5af6c070e323d39ee519e1ab5a58", "sha256": "d6ef1eff17d410db5df925612c0d49e464e87813e3a0e5c20530d13a5ccafd25" }, "downloads": -1, "filename": "refcount-0.6.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "5e1b5af6c070e323d39ee519e1ab5a58", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10424, "upload_time": "2019-01-03T00:32:11", "url": "https://files.pythonhosted.org/packages/b1/56/af711ff733a7e85bbbd74cead55789815f7ed26dec4c997971714b846167/refcount-0.6.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "70afe207e2b8e7a4271aad66a8652c4d", "sha256": "73d13bc48610eb79713d5078f6934b09a64df7044dd1728bdfd2857de281be72" }, "downloads": -1, "filename": "refcount-0.6.2.zip", "has_sig": false, "md5_digest": "70afe207e2b8e7a4271aad66a8652c4d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17712, "upload_time": "2019-01-03T00:32:13", "url": "https://files.pythonhosted.org/packages/29/6c/dde15799a7dadab06f4dc422ff9c775e99c8661b6b8fed842404428ebef6/refcount-0.6.2.zip" } ] }