{ "info": { "author": "Ilya Lebedev", "author_email": "melevir@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Console", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "# mr. Proper\n\n[![Build Status](https://travis-ci.org/best-doctor/mr_proper.svg?branch=master)](https://travis-ci.org/best-doctor/mr_proper)\n[![PyPI version](https://badge.fury.io/py/mr-proper.svg)](https://badge.fury.io/py/mr-proper)\n[![Maintainability](https://api.codeclimate.com/v1/badges/4b2234d95d5c4944e2e6/maintainability)](https://codeclimate.com/github/best-doctor/mr_proper/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/4b2234d95d5c4944e2e6/test_coverage)](https://codeclimate.com/github/best-doctor/mr_proper/test_coverage)\n\nStatic Python code analyzer, that tries to check if functions in code are\n[pure](https://en.wikipedia.org/wiki/Pure_function) or not and why.\n\n![Have fun with mr Clean](https://raw.githubusercontent.com/best-doctor/mr_proper/master/docs_img/mr_clean_sponge.jpg)\n\n*DISCLAIMER*: this library is very experimental and has a lot of edge cases.\nFunctions that mr. Proper marks as pure can be not pure, but they are\nusually cleaner than other functions.\n\n## Installation\n\n```bash\npip install mr_proper\n```\n\n## What mr. Proper check\n\n1. that function has no blacklisted calls (like `print`)\n and blacklisted attributes access (like `smth.count`);\n1. that function not uses global objects (only local vars and function arguments);\n1. that function has al least one return;\n1. that function not mutates it's arguments;\n1. that function has no local imports;\n1. that function has no arguments of forbidden types (like ORM objects);\n1. that function not uses `self`, `class` or `super`;\n1. that function has calls of only pure functions.\n\nThis list is not enought to say that function is pure and some points\nare quite controversial, but it's a nice start.\n\n## Example\n\nConsole usage:\n\n```python\n # test.py\n def add_one(n: int) -> int:\n return n + 1\n\n def print_amount_of_users(users_qs: QuerySet) -> None:\n print(f'Current amount of users is {users_qs.count()}')\n```\n\n```bash\n$ mr_propper test.py\nadd_one is pure!\nprint_amount_of_users is not pure because of:\n it uses forbidden argument types (QuerySet)\n it calls not pure functions (print)\n it has no return\n```\n\nUsage inside Python code sample:\n\n```jupyterpython\n>>> import ast\n>>> from mr_propper.utils import is_function_pure\n>>> funcdef = ast.parse('''\n def add_one(n: int) -> int:\n return n + 1\n''').body[0]\n>>> is_function_pure(funcdef)\nTrue\n>>> is_function_pure(funcdef, with_errors=True)\n(True, [])\n```\n\n## Parameters\n\nCLI interface:\n\n- `filepath`: path to .py file to check (directories are not supported for now);\n- `--recursive`: require inner calls to be pure for function pureness.\n\n## Code prerequisites\n\n1. Python 3.7+;\n1. Functions are fully type-annotated;\n1. No dynamic calls (like `getattr(sender, 'send_' + message_type)(message)`).\n\n## Contributing\n\nWe would love you to contribute to our project. It's simple:\n\n1. Create an issue with bug you found or proposal you have.\n Wait for approve from maintainer.\n1. Create a pull request. Make sure all checks are green.\n1. Fix review comments if any.\n1. Be awesome.\n\nHere are useful tips:\n\n- You can run all checks and tests with `make check`.\n Please do it before TravisCI does.\n- We use [BestDoctor python styleguide](https://github.com/best-doctor/guides/blob/master/guides/en/python_styleguide.md).\n- We respect [Django CoC](https://www.djangoproject.com/conduct/).\n Make soft, not bullshit.\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/best-doctor/mr_proper", "keywords": "static-analyzer,pure-function", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "mr-proper", "package_url": "https://pypi.org/project/mr-proper/", "platform": "", "project_url": "https://pypi.org/project/mr-proper/", "project_urls": { "Homepage": "https://github.com/best-doctor/mr_proper" }, "release_url": "https://pypi.org/project/mr-proper/0.0.7/", "requires_dist": [ "click (>=7.1.2)", "setuptools", "stdlib-list (>=0.5.0)", "typing-extensions (>=3.7.4.3) ; python_version < \"3.8\"" ], "requires_python": "", "summary": "Static Python code analyzer, that tries to check if functions in code are pure or not and why.", "version": "0.0.7", "yanked": false, "yanked_reason": null }, "last_serial": 11846392, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "b4e6a918871418e6b5e368f33b3dbd87", "sha256": "337caadb26ef9d159fe319cdef987b75eda826b013f4911b92bb37b4248028bb" }, "downloads": -1, "filename": "mr_proper-0.0.1.tar.gz", "has_sig": false, "md5_digest": "b4e6a918871418e6b5e368f33b3dbd87", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7929, "upload_time": "2019-10-27T19:13:38", "upload_time_iso_8601": "2019-10-27T19:13:38.937443Z", "url": "https://files.pythonhosted.org/packages/4e/49/80ebc65e1c92fdaf575b54b25996b251d7f200cbbf57dd4a74cdf254243f/mr_proper-0.0.1.tar.gz", "yanked": false, "yanked_reason": null } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "61a6c69caae7a22649cedfbd02fc1ee6", "sha256": "c334c52735ae2cd07aad2af9a17df66a2d36f41a629bcdcb1dbdcd3f5609f6a5" }, "downloads": -1, "filename": "mr_proper-0.0.2.tar.gz", "has_sig": false, "md5_digest": "61a6c69caae7a22649cedfbd02fc1ee6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8581, "upload_time": "2019-11-15T10:44:28", "upload_time_iso_8601": "2019-11-15T10:44:28.847322Z", "url": "https://files.pythonhosted.org/packages/90/6a/3d4691af116e0d60b59e2eb221f6de30b51b55b7fe66804e6bea04ab6245/mr_proper-0.0.2.tar.gz", "yanked": false, "yanked_reason": null } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "fe8b8355daa32f6fd0657164131d70e8", "sha256": "275cdcba4b3b99de8f583b010189e45ccaa7cce168481d0a3e442864b2a5e770" }, "downloads": -1, "filename": "mr_proper-0.0.3.tar.gz", "has_sig": false, "md5_digest": "fe8b8355daa32f6fd0657164131d70e8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8582, "upload_time": "2019-11-15T10:47:18", "upload_time_iso_8601": "2019-11-15T10:47:18.922195Z", "url": "https://files.pythonhosted.org/packages/9d/eb/2dd98819d9344b9c316826b6fa9c5ed3c7887fdda8df43c8fd2388ba30d9/mr_proper-0.0.3.tar.gz", "yanked": false, "yanked_reason": null } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "92b4e0d6c033a2b7689e3063cb39d707", "sha256": "866df6f5cfdf55c643cf75a0c9c2eb05e26d9e717160cca24e89bbce28bd6701" }, "downloads": -1, "filename": "mr_proper-0.0.4.tar.gz", "has_sig": false, "md5_digest": "92b4e0d6c033a2b7689e3063cb39d707", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8595, "upload_time": "2019-12-16T12:01:21", "upload_time_iso_8601": "2019-12-16T12:01:21.728433Z", "url": "https://files.pythonhosted.org/packages/ef/b3/b211ade4edd86a16067899a3487bf92cc0ae00f98a92549e7dad29973dc9/mr_proper-0.0.4.tar.gz", "yanked": false, "yanked_reason": null } ], "0.0.5": [ { "comment_text": "", "digests": { "md5": "dd9408ae4bbe5e35dc88fc734d2925cf", "sha256": "35a4bb4bbb8d706fbac75a29488c26dcfca4757e05c9ba6004d76c40e5c69815" }, "downloads": -1, "filename": "mr_proper-0.0.5.tar.gz", "has_sig": false, "md5_digest": "dd9408ae4bbe5e35dc88fc734d2925cf", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9321, "upload_time": "2020-05-06T06:06:02", "upload_time_iso_8601": "2020-05-06T06:06:02.929329Z", "url": "https://files.pythonhosted.org/packages/4c/51/724885f72873fcf2abdec2a6b73b2b428ebd488b29162ac473b235cfa89e/mr_proper-0.0.5.tar.gz", "yanked": false, "yanked_reason": null } ], "0.0.6": [ { "comment_text": "", "digests": { "md5": "6d49c33422e794c3c17dd5770756498d", "sha256": "12da55d81f04dd0e8ede6f8a1d76e6e5026d3f758b7942c8c215e07d86227bd1" }, "downloads": -1, "filename": "mr_proper-0.0.6.tar.gz", "has_sig": false, "md5_digest": "6d49c33422e794c3c17dd5770756498d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10420, "upload_time": "2021-01-14T14:38:10", "upload_time_iso_8601": "2021-01-14T14:38:10.807066Z", "url": "https://files.pythonhosted.org/packages/7a/10/e9acc83bf14078f6479e28037a54a551d6f24fc9057264620461adbc3072/mr_proper-0.0.6.tar.gz", "yanked": false, "yanked_reason": null } ], "0.0.7": [ { "comment_text": "", "digests": { "md5": "2d55f8fa5a3e495d140a1a4f103797bd", "sha256": "74a1b60240c46f10ba518707ef72811a01e5c270da0a78b5dd2dd923d99fdb14" }, "downloads": -1, "filename": "mr_proper-0.0.7-py3-none-any.whl", "has_sig": false, "md5_digest": "2d55f8fa5a3e495d140a1a4f103797bd", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 11537, "upload_time": "2021-10-27T13:06:01", "upload_time_iso_8601": "2021-10-27T13:06:01.852589Z", "url": "https://files.pythonhosted.org/packages/e5/b0/2b19f1c38cc1ff29af21c1851c1160cfb185d4516834a37b7227d7df01b2/mr_proper-0.0.7-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "a74978c0e0059ee1c2582cf9884d5cd8", "sha256": "03b517b19e617537f711ce418b125e5f2efd82ec881539cdee83195c78c14a02" }, "downloads": -1, "filename": "mr_proper-0.0.7.tar.gz", "has_sig": false, "md5_digest": "a74978c0e0059ee1c2582cf9884d5cd8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11028, "upload_time": "2021-10-27T13:06:03", "upload_time_iso_8601": "2021-10-27T13:06:03.309589Z", "url": "https://files.pythonhosted.org/packages/e3/35/a50ba9e3097ee0d71232c996c626a17f80424140b365122c8f1bc9933118/mr_proper-0.0.7.tar.gz", "yanked": false, "yanked_reason": null } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "2d55f8fa5a3e495d140a1a4f103797bd", "sha256": "74a1b60240c46f10ba518707ef72811a01e5c270da0a78b5dd2dd923d99fdb14" }, "downloads": -1, "filename": "mr_proper-0.0.7-py3-none-any.whl", "has_sig": false, "md5_digest": "2d55f8fa5a3e495d140a1a4f103797bd", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 11537, "upload_time": "2021-10-27T13:06:01", "upload_time_iso_8601": "2021-10-27T13:06:01.852589Z", "url": "https://files.pythonhosted.org/packages/e5/b0/2b19f1c38cc1ff29af21c1851c1160cfb185d4516834a37b7227d7df01b2/mr_proper-0.0.7-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "a74978c0e0059ee1c2582cf9884d5cd8", "sha256": "03b517b19e617537f711ce418b125e5f2efd82ec881539cdee83195c78c14a02" }, "downloads": -1, "filename": "mr_proper-0.0.7.tar.gz", "has_sig": false, "md5_digest": "a74978c0e0059ee1c2582cf9884d5cd8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11028, "upload_time": "2021-10-27T13:06:03", "upload_time_iso_8601": "2021-10-27T13:06:03.309589Z", "url": "https://files.pythonhosted.org/packages/e3/35/a50ba9e3097ee0d71232c996c626a17f80424140b365122c8f1bc9933118/mr_proper-0.0.7.tar.gz", "yanked": false, "yanked_reason": null } ], "vulnerabilities": [] }