{ "info": { "author": "Wouter Boomsma", "author_email": "wb@di.ku.dk", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: C++", "Programming Language :: Cython", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6" ], "description": "[![Build Status](https://travis-ci.org/wouterboomsma/eigency.svg?branch=master)](https://travis-ci.org/wouterboomsma/eigency)\n\n# Eigency\nEigency is a Cython interface between Numpy arrays and Matrix/Array\nobjects from the Eigen C++ library. It is intended to simplify the\nprocess of writing C++ extensions using the Eigen library. Eigency is\ndesigned to reuse the underlying storage of the arrays when passing\ndata back and forth, and will thus avoid making unnecessary copies\nwhenever possible. Only in cases where copies are explicitly requested\nby your C++ code will they be made.\n\nBelow is a description of a range of common usage scenarios. A full working\nexample of both setup and these different use cases is available in the\n`test` directory distributed with the this package.\n\n## Setup\nTo import eigency functionality, add the following to your `.pyx` file:\n```\nfrom eigency.core cimport *\n```\nIn addition, in the `setup.py` file, the include directories must be\nset up to include the eigency includes. This can be done by calling\nthe `get_includes` function in the `eigency` module:\n```\nimport eigency\n...\nextensions = [\n Extension(\"module-dir-name/module-name\", [\"module-dir-name/module-name.pyx\"],\n include_dirs = [\".\", \"module-dir-name\"] + eigency.get_includes()\n ),\n]\n```\nEigency includes a version of the Eigen library, and the `get_includes` function will include the path to this directory. If you\nhave your own version of Eigen, just set the `include_eigen` option to False, and add your own path instead:\n\n```\n include_dirs = [\".\", \"module-dir-name\", 'path-to-own-eigen'] + eigency.get_includes(include_eigen=False)\n```\n\n## From Numpy to Eigen\nAssume we are writing a Cython interface to the following C++ function:\n\n```c++\nvoid function_w_mat_arg(const Eigen::Map &mat) {\n std::cout << mat << \"\\n\";\n}\n```\n\nNote that we use `Eigen::Map` to ensure that we can reuse the storage\nof the numpy array, thus avoiding making a copy. Assuming the C++ code\nis in a file called `functions.h`, the corresponding `.pyx` entry could look like this:\n\n```\ncdef extern from \"functions.h\":\n cdef void _function_w_mat_arg \"function_w_mat_arg\"(Map[MatrixXd] &)\n\n# This will be exposed to Python\ndef function_w_mat_arg(np.ndarray array):\n return _function_w_mat_arg(Map[MatrixXd](array))\n```\n\nThe last line contains the actual conversion. `Map` is an Eigency\ntype that derives from the real Eigen map, and will take care of\nthe conversion from the numpy array to the corresponding Eigen type. \n\nWe can now call the C++ function directly from Python:\n```python\n>>> import numpy as np\n>>> import eigency_tests\n>>> x = np.array([[1.1, 2.2], [3.3, 4.4]])\n>>> eigency_tests.function_w_mat_arg(x)\n1.1 3.3\n2.2 4.4\n```\n(if you are wondering about why the matrix is transposed, please \nsee the Storage layout section below).\n\n## Types matter\n\nThe basic idea behind eigency is to share the underlying representation of a \nnumpy array between Python and C++. This means that somewhere in the process, \nwe need to make explicit which numerical types we are dealing with. In the\nfunction above, we specify that we expect an Eigen MatrixXd, which means\nthat the numpy array must also contain double (i.e. float64) values. If we instead provide\na numpy array of ints, we will get strange results. \n\n```python\n>>> import numpy as np\n>>> import eigency_tests\n>>> x = np.array([[1, 2], [3, 4]])\n>>> eigency_tests.function_w_mat_arg(x)\n4.94066e-324 1.4822e-323\n9.88131e-324 1.97626e-323\n```\nThis is because we are explicitly asking C++ to interpret out python integer\nvalues as floats. \n\nTo avoid this type of error, you can force your cython function to\naccept only numpy arrays of a specific type:\n\n```\ncdef extern from \"functions.h\":\n cdef void _function_w_mat_arg \"function_w_mat_arg\"(Map[MatrixXd] &)\n\n# This will be exposed to Python\ndef function_w_mat_arg(np.ndarray[np.float64_t, ndim=2] array):\n return _function_w_mat_arg(Map[MatrixXd](array))\n```\n\n(Note that when using this technique to select the type, you also need to specify \nthe dimensions of the array (this will default to 1)). Using this new definition, \nusers will get an error when passing arrays of the wrong type:\n\n```python\n>>> import numpy as np\n>>> import eigency_tests\n>>> x = np.array([[1, 2], [3, 4]])\n>>> eigency_tests.function_w_mat_arg(x)\nTraceback (most recent call last):\n File \"\", line 1, in \n File \"eigency_tests/eigency_tests.pyx\", line 87, in eigency_tests.eigency_tests.function_w_mat_arg\nValueError: Buffer dtype mismatch, expected 'float64_t' but got 'long'\n```\n\nSince it avoids many surprises, it is strongly recommended to use this technique\nto specify the full types of numpy arrays in your cython code whenever \npossible.\n\n\n## Writing Eigen Map types in Cython\n\nSince Cython does not support nested fused types, you cannot write types like `Map[Matrix[double, 2, 2]]`. In most cases, you won't need to, since you can just use Eigens convenience typedefs, such as `Map[VectorXd]`. If you need the additional flexibility of the full specification, you can use the `FlattenedMap` type, where all type arguments can be specified at top level, for instance `FlattenedMap[Matrix, double, _2, _3]` or `FlattenedMap[Matrix, double, _2, Dynamic]`. Note that dimensions must be prefixed with an underscore.\n\nUsing full specifications of the Eigen types, the previous example would look like this:\n```\ncdef extern from \"functions.h\":\n cdef void _function_w_mat_arg \"function_w_mat_arg\" (FlattenedMap[Matrix, double, Dynamic, Dynamic] &)\n\n# This will be exposed to Python\ndef function_w_mat_arg(np.ndarray[np.float64_t, ndim=2] array):\n return _function_w_mat_arg(FlattenedMap[Matrix, double, Dynamic, Dynamic](array))\n```\n\n`FlattenedType` takes four template parameters: arraytype, scalartype,\nrows and cols. Eigen supports a few other template arguments for\nsetting the storage layout and Map strides. Since cython does not\nsupport default template arguments for fused types, we have instead\ndefined separate types for this purpose. These are called\n`FlattenedMapWithOrder` and `FlattenedMapWithStride` with five and eight\ntemplate arguments, respectively. For details on their use, see the section\nabout storage layout below.\n\n## From Numpy to Eigen (insisting on a copy)\n\nEigency will not complain if the C++ function you interface with does\nnot take a Eigen Map object, but instead a regular Eigen Matrix or\nArray. However, in such cases, a copy will be made. Actually, the\nprocedure is exactly the same as above. In the `.pyx` file, you still\ndefine everything exactly the same way as for the Map case described above.\n\nFor instance, given the following C++ function:\n```c++\nvoid function_w_vec_arg_no_map(const Eigen::VectorXd &vec);\n```\n\nThe Cython definitions would still look like this:\n\n```\ncdef extern from \"functions.h\":\n cdef void _function_w_vec_arg_no_map \"function_w_vec_arg_no_map\"(Map[VectorXd] &)\n\n# This will be exposed to Python\ndef function_w_vec_arg_no_map(np.ndarray[np.float64_t] array):\n return _function_w_vec_arg_no_map(Map[VectorXd](array))\n```\n\nCython will not mind the fact that the argument type in the extern\ndeclaration (a Map type) differs from the actual one in the `.h` file,\nas long as one can be assigned to the other. Since Map objects can be\nassigned to their corresponding Matrix/Array types this works\nseemlessly. But keep in mind that this assignment will make a copy of\nthe underlying data.\n\n## Eigen to Numpy\n\nC++ functions returning a reference to an Eigen Matrix/Array can also\nbe transferred to numpy arrays without copying their content. Assume\nwe have a class with a single getter function that returns an Eigen\nmatrix member:\n\n```c++\nclass MyClass {\npublic:\n MyClass():\n matrix(Eigen::Matrix3d::Constant(3.)) {\n }\n Eigen::MatrixXd &get_matrix() {\n return this->matrix;\n }\nprivate:\n Eigen::Matrix3d matrix;\n};\n```\n\nThe Cython C++ class interface is specified as usual:\n\n```\n cdef cppclass _MyClass \"MyClass\":\n _MyClass \"MyClass\"() except +\n Matrix3d &get_matrix()\n```\n\nAnd the corresponding Python wrapper:\n\n```python\ncdef class MyClass:\n cdef _MyClass *thisptr;\n\n def __cinit__(self):\n self.thisptr = new _MyClass()\n\n def __dealloc__(self):\n del self.thisptr\n\n def get_matrix(self):\n return ndarray(self.thisptr.get_matrix())\n```\n\nThis last line contains the actual conversion. Again, eigency has its\nown version of `ndarray`, that will take care of the conversion for\nyou.\n\nDue to limitations in Cython, Eigency cannot deal with full\nMatrix/Array template specifications as return types\n(e.g. `Matrix[double, 4, 2]`). However, as a workaround, you can use\n`PlainObjectBase` as a return type in such cases (or in all cases if\nyou prefer):\n\n```\n PlainObjectBase &get_matrix()\n```\n\n## Overriding default behavior\n\nThe `ndarray` conversion type specifier will attempt do guess whether you want a copy\nor a view, depending on the return type. Most of the time, this is\nprobably what you want. However, there might be cases where you want\nto override this behavior. For instance, functions returning const\nreferences will result in a copy of the array, since the const-ness\ncannot be enforced in Python. However, you can always override the\ndefault behavior by using the `ndarray_copy` or `ndarray_view`\nfunctions.\n\nExpanding the `MyClass` example from before:\n\n```c++\nclass MyClass {\npublic:\n ...\n const Eigen::MatrixXd &get_const_matrix() {\n return this->matrix;\n }\n ...\n};\n```\n\nWith the corresponding cython interface specification\nThe Cython C++ class interface is specified as usual:\n\n```\n cdef cppclass _MyClass \"MyClass\":\n ...\n const Matrix3d &get_const_matrix()\n```\n\nThe following would return a copy\n\n```python\ncdef class MyClass:\n ...\n def get_const_matrix(self):\n return ndarray(self.thisptr.get_const_matrix())\n```\n\nwhile the following would force it to return a view\n\n```python\ncdef class MyClass:\n ...\n def get_const_matrix(self):\n return ndarray_view(self.thisptr.get_const_matrix())\n```\n\n## Eigen to Numpy (non-reference return values)\n\nFunctions returning an Eigen object (not a reference), are specified\nin a similar way. For instance, given the following C++ function:\n\n```c++\nEigen::Matrix3d function_w_mat_retval();\n```\n\nThe Cython code could be written as:\n\n```\ncdef extern from \"functions.h\":\n cdef Matrix3d _function_w_mat_retval \"function_w_mat_retval\" ()\n\n# This will be exposed to Python\ndef function_w_mat_retval():\n return ndarray_copy(_function_w_mat_retval())\n```\n\nAs mentioned above, you can replace `Matrix3d` (or any other Eigen return type) with\n`PlainObjectBase`, which is especially relevant when working with\nEigen object that do not have an associated convenience typedef.\n\nNote that we use `ndarray_copy` instead of `ndarray` to explicitly\nstate that a copy should be made. In c++11 compliant compilers, it\nwill detect the rvalue reference and automatically make a copy even if\nyou just use `ndarray` (see next section), but to ensure that it works\nalso with older compilers it is recommended to always use\n`ndarray_copy` when returning newly constructed eigen values.\n\n\n## Corrupt data when returning non-map types\nThe tendency of Eigency to avoid copies whenever possible can lead\nto corrupted data when returning non-map Eigen arrays. For instance,\nin the `function_w_mat_retval` from the previous section, a temporary\nvalue will be returned from C++, and we have to take care to make\na copy of this data instead of letting the resulting numpy array\nrefer directly to this memory. In C++11, this situation can be\ndetected directly using rvalue references, and it will therefore\nautomatically make a copy: \n```\ndef function_w_mat_retval():\n # This works in C++11, because it detects the rvalue reference\n return ndarray(_function_w_mat_retval()) \n```\n\nHowever, to make sure it works with older compilers,\nit is recommended to use the `ndarray_copy` conversion:\n\n```\ndef function_w_mat_retval():\n # Explicit request for copy - this always works\n return ndarray_copy(_function_w_mat_retval()) \n```\n\n\n\n## Storage layout - why arrays are sometimes transposed\n\nThe default storage layout used in numpy and Eigen differ. Numpy uses\na row-major layout (C-style) per default while Eigen uses a\ncolumn-major layout (Fortran style) by default. In Eigency, we prioritize to\navoid copying of data whenever possible, which can have unexpected\nconsequences in some cases: There is no problem when passing values\nfrom C++ to Python - we just adjust the storage layout of the returned\nnumpy array to match that of Eigen. However, since the storage layout\nis encoded into the _type_ of the Eigen array (or the type of the\nMap), we cannot automatically change the layout in the Python to C++ direction. In\nEigency, we have therefore opted to return the transposed array/matrix\nin such cases. This provides the user with the flexibility to deal\nwith the problem either in Python (use order=\"F\" when constructing\nyour numpy array), or on the C++ side: (1) explicitly define your\nargument to have the row-major storage layout, 2) manually set the Map\nstride, or 3) just call `.transpose()` on the received\narray/matrix). \n\nAs an example, consider the case of a C++ function that both receives\nand returns a Eigen Map type, thus acting as a filter:\n\n```c++\nEigen::Map function_filter(Eigen::Map &mat) {\n return mat;\n}\n```\n\nThe Cython code could be:\n\n```\ncdef extern from \"functions.h\":\n ...\n cdef Map[ArrayXXd] &_function_filter1 \"function_filter1\" (Map[ArrayXXd] &)\n\ndef function_filter1(np.ndarray[np.float64_t, ndim=2] array):\n return ndarray(_function_filter1(Map[ArrayXXd](array)))\n\n```\n\nIf we call this function from Python in the standard way, we will\nsee that the array is transposed on the way from Python to C++, and\nremains that way when it is again returned to Python:\n\n```python\n>>> x = np.array([[1., 2., 3., 4.], [5., 6., 7., 8.]])\n>>> y = function_filter1(x)\n>>> print x\n[[ 1. 2. 3. 4.]\n [ 5. 6. 7. 8.]]\n>>> print y\n[[ 1. 5.]\n [ 2. 6.]\n [ 3. 7.]\n [ 4. 8.]]\n```\n\nThe simplest way to avoid this is to tell numpy to use a\ncolumn-major array layout instead of the default row-major\nlayout. This can be done using the order='F' option:\n\n```python\n>>> x = np.array([[1., 2., 3., 4.], [5., 6., 7., 8.]], order='F')\n>>> y = function_filter1(x)\n>>> print x\n[[ 1. 2. 3. 4.]\n [ 5. 6. 7. 8.]]\n>>> print y\n[[ 1. 2. 3. 4.]\n [ 5. 6. 7. 8.]]\n```\n\nThe other alternative is to tell Eigen to use RowMajor layout. This\nrequires changing the C++ function definition:\n\n```c++\ntypedef Eigen::Map > RowMajorArrayMap;\n\nRowMajorArrayMap &function_filter2(RowMajorArrayMap &mat) {\n return mat;\n}\n```\n\nTo write the corresponding Cython definition, we need the expanded version of\n`FlattenedMap` called `FlattenedMapWithOrder`, which allows us to specify\nthe storage order:\n\n```\ncdef extern from \"functions.h\":\n ...\n cdef PlainObjectBase _function_filter2 \"function_filter2\" (FlattenedMapWithOrder[Array, double, Dynamic, Dynamic, RowMajor])\n\ndef function_filter2(np.ndarray[np.float64_t, ndim=2] array):\n return ndarray(_function_filter2(FlattenedMapWithOrder[Array, double, Dynamic, Dynamic, RowMajor](array)))\n```\n\nAnother alternative is to keep the array itself in RowMajor format,\nbut use different stride values for the Map type:\n\n```c++\ntypedef Eigen::Map > CustomStrideMap;\n\nCustomStrideMap &function_filter3(CustomStrideMap &);\n```\n\nIn this case, in Cython, we need to use the even more extended\n`FlattenedMap` type called `FlattenedMapWithStride`, taking eight\narguments:\n\n```\ncdef extern from \"functions.h\":\n ...\n cdef PlainObjectBase _function_filter3 \"function_filter3\" (FlattenedMapWithStride[Array, double, Dynamic, Dynamic, ColMajor, Unaligned, _1, Dynamic])\n\ndef function_filter3(np.ndarray[np.float64_t, ndim=2] array):\n return ndarray(_function_filter3(FlattenedMapWithStride[Array, double, Dynamic, Dynamic, ColMajor, Unaligned, _1, Dynamic](array)))\n```\n\nIn all three cases, the returned array will now be of the same shape\nas the original.\n\n\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/wouterboomsma/eigency", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "eigency", "package_url": "https://pypi.org/project/eigency/", "platform": "", "project_url": "https://pypi.org/project/eigency/", "project_urls": { "Homepage": "https://github.com/wouterboomsma/eigency" }, "release_url": "https://pypi.org/project/eigency/1.77/", "requires_dist": null, "requires_python": "", "summary": "Cython interface between the numpy arrays and the Matrix/Array classes of the Eigen C++ library", "version": "1.77" }, "last_serial": 3593976, "releases": { "1.0": [], "1.1": [ { "comment_text": "", "digests": { "md5": "3751a5b2918b65830d85c2aa0bbba5a8", "sha256": "519ccf81186c44d836adfcc18613b8e9a43ad29d98d8294cd21e5ffea026645b" }, "downloads": -1, "filename": "eigency-1.1.tar.gz", "has_sig": false, "md5_digest": "3751a5b2918b65830d85c2aa0bbba5a8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1697372, "upload_time": "2016-04-11T14:59:43", "url": "https://files.pythonhosted.org/packages/1b/86/d02a296e80bc2d2efbbe684ad7e7d27f24273a253c40bb573b4cd08f5f9c/eigency-1.1.tar.gz" } ], "1.2": [ { "comment_text": "", "digests": { "md5": "9d8d6a8bd4fbeb3edcc2ac3d92b685c0", "sha256": "f5af37199f29ba67036e61f658b683e6f0c2f50f0b7127b6e83c9f107948895b" }, "downloads": -1, "filename": "eigency-1.2.tar.gz", "has_sig": false, "md5_digest": "9d8d6a8bd4fbeb3edcc2ac3d92b685c0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1513652, "upload_time": "2016-04-12T07:17:10", "url": "https://files.pythonhosted.org/packages/c1/ed/011d23204d0e691f77527bf74cabd5cae726cea2c67ab1244040a2b9760a/eigency-1.2.tar.gz" } ], "1.3": [ { "comment_text": "", "digests": { "md5": "b8f131ee451b75ec67097914f8dd1310", "sha256": "6b68868c64b0087acd63cc63cbcfa1ef276f760a59dea8d2acdc5e6e46153977" }, "downloads": -1, "filename": "eigency-1.3.tar.gz", "has_sig": false, "md5_digest": "b8f131ee451b75ec67097914f8dd1310", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1609756, "upload_time": "2016-04-18T20:12:02", "url": "https://files.pythonhosted.org/packages/98/11/a6cbce21d5770b60e2804f185ed01359e60e6953d98546514ee6a80d9651/eigency-1.3.tar.gz" } ], "1.4": [ { "comment_text": "", "digests": { "md5": "10cdea36a93662bb9d45972a70934165", "sha256": "9d6f353acbba62572545cb640398d66692574d02ee81ae9947f77584448e8f1d" }, "downloads": -1, "filename": "eigency-1.4.tar.gz", "has_sig": false, "md5_digest": "10cdea36a93662bb9d45972a70934165", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1513426, "upload_time": "2016-04-18T20:26:23", "url": "https://files.pythonhosted.org/packages/2f/9c/dbaf2609817811ba83f6e833d528532b0ba86a80170ef023fec5a8e38719/eigency-1.4.tar.gz" } ], "1.5": [ { "comment_text": "", "digests": { "md5": "a8579cb2ae6a61ec5b4ce4342033ad62", "sha256": "c55bbc1c3eb4718011b9661234a24a1097922e96493f08f6118657311147640c" }, "downloads": -1, "filename": "eigency-1.5.tar.gz", "has_sig": false, "md5_digest": "a8579cb2ae6a61ec5b4ce4342033ad62", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1516789, "upload_time": "2016-04-27T19:36:32", "url": "https://files.pythonhosted.org/packages/6f/29/5e3a14d9072743df1ba9c4377a1267b16592859b4090c22e94fb3fd50a2d/eigency-1.5.tar.gz" } ], "1.6": [ { "comment_text": "", "digests": { "md5": "b449a5c99edb864d5487066547b7cb3f", "sha256": "8d23832c5f2607dff1e5f6b21ec441a4877bd401191838406fe7d9778c58ab2c" }, "downloads": -1, "filename": "eigency-1.6.tar.gz", "has_sig": false, "md5_digest": "b449a5c99edb864d5487066547b7cb3f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1517526, "upload_time": "2016-04-30T18:54:39", "url": "https://files.pythonhosted.org/packages/cb/6b/fb16f132e57e04feeddcf4d91da08a25386502f0873da6601d5907809065/eigency-1.6.tar.gz" } ], "1.61": [ { "comment_text": "", "digests": { "md5": "90d555a850479331391e9728e2ae7e0d", "sha256": "9bccdfb32028c9ca5f8af641a5a2ba2977bf2fbbc9100cae7bc54fa77f492f12" }, "downloads": -1, "filename": "eigency-1.61.tar.gz", "has_sig": false, "md5_digest": "90d555a850479331391e9728e2ae7e0d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1517901, "upload_time": "2016-05-21T09:37:29", "url": "https://files.pythonhosted.org/packages/00/95/a89f75a7c84ca20ed67331811cbd834d286ace303d87765e9b442a70fe07/eigency-1.61.tar.gz" } ], "1.62": [ { "comment_text": "", "digests": { "md5": "706379b769b55502c9680b118df1cba8", "sha256": "caa8ca67e255e9742138c97e922377ae88e7c4f9c6453b563a75c422031b82eb" }, "downloads": -1, "filename": "eigency-1.62.tar.gz", "has_sig": false, "md5_digest": "706379b769b55502c9680b118df1cba8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1517525, "upload_time": "2016-06-23T06:26:39", "url": "https://files.pythonhosted.org/packages/5f/d5/c2a17e79fdb8ba657a5c7aa90d5271b936325365a7f09aac68ef639ee102/eigency-1.62.tar.gz" } ], "1.63": [ { "comment_text": "", "digests": { "md5": "7d557bd377517cc3339906cae04ba695", "sha256": "2b5ad8f331d29b43cdff082526ba44387877613f3e67dc4ebaa721556bf0d5fc" }, "downloads": -1, "filename": "eigency-1.63.tar.gz", "has_sig": false, "md5_digest": "7d557bd377517cc3339906cae04ba695", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1517544, "upload_time": "2016-06-23T09:24:08", "url": "https://files.pythonhosted.org/packages/7b/e4/4f98b2f26154e42ab59f389f3d9d17d8bae886c982d2e18136d88da987eb/eigency-1.63.tar.gz" } ], "1.64": [ { "comment_text": "", "digests": { "md5": "8b580584a61310aee9086927d5069455", "sha256": "d4655d10eb9fd718fce84689b437208be391e6d6130d69e4fdd245a34b7cbd80" }, "downloads": -1, "filename": "eigency-1.64.tar.gz", "has_sig": false, "md5_digest": "8b580584a61310aee9086927d5069455", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1517456, "upload_time": "2016-06-23T09:32:44", "url": "https://files.pythonhosted.org/packages/c7/6d/378903a3b6ecd1bc2497b2bf5d01e728e1358aa2c9029e8bf1f3696ffec5/eigency-1.64.tar.gz" } ], "1.65": [ { "comment_text": "", "digests": { "md5": "e5be40e6e38049b1feb13adda174797c", "sha256": "f3ad05f862b202a5decfb84454e73f3ecac4211a9a7a2a0dce47990d1c19b230" }, "downloads": -1, "filename": "eigency-1.65.tar.gz", "has_sig": false, "md5_digest": "e5be40e6e38049b1feb13adda174797c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1517530, "upload_time": "2016-06-29T12:51:18", "url": "https://files.pythonhosted.org/packages/30/8c/7fb93652aa03bafe620ea0d26ffced61a4ce34c2a20da73bfd4017fcc665/eigency-1.65.tar.gz" } ], "1.66": [ { "comment_text": "", "digests": { "md5": "f75f8486f380e746a9be21b01b57dafe", "sha256": "151aa3b4b10b4041046d5e250936ea5d97f969ac22160b9206a88424ed2bc298" }, "downloads": -1, "filename": "eigency-1.66.tar.gz", "has_sig": false, "md5_digest": "f75f8486f380e746a9be21b01b57dafe", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1518217, "upload_time": "2016-07-23T11:35:27", "url": "https://files.pythonhosted.org/packages/c7/ab/e02c66afabc3c8d189c3644ea16e60445af97a355977dacb9ef50796f935/eigency-1.66.tar.gz" } ], "1.68": [ { "comment_text": "", "digests": { "md5": "496e5db0eeb4caa59c090c29277a0edf", "sha256": "78543d8748fdcb11e21bdf2659851e5fcb3d76e9ef16f761cd4b5ddb4ff7f287" }, "downloads": -1, "filename": "eigency-1.68.tar.gz", "has_sig": false, "md5_digest": "496e5db0eeb4caa59c090c29277a0edf", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1630173, "upload_time": "2016-09-14T07:13:08", "url": "https://files.pythonhosted.org/packages/1b/78/0d46045d42f9303b8cb0f4f87f17d7c65b0c626ffd6f0c7a7d6e3b92294c/eigency-1.68.tar.gz" } ], "1.69": [ { "comment_text": "", "digests": { "md5": "f6863401e3e7b4424aa8a6f8686fe943", "sha256": "4cfb47c1b1e482047a5279c84f20c79f3ee1bbaebe418f63f3cd72267fcd1e41" }, "downloads": -1, "filename": "eigency-1.69.tar.gz", "has_sig": false, "md5_digest": "f6863401e3e7b4424aa8a6f8686fe943", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1629693, "upload_time": "2016-10-11T21:45:51", "url": "https://files.pythonhosted.org/packages/bd/24/0ae0a41e81618b3d5590ac527187eef7dbe4d870fb4f0ca92da219c8f178/eigency-1.69.tar.gz" } ], "1.70": [ { "comment_text": "", "digests": { "md5": "21f333a20e7f2734f1da8ac477cac7f0", "sha256": "c1a9313abf07a19ab3789c4cd725ffec17137c87d638f9f5b6644c0de5e61890" }, "downloads": -1, "filename": "eigency-1.70.tar.gz", "has_sig": false, "md5_digest": "21f333a20e7f2734f1da8ac477cac7f0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1630143, "upload_time": "2016-10-11T22:06:16", "url": "https://files.pythonhosted.org/packages/99/2d/51004c7d6aa9581404cbcd4b5e4efb277e9511755feee49cf275fb141478/eigency-1.70.tar.gz" } ], "1.71": [ { "comment_text": "", "digests": { "md5": "fb37fe284ce8316064eb5e007bbe1358", "sha256": "b8f5edd9c53f05fcd4989a356615f1405abc547add480dc3f4e34698ac8c3158" }, "downloads": -1, "filename": "eigency-1.71.tar.gz", "has_sig": false, "md5_digest": "fb37fe284ce8316064eb5e007bbe1358", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1630208, "upload_time": "2016-11-03T15:18:21", "url": "https://files.pythonhosted.org/packages/4b/0b/4aefbbbc78e6b6bf7e686a2b2b042bf77480b890f20e8b96457bd2661764/eigency-1.71.tar.gz" } ], "1.72": [ { "comment_text": "", "digests": { "md5": "02965caf913a8291c468da84a696d07f", "sha256": "dc7a470e1dbdbdd294c1694bf2751f4f488d245dbd66f13714e83a73b8682b72" }, "downloads": -1, "filename": "eigency-1.72.tar.gz", "has_sig": false, "md5_digest": "02965caf913a8291c468da84a696d07f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1642924, "upload_time": "2017-03-06T23:55:35", "url": "https://files.pythonhosted.org/packages/e3/fc/47ba8b8a433e3323c735faf680bd3a689913bbce88cd382dd3cb0201ed9f/eigency-1.72.tar.gz" } ], "1.73": [ { "comment_text": "", "digests": { "md5": "f5be85d6575e8d38cf5f839d7953ec4f", "sha256": "54474de512e0c802968b0718dfaacc9710e1f89918c1986d294749ace5189242" }, "downloads": -1, "filename": "eigency-1.73.tar.gz", "has_sig": false, "md5_digest": "f5be85d6575e8d38cf5f839d7953ec4f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1638552, "upload_time": "2017-03-20T22:28:07", "url": "https://files.pythonhosted.org/packages/1b/23/358c80a7e780f3c224c6335e7b685843fed0fbd1efda0a5f37aca427e785/eigency-1.73.tar.gz" } ], "1.74": [ { "comment_text": "", "digests": { "md5": "460575838955a06496a5629ee33c0a0d", "sha256": "8cb4991d8b8ac2093a9e54d37bb5747f6305b6e90fdbc0fde97aeac165e03d9c" }, "downloads": -1, "filename": "eigency-1.74.tar.gz", "has_sig": false, "md5_digest": "460575838955a06496a5629ee33c0a0d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20891, "upload_time": "2017-03-30T08:24:45", "url": "https://files.pythonhosted.org/packages/9a/46/db59a9c09b3b4f684917edb58f24daef49463b25811989156984b8147279/eigency-1.74.tar.gz" } ], "1.75": [ { "comment_text": "", "digests": { "md5": "c85c97925e9b1fdfc6ed20897298f407", "sha256": "2136439a9300641282c1871af88c0806e14967201aa0ada55490e8d60c405537" }, "downloads": -1, "filename": "eigency-1.75.tar.gz", "has_sig": false, "md5_digest": "c85c97925e9b1fdfc6ed20897298f407", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 666157, "upload_time": "2017-04-05T20:11:00", "url": "https://files.pythonhosted.org/packages/55/a0/f6101aa64eb3840a2ca853dea2f8995e44a1a7633c5a70dce2b2672db019/eigency-1.75.tar.gz" } ], "1.76": [ { "comment_text": "", "digests": { "md5": "3083f0bab44dd9934facc2d55260380a", "sha256": "b5008d8b502d0ecdafbc6c288a98c24d098e594e3cb06a260fe070accf40a148" }, "downloads": -1, "filename": "eigency-1.76.tar.gz", "has_sig": false, "md5_digest": "3083f0bab44dd9934facc2d55260380a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 675333, "upload_time": "2018-02-16T16:23:40", "url": "https://files.pythonhosted.org/packages/bc/bf/030ed2136c49a7753a9cc11be7454e16de1977f23ce1cff5fe5427579c2e/eigency-1.76.tar.gz" } ], "1.77": [ { "comment_text": "", "digests": { "md5": "dad53f1975e99810925c3f691e29b092", "sha256": "13cf96e00020fd900aa5f8905036488afd27c89212bfc07b60ac5412073ea7d7" }, "downloads": -1, "filename": "eigency-1.77.tar.gz", "has_sig": false, "md5_digest": "dad53f1975e99810925c3f691e29b092", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 678511, "upload_time": "2018-02-18T19:17:13", "url": "https://files.pythonhosted.org/packages/fb/6e/bc4359fbfb0bb0b588ec328251b0d0836bdd7c0a4c568959ea06df023e18/eigency-1.77.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "dad53f1975e99810925c3f691e29b092", "sha256": "13cf96e00020fd900aa5f8905036488afd27c89212bfc07b60ac5412073ea7d7" }, "downloads": -1, "filename": "eigency-1.77.tar.gz", "has_sig": false, "md5_digest": "dad53f1975e99810925c3f691e29b092", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 678511, "upload_time": "2018-02-18T19:17:13", "url": "https://files.pythonhosted.org/packages/fb/6e/bc4359fbfb0bb0b588ec328251b0d0836bdd7c0a4c568959ea06df023e18/eigency-1.77.tar.gz" } ] }