# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['megamock', 'megamock.plugins']

package_data = \
{'': ['*']}

install_requires = \
['asttokens>=2.2.1,<3.0.0', 'varname[asttokens]>=0.10.0,<0.11.0']

setup_kwargs = {
    'name': 'megamock',
    'version': '0.1.0a3',
    'description': 'Mega mocking capabilities',
    'long_description': '# MegaMock\n\nPew pew! Patch objects, variables, attributes, etc by passing in the thing in question, rather than passing in dot-delimited paths!\nAlso sane defaults for mocking behavior!\n\nSupported Python Versions: 3.10+\n\n# Why Use MegaMock?\nMegaMock was created to address some shortcomings in the built-in Python library:\n- Legacy code holds back "best practice" defaults, so many developers write sub-optimal mocks\n  that allow things that should not be allowed. Likewise, writing better mocks are more work,\n  so there\'s a tendency to write simpler code because, at that point in time, the developer\n  felt that is all that was needed. MegaMock\'s simple interface provides sane defaults.\n- `mock.patch` is very commonly used, and can work well when `autospec=True`, but has the drawback that\n  you need to pass in a string to the thing that is being patched. Most (all?) IDEs do not properly\n  recognize these strings as references to the objects that are being patched, and thus automated\n  refactoring and reference finding skips them. Likewise, automatically getting a dot referenced path\n  to an object is also commonly missing functionality. This all adds additional burden to the developer.\n  With `MegaPatch`, you can import an object as you normally would into the test, then pass in thing\n  itself you want to patch. This even works for methods, attributes, and nested classes!\n- `mock.patch` has a gotcha where the string you provide must match where the reference lives.\n  So, for example, if you have in `my_module.py`: `from other_module import Thing`, then doing\n  `mock.patch("other_module.Thing")` won\'t actually work, because the reference in `my_module` still\n  points to the original. You can work around this by doing `import other_module` and referencing `Thing`\n  by `other_module.Thing`. MegaMock does not have this problem, and it doesn\'t matter how you import.\n\n## Example Usage\n\n### Production Code\n```python\nfrom module.submodule import MyClassToMock\n\n\ndef my_method(...):\n    ...\n    a_thing = MyClassToMock(...)\n    do_something_with_a_thing(a_thing)\n    ...\n\n\ndef do_something_with_a_thing(a_thing: MyClassToMock) -> None:\n    result = a_thing.some_method(...)\n    if result == "a value":\n        ...\n```\n\n### Test Code\n```python\nfrom megamock import MegaPatch\nfrom module.submodule import MyClassToMock\n\n\ndef test_something(...):\n    patched = MegaPatch.it(MyClassToMock.some_method)\n    patched.return_value = "a value"\n\n    my_method(...)\n```\n\n## Documentation\n\n### Installation\n\n`pip install megamock`\n\n### Usage\n\nImport and execution order is important for MegaMock. When running tests, you will need to execute the `start_import_mod`\nfunction prior to importing any production or test code. You will also want it so the loader is not used in production.\n\nWith `pytest`, this is easily done by using the included pytest plugin. You can use it by adding `-p megamock.plugins.pytest`\nto the command line.\n\nCommand line example:\n```\npytest -p megamock.plugins.pytest\n```\n\n`pyproject.toml` example:\n```toml\n[tool.pytest.ini_options]\naddopts = "-p megamock.plugins.pytest"\n```\n\nThe pytest plugin also automatically stops `MegaPatch`es after each test. To disable this behavior, pass in the `--do_not_autostop_megapatches`\ncommand line argument.\n\nIn tests, the `MegaMock` class replaces the mock classes `MagicMock` and `Mock`. `MegaPatch.it(...)` replaces `patch(...)`.\nCurrently, there is no substitute for `patch.object` although `MegaPatch.it` should work on global instances (singletons).\n\n```python\n\nfrom megamock import MegaMock\n\ndef test_something(...):\n    manager = MegaMock(MyManagerClass)\n    service = SomeService(manager)\n    ...\n```\n\n```python\nfrom elsewhere import Service\n\nfrom megamock import MegaPatch\n\ndef test_something(...):\n    patched = MegaPatch.it(Service.make_external_call)\n    patched.return_value = SomeValue(...)\n    service = SomeService(...)\n\n    code_under_test(service)\n    ...\n```\n\nYou can focus your production code on creating an intuitive, "batteries included" interface for developers\nwithout making compromises for testability.\nPlease see the guidance section (TODO) for more information on how and when you would use MegaMock.\n\n### Use Case Examples\n\nAll use cases below have the following import:\n\n```python\nfrom megamock import MegaMock, MegaPatch\n```\n\nCreating a mock instance of a class:\n\n```python\nfrom my_module import MyClass\n\nmock_instance = MegaMock(MyClass)\n```\n\nCreating a mock class itself:\n\n```python\nfrom my_module import MyClass\n\nmock_class = MegaMock(MyClass, instance=False)\n```\n\nPatching a class:\n\n```python\nfrom my_module import MyClass\n\nmock_patch = MegaPatch(MyClass)\n\n# the class itself\nmock_patch.new_value\n\n# the class instance\nmock_patch.return_value\n\n# the return value of the __call__ method on the class\nmock_patch.return_value.return_value\n```\n\nPatching a class attribute:\n\n```python\nfrom my_module import MyClass\n\n# temporarily update the hard coded default max retries to 0\nmega_patch = MegaPatch(MyClass.max_retries, new=0)\n```\n\nPatching a class method:\n\n```python\nfrom my_module import MyClass\n\nmega_patch = MegaPatch.it(MyClass.my_method, return_value=...)\n```\n\nAlternatively:\n```python\nmega_patch = MegaPatch.it(MyClass.my_method)\nmega_patch.mock.return_value = ...\n```\n\n```python\nmega_patch = MegaPatch.it(MyClass.my_method)\nmega_patch.new_value.return_value = ...\n```\n\nYou can also alter the return value of your mock without creating a separate mock object first.\n\n```python\nmega_patch.return_value.user = SomeUser()\n```\n\nWorking with `MegaPatch` and classes:\n\n`mega_patch.new_value` is the class _type_ itself\n\n```python\nmega_patch = MegaPatch.it(MyClass)\n\nmega_patch.new_value.x is MyClass.x\n```\n\n`mega_patch.return_value` is the class _instance_ returned\n\n```python\nmega_patch = MegaPatch.it(MyClass)\n\nmega_patch.return_value is MyClass()\n```\n\nPatching a module attribute:\n\n```python\nimport my_module\n\nMegaPatch.it(my_module.some_attribute, new=...)\n```\n\nPatching a method of a nested class:\n\n```python\nimport my_module\n\nMegaPatch.it(\n    my_module.MyClass.MyNestedClass.some_method,\n    return_value=...\n)\n```\n\n# Behavior differences from `mock`\n- Using `MegaMock` is like using the `mock.create_autospec()` function\n- Using `MegaPatch` is like setting `autospec=True`\n- Mocking a class by default returns an instance of the class instead of a mocked type. This is like setting `instance=True`\n\n# Art Gallery\n\n![MegaMock](docs/img/megamock-cropped.png)\n',
    'author': 'James Hutchison',
    'author_email': 'jamesghutchison@proton.me',
    'maintainer': 'None',
    'maintainer_email': 'None',
    'url': 'https://github.com/JamesHutchison/megamock',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.10,<4.0',
}


setup(**setup_kwargs)
