{"action":"created","issue":{"url":"https://api.github.com/repos/pyinstaller/pyinstaller/issues/1561","labels_url":"https://api.github.com/repos/pyinstaller/pyinstaller/issues/1561/labels{/name}","comments_url":"https://api.github.com/repos/pyinstaller/pyinstaller/issues/1561/comments","events_url":"https://api.github.com/repos/pyinstaller/pyinstaller/issues/1561/events","html_url":"https://github.com/pyinstaller/pyinstaller/pull/1561","id":109240911,"number":1561,"title":"Robust Module Version Comparisons ~ Redux Redux","user":{"login":"leycec","id":217028,"avatar_url":"https://avatars.githubusercontent.com/u/217028?v=3","gravatar_id":"","url":"https://api.github.com/users/leycec","html_url":"https://github.com/leycec","followers_url":"https://api.github.com/users/leycec/followers","following_url":"https://api.github.com/users/leycec/following{/other_user}","gists_url":"https://api.github.com/users/leycec/gists{/gist_id}","starred_url":"https://api.github.com/users/leycec/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/leycec/subscriptions","organizations_url":"https://api.github.com/users/leycec/orgs","repos_url":"https://api.github.com/users/leycec/repos","events_url":"https://api.github.com/users/leycec/events{/privacy}","received_events_url":"https://api.github.com/users/leycec/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/pyinstaller/pyinstaller/labels/hooks","name":"hooks","color":"fef2c0"}],"state":"closed","locked":false,"assignee":{"login":"htgoebel","id":784161,"avatar_url":"https://avatars.githubusercontent.com/u/784161?v=3","gravatar_id":"","url":"https://api.github.com/users/htgoebel","html_url":"https://github.com/htgoebel","followers_url":"https://api.github.com/users/htgoebel/followers","following_url":"https://api.github.com/users/htgoebel/following{/other_user}","gists_url":"https://api.github.com/users/htgoebel/gists{/gist_id}","starred_url":"https://api.github.com/users/htgoebel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/htgoebel/subscriptions","organizations_url":"https://api.github.com/users/htgoebel/orgs","repos_url":"https://api.github.com/users/htgoebel/repos","events_url":"https://api.github.com/users/htgoebel/events{/privacy}","received_events_url":"https://api.github.com/users/htgoebel/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/pyinstaller/pyinstaller/milestones/11","html_url":"https://github.com/pyinstaller/pyinstaller/milestones/PyInstaller%203.1","labels_url":"https://api.github.com/repos/pyinstaller/pyinstaller/milestones/11/labels","id":1290827,"number":11,"title":"PyInstaller 3.1","description":"* close all feature- and enhancement-requests known at the time 3.0 was released\r\n* clean up the code base (which seams to be necessary after integrating modulegraph)\r\n* update manual and explain better how !PyInstaller works internally.","creator":{"login":"htgoebel","id":784161,"avatar_url":"https://avatars.githubusercontent.com/u/784161?v=3","gravatar_id":"","url":"https://api.github.com/users/htgoebel","html_url":"https://github.com/htgoebel","followers_url":"https://api.github.com/users/htgoebel/followers","following_url":"https://api.github.com/users/htgoebel/following{/other_user}","gists_url":"https://api.github.com/users/htgoebel/gists{/gist_id}","starred_url":"https://api.github.com/users/htgoebel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/htgoebel/subscriptions","organizations_url":"https://api.github.com/users/htgoebel/orgs","repos_url":"https://api.github.com/users/htgoebel/repos","events_url":"https://api.github.com/users/htgoebel/events{/privacy}","received_events_url":"https://api.github.com/users/htgoebel/received_events","type":"User","site_admin":false},"open_issues":0,"closed_issues":120,"state":"open","created_at":"2015-09-04T16:32:45Z","updated_at":"2016-01-04T07:09:49Z","due_on":"2015-12-30T23:00:00Z","closed_at":null},"comments":14,"created_at":"2015-10-01T06:52:49Z","updated_at":"2016-01-04T18:39:46Z","closed_at":"2015-12-18T22:15:45Z","pull_request":{"url":"https://api.github.com/repos/pyinstaller/pyinstaller/pulls/1561","html_url":"https://github.com/pyinstaller/pyinstaller/pull/1561","diff_url":"https://github.com/pyinstaller/pyinstaller/pull/1561.diff","patch_url":"https://github.com/pyinstaller/pyinstaller/pull/1561.patch"},"body":"This pull request completes my [previously incomplete pull request](https://github.com/pyinstaller/pyinstaller/pull/1373).\r\n\r\nLike that request, this request refactors the `is_module_version()` hook helper to behave more sensibly. Unlike that request, this request provides additional support for validating whether a module satisfies multiple constraints – including both versions _and_ extras (i.e., optional install-time features). Hence, this helper has been renamed to `is_module_satisfies()`.\r\n\r\nUnrelatedly, the docstring for the `get_pywin32_module_file_attribute()` hook helper was a confusing lie. That's been fixed, too.\r\n\r\n## Help-a Me Help-a You\r\n\r\nAs consensus (rightfully) demanded, the `is_module_satisfies()` helper now accepts three parameters:\r\n\r\n1. A mandatory `setuptools`-formatted requirements string (e.g., `some_module_name[some_feature] < 1.6, > 1.9, != 1.9.6, < 2.0a0, == 2.4c1`). Courtesy `setuptools`, complex magic is now feasible. **Rejoice!**\r\n1. An optional PEP 0440-compliant version (e.g., `3.14-rc5`) to be used  _instead_ of the current version of the desired module. This permits arbitrary versions originating from odd sources to be compared. See `hook-PyQt5` for a useful example.\r\n1. The optional name of the version attribute defined by the desired module, defaulting to `__version__`. Since we prefer `setuptools` machinery to manually querying modules, this is a fallback in the event that this module was _not_ installed by `pip` or `easy_install`. (In other words, mostly ignorable.)\r\n\r\n## Examples or the Little Puppy Gets It\r\n\r\nUsage is (hopefully) simple. For most purposes, the optional parameters are ignorable. To illustrate this, assume that PIL 2.9.0, Sphinx 1.3.1, and SQLAlchemy 0.6 are all locally installed:\r\n\r\n        >>> from PyInstaller.util.hooks import is_module_satisfies\r\n        >>> is_module_satisfies('sphinx >= 1.3.1, < 1.3.2')\r\n        True\r\n        >>> is_module_satisfies('sqlalchemy != 0.6')\r\n        False\r\n\r\n        # Compare two arbitrary versions. In this case, the module name\r\n        # \"sqlalchemy\" is simply ignored.\r\n        >>> is_module_satisfies('sqlalchemy != 0.6', version='0.5')\r\n        True\r\n\r\n        # Since the \"pillow\" project providing PIL publishes its version via\r\n        # the custom \"PILLOW_VERSION\" attribute (rather than the standard\r\n        # \"__version__\" attribute), an attribute name is passed as a fallback\r\n        # to validate PIL when not installed by setuptools. As PIL is usually\r\n        # installed by setuptools, this optional parameter is usually ignored.\r\n        >>> is_module_satisfies('PIL == 2.9.0', version_attr='PILLOW_VERSION')\r\n        True\r\n\r\n## Will Anyone Actually Use This?\r\n\r\nI can't answer that. I can tell you, however, that the following hooks all call `is_module_satisfies()` now:\r\n\r\n* `hook-PyQt5`.\r\n* `hook-sphinx`.\r\n* `hook-sqlalchemy`.\r\n\r\nTo support SciPy >= 0.15.I, I have plans to add a new `hook-scipy` _also_ calling `is_module_satisfies()`. It's overwhelming popularity grows day by day. :clap: \r\n\r\nIn closing, another Ultraman kaiju! _What is this thing._\r\n\r\n![No idea, folks.](https://i1.ytimg.com/vi/1n5AAjc6grQ/maxresdefault.jpg)"},"comment":{"url":"https://api.github.com/repos/pyinstaller/pyinstaller/issues/comments/168763142","html_url":"https://github.com/pyinstaller/pyinstaller/pull/1561#issuecomment-168763142","issue_url":"https://api.github.com/repos/pyinstaller/pyinstaller/issues/1561","id":168763142,"user":{"login":"bjones1","id":2125584,"avatar_url":"https://avatars.githubusercontent.com/u/2125584?v=3","gravatar_id":"","url":"https://api.github.com/users/bjones1","html_url":"https://github.com/bjones1","followers_url":"https://api.github.com/users/bjones1/followers","following_url":"https://api.github.com/users/bjones1/following{/other_user}","gists_url":"https://api.github.com/users/bjones1/gists{/gist_id}","starred_url":"https://api.github.com/users/bjones1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bjones1/subscriptions","organizations_url":"https://api.github.com/users/bjones1/orgs","repos_url":"https://api.github.com/users/bjones1/repos","events_url":"https://api.github.com/users/bjones1/events{/privacy}","received_events_url":"https://api.github.com/users/bjones1/received_events","type":"User","site_admin":false},"created_at":"2016-01-04T18:39:46Z","updated_at":"2016-01-04T18:39:46Z","body":"I did post on Enki in PyQt. I'll let you know when I can get the Mac Pyinstaller binary ready..."}}