# -*- coding: utf-8 -*-
from distutils.core import setup

packages = \
['flake8_pie']

package_data = \
{'': ['*'], 'flake8_pie': ['tests/*']}

install_requires = \
['typing_extensions']

entry_points = \
{'flake8.extension': ['PIE = flake8_pie:Flake8PieCheck']}

setup_kwargs = {
    'name': 'flake8-pie',
    'version': '0.13.0',
    'description': 'A flake8 extension that implements misc. lints',
    'long_description': '# flake8-pie [![CircleCI](https://circleci.com/gh/sbdchd/flake8-pie.svg?style=svg)](https://circleci.com/gh/sbdchd/flake8-pie) [![pypi](https://img.shields.io/pypi/v/flake8-pie.svg)](https://pypi.org/project/flake8-pie/)\n\n> A flake8 extension that implements misc. lints\n\n## lints\n\n### PIE781: assign-and-return\n\nBased on Clippy\'s\n[`let_and_return`](https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return)\nand Microsoft\'s TSLint rule\n[`no-unnecessary-local-variable`](https://github.com/Microsoft/tslint-microsoft-contrib).\n\nFor more info on the structure of this lint, see the [accompanying blog\npost](https://steve.dignam.xyz/2018/12/16/creating-a-flake8-lint/).\n\n#### examples\n\n```python\n# error\ndef foo():\n   x = bar()\n   return x\n\n# allowed\ndef foo():\n   x, _ = bar()\n   return x\n```\n\n### PIE783: celery-explicit-names\n\nWarn about [Celery](https://pypi.org/project/celery/) task definitions that don\'t have explicit names.\n\nNote: this lint is kind of naive considering any decorator with a `.task()`\nmethod or any decorator called `shared_task()` a Celery decorator.\n\n#### examples\n\n```python\n# error\n@app.task()\ndef foo():\n    pass\n\n# ok\n@app.task(name="app_name.tasks.foo")\ndef foo():\n    pass\n```\n\n### PIE784: celery-explicit-crontab-args\n\nThe `crontab` class provided by Celery has some default args that are\nsuprising to new users. Specifically, `crontab(hour="0,12")` won\'t run a task\nat midnight and noon, it will run the task at every minute during those two\nhours. This lint makes that call an error, forcing you to write\n`crontab(hour="0, 12", minute="*")`.\n\nAdditionally, the lint is a bit more complex in that it requires you specify\nevery smaller increment than the largest time increment you provide. So if you\nprovide `days_of_week`, then you need to provide `hour`s and `minute`s\nexplicitly.\n\nNote: if you like the default behavior of `crontab()` then you can either\ndisable this lint or pass `"*"` for the `kwarg` value, e.g., `minutes="*"`.\n\nAlso, since this lint is essentially a naive search for calls to a\n`crontab()` function, if you have a function named the same then this will\ncause false positives.\n\n### PIE785: celery-require-tasks-expire\n\nCelery tasks can bunch up if they don\'t have expirations.\n\nThis enforces specifying expirations in both the celery beat config dict and\nin `.apply_async()` calls.\n\nThe same caveat applies about how this lint is naive.\n\n### PIE786: precise-exception-handlers\n\nBe precise in what exceptions you catch. Bare `except:` handlers, catching `BaseException`, or catching `Exception` can lead to unexpected bugs.\n\n#### examples\n\n```python\n# error\ntry:\n    save_file(name="export.csv")\nexcept:\n    pass\n\n# error\ntry:\n    save_file(name="export.csv")\nexcept BaseException:\n    pass\n\n# error\ntry:\n    save_file(name="export.csv")\nexcept Exception:\n    pass\n\n# error\ntry:\n    save_file(name="export.csv")\nexcept (ValueError, Exception):\n    pass\n\n\n# ok\ntry:\n    save_file(name="export.csv")\nexcept OSError:\n    pass\n```\n\n### PIE787: no-len-condition\n\nEmpty collections are fasley in Python so calling `len()` is unnecessary when\nchecking for emptiness in an if statement/expression.\n\nComparing to explicit scalars is allowed.\n\n```python\n# error\nif len(foo): ...\nif not len(foo): ...\n\n# ok\nif foo: ...\nif not foo: ...\nif len(foo) > 0: ...\nif len(foo) == 0: ...\n```\n\n### PIE788: no-bool-condition\n\nIf statements/expressions evalute the truthiness of the their test argument,\nso calling `bool()` is unnecessary.\n\nComparing to `True`/`False` is allowed.\n\n```python\n# error\nif bool(foo): ...\nif not bool(foo): ...\n\n# ok\nif foo: ...\nif not foo: ...\nif bool(foo) is True: ...\nif bool(foo) is False: ...\n```\n\n### PIE789: prefer-isinstance-type-compare\n\nUsing `type()` doesn\'t take into account subclassess and type checkers won\'t\nrefine the type, use `isinstance` instead.\n\n```python\n# error\nif type(foo) == str: ...\nif type(foo) is str: ...\nif type(foo) in [int, str]: ...\n\n# ok\nif isinstance(foo, str): ...\nif isinstance(foo, (int, str)): ...\n```\n\n### PIE790: no-unnecessary-pass\n\n`pass` is unnecessary when definining a `class` or function with an empty\nbody.\n\n```python\n# error\nclass BadError(Exception):\n    """\n    some doc comment\n    """\n    pass\n\ndef foo() -> None:\n    """\n    some function\n    """\n    pass\n\n# ok\nclass BadError(Exception):\n    """\n    some doc comment\n    """\n\ndef foo() -> None:\n    """\n    some function\n    """\n```\n\n### PIE791: no-pointless-statements\n\nComparisions without an assignment or assertion are probably a typo.\n\n```python\n# error\n"foobar" in data\nres.json() == []\nuser.is_authenticated() is True\n\n# ok\nassert "foobar" in data\nfoo = res.json() == []\nuse.is_authenticated()\n```\n\n### PIE792: no-inherit-object\n\nInheriting from `object` isn\'t necessary in Python 3.\n\n```python\n# error\nclass Foo(object):\n    ...\n\n# ok\nclass Foo:\n    ...\n```\n\n### PIE793: prefer-dataclass\n\nAttempts to find cases where the `@dataclass` decorator is unintentionally\nmissing.\n\n```python\n# error\nclass Foo:\n    z: dict[int, int]\n    def __init__(self) -> None: ...\n\nclass Bar:\n    x: list[str]\n\n# ok\nclass Bar(Foo):\n    z: dict[int, int]\n\n@dataclass\nclass Bar:\n    x: list[str]\n```\n\n### PIE794: dupe-class-field-definitions\n\nFinds duplicate definitions for the same field, which can occur in large ORM\nmodel definitions.\n\n```python\n# error\nclass User(BaseModel):\n    email = fields.EmailField()\n    # ...80 more properties...\n    email = fields.EmailField()\n\n# ok\nclass User(BaseModel):\n    email = fields.EmailField()\n    # ...80 more properties...\n```\n\n### PIE795: prefer-stdlib-enums\n\nInstead of defining various constant properties on a class, use the stdlib\nenum which typecheckers support for type refinement.\n\n```python\n# error\nclass Foo:\n    A = "A"\n    B = "B"\n    C = "C"\n\n# ok\nimport enum\nclass Foo(enum.Enum):\n    A = "A"\n    B = "B"\n    C = "C"\n```\n\n### PIE796: prefer-unique-enums\n\nBy default the stdlib enum allows multiple field names to map to the same\nvalue, this lint requires each enum value be unique.\n\n```python\n# error\nclass Foo(enum.Enum):\n    A = "A"\n    B = "B"\n    C = "C"\n    D = "C"\n\n# ok\nclass Foo(enum.Enum):\n    A = "A"\n    B = "B"\n    C = "C"\n    D = "D"\n```\n\n### PIE797: no-unnecessary-if-expr\n\nCall `bool()` directly rather than reimplementing its functionality.\n\n```python\n# error\nfoo(is_valid=True if buzz() else False)\n\n# ok\nfoo(is_valid=bool(buzz()))\n```\n\n### PIE798: no-unnecessary-class\n\nInstead of using class to namespace functions, use a module.\n\n```python\n# error\nclass UserManager:\n    class User(NamedTuple):\n        name: str\n\n    @classmethod\n    def update_user(cls, user: User) -> None:\n        ...\n\n    @staticmethod\n    def sync_users() -> None:\n        ...\n\n# ok\nclass User(NamedTuple):\n    name: str\n\ndef update_user(user: User) -> None:\n    ...\n\ndef sync_users() -> None:\n    ...\n```\n\n### PIE799: prefer-col-init\n\nCheck that values are passed in when collections are created rather than\ncreating an empty collection and then inserting.\n\n```python\n# error\nbars = []\nbar = bar()\nbars.append(bar)\n\n# ok\nbar = bar()\nbars = [bar]\n\n# error\ns = deque()\ns.append(foo)\n\n# ok\ns = deque([foo])\n```\n\n### PIE800: no-unnecessary-spread\n\nCheck for unnecessary dict unpacking.\n\n```python\n# error\n{**foo, **{"bar": 10}}\n\n# ok\n{**foo, "bar": 10}\n```\n\n### PIE801: prefer-simple-return\n\nReturn boolean expressions directly instead of returning `True` and `False`.\n\n```python\n# error\ndef main():\n    if foo > 5:\n        return True\n    return False\n\n# error\ndef main():\n    if foo > 5:\n        return True\n    else:\n        return False\n\n# ok\ndef main():\n    return foo > 5\n```\n\n### PIE802: prefer-simple-any-all\n\nRemove unnecessary comprehensions for `any` and `all`\n\n```python\n# error\nany([x.id for x in bar])\nall([x.id for x in bar])\n\n# ok\nall(x.id for x in bar)\nany(x.id for x in bar)\nany({x.id for x in bar})\n```\n\n### PIE803: prefer-logging-interpolation\n\nDon\'t format strings before logging. Let `logging` interpolate arguments.\n\nThis allows Sentry to aggregate logs, prevents raising exceptions if interpolation fails, and improves performance if the log level is disabled. See ["PyCQA/pylint#1788"](https://github.com/PyCQA/pylint/issues/1788#issuecomment-461279687).\n\n```python\n# error\nlogger.info("Login error for %s" % user)\nlogger.info("Login error for %s, %s" % (user_id, name))\n\n# error\nlogger.info("Login error for {}".format(user))\nlogger.info("Login error for {}, {}".format(user_id, name))\n\n# error\nlogger.info(f"Login error for {user}")\nlogger.info(f"Login error for {user_id}, {name}")\n\n# ok\nlogger.info("Login error for %s", user)\nlogger.info("Login error for %s, %s", user_id, name)\n```\n\n### PIE804: no-unnecessary-dict-kwargs\n\nAs long as the keys of the dict are valid Python identifier names, we can safely\nremove the surrounding dict.\n\n```python\n# error\nfoo(**{"bar": True})\n\n# ok\nfoo(bar=True)\nfoo(**buzz)\nfoo(**{"bar foo": True})\n```\n\n## dev\n\n```shell\n# install dependencies\npoetry install\n\ns/lint\ns/test\n```\n\n## uploading a new version to [PyPi](https://pypi.org)\n\n```shell\n# increment `Flake8PieCheck.version` and pyproject.toml `version`\n\n# build new distribution files and upload to pypi\n# Note: this will ask for login credentials\nrm -rf dist && poetry publish --build\n```\n',
    'author': 'Steve Dignam',
    'author_email': 'steve@dignam.xyz',
    'url': 'https://github.com/sbdchd/flake8-pie',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'entry_points': entry_points,
    'python_requires': '>=3.7',
}


setup(**setup_kwargs)
