# **MegaMock** - _The Developer Experience Upgrade for Python Mocking_
Pew pew! Sane defaults for mocking behavior! Patch objects, variables, attributes, etc by passing in the thing in question, rather than passing in dot-delimited path strings! Create tests faster than ever!
Supported Python Versions: 3.10+
## New! Use the official GPT!
An OpenAI ChatGPT+ GPT has been created for MegaMock! Ask questions about library usage or have it generate tests! The GPT has been coached on test generation and should outperform vanilla GPT-4. The GPT is available at: https://chat.openai.com/g/g-DtZiDVQsz-python-megamock-test-generation-assistant
If the GPT can't find info or gives bad answers, try asking it to consult the reference file. See this example: https://chat.openai.com/share/b942b5cc-bfa5-4844-8c46-922a3c2c99fc
The GPT is experimental. It has a tendency to regress during conversations. If it starts mixing MegaMock and mock, remind it to double check that its following its instructions. Its been coached on a specific pytest style but you can tell it do something else. It tends to be aggressive with the mocking, so you'll need to reel it in and use your judgement on what ultimately makes sense to mock. Don't mock something you don't need to. Don't create unit tests using mocks that will just shadow required integration tests.
### Installation
Pip installation:
```
pip install megamock
```
[poetry](https://python-poetry.org/) (as a development dependency):
```
poetry add megamock --group=dev
```
# Why Use MegaMock? (short version)
MegaMock is a library that provides a better interface for mocking and patching in Python. Its version
of patch doesn't have any gotchas based on how you import something, and it also automatically
creates mocks using best practices. Additionally, the generated mock types are unions of the mocked object
and `MegaMock`, allowing you to better leverage your IDE's autocomplete.
![Sample MegaMock vs Mock Comparison](docs/img/megamock-example.gif)
Mock:
```python
class_mock = mock.create_autospec(ClassICareAbout, instance=True)
# cmd / alt clicking on "method_call" doesn't direct you to the definition
class_mock.method_call.return_value = "some value"
# can't simply cmd / alt click and go to ClassICareAbout
with mock.patch("some.hard.to.remember.and.long.dot.path.ClassICareAbout", class_mock) as mock_instance:
do_something()
```
MegaMock:
```python
# cmd / alt clicking on ClassICareAbout takes you to the definition
patch = MegaPatch.it(ClassICareAbout)
mock_instance = patch.megainstance
# cmd / alt clicking on "method_call" directs you to the definition
mock_instance.method_call.return_value = "some value"
do_something()
```
# Why Use MegaMock? (long version)
MegaMock was created to address some shortcomings in the built-in Python library:
- Legacy code holds back "best practice" defaults, so many developers write sub-optimal mocks
that allow things that should not be allowed. Likewise, writing better mocks are more work,
so there's a tendency to write simpler code because, at that point in time, the developer
felt that is all that was needed. MegaMock's simple interface provides sane defaults.
- `mock.patch` is very commonly used, and can work well when `autospec=True`, but has the drawback that
you need to pass in a string to the thing that is being patched. Most (all?) IDEs do not properly
recognize these strings as references to the objects that are being patched, and thus automated
refactoring and reference finding skips them. Likewise, automatically getting a dot referenced path
to an object is also commonly missing functionality. This all adds additional burden to the developer.
With `MegaPatch`, you can import an object as you normally would into the test, then pass in thing
itself you want to patch. This even works for methods, attributes, and nested classes! Additionally, your IDE's autocomplete for attributes
will work in many situations as well!
- `mock.patch` has a gotcha where the string you provide must match where the reference lives.
So, for example, if you have in `my_module.py`: `from other_module import Thing`, then doing
`mock.patch("other_module.Thing")` won't actually work, because the reference in `my_module` still
points to the original. You can work around this by doing `import other_module` and referencing `Thing`
by `other_module.Thing`. MegaMock does not have this problem, and it doesn't matter how you import.
## Features
See the [full features list](FEATURES.md).
## Example Usage
### Production Code
```python
from module.submodule import MyClassToMock
def my_method(...):
...
a_thing = MyClassToMock(...)
do_something_with_a_thing(a_thing)
...
def do_something_with_a_thing(a_thing: MyClassToMock) -> None:
result = a_thing.some_method(...)
if result == "a value":
...
```
### Test Code
```python
from megamock import MegaPatch
from module.submodule import MyClassToMock
def test_something(...):
patch = MegaPatch.it(MyClassToMock.some_method)
patch.return_value = "a value"
my_method(...)
```
## Documentation
### Usage (pytest)
With [pytest](https://pytest.org), MegaMock is easily leveraged by using the included pytest plugin. You can use it by adding `-p megamock.plugins.pytest`
to the command line.
Command line example:
```
pytest -p megamock.plugins.pytest
```
`pyproject.toml` example:
```toml
[tool.pytest.ini_options]
addopts = "-p megamock.plugins.pytest"
```
The pytest plugin also automatically stops `MegaPatch`es after each test. If `pytest-mock` is installed, the default mocker will be switched to the `pytest-mock` `mocker`.
### Usage (other test frameworks)
If you're not using the pytest plugin, import and execution order is important for MegaMock. When running tests, you will need to execute the `start_import_mod`
function prior to importing any production or test code. You will also want it so the loader is not used in production.
-------------------
**Core Classes**
`MegaMock` - the primary class for a mocked object. This is similar to `MagicMock`. To create a mock instance of a class, use `MegaMock.it(MyClass)` to make `MyClass` the [spec](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.create_autospec). To create a mock class (the type) use `MegaMock.the_class(MyClass)`. To create mock instances of instantiated objects, functions, etc, use `MegaMock.this(some_object)`.
`MegaPatch` - the class for patching. This is similar to `patch`. Use `MegaPath.it(MyObject)` to replace new instances of the `MyObject` class.
`Mega` - helper class for accessing mock attributes without having to memorize them due to lost type inference. Use `Mega(some_megamock)`.
Note that the `assert_` methods, such as `assert_called_once`, is now `called_once` and returns a boolean. The assertion error
is stored in `Mega.last_assertion_error`. This is typically for doing asserts against mocked functions and methods.
--------------------
Dependency injection example:
```python
from megamock import MegaMock
def test_something(...):
manager = MegaMock.it(MyManagerClass)
service = SomeService(manager)
...
```
MegaPatch example:
```python
from elsewhere import Service
from megamock import MegaPatch
def test_something(...):
patched = MegaPatch.it(Service.make_external_call)
patched.return_value = SomeValue(...)
service = SomeService(...)
code_under_test(service)
...
```
`MegaMock` objects have the same attributes as regular `MagicMock`s plus `megamock` and `megainstance`.
For example, `my_mega_mock.megamock.spy` is the object being spied, if set. `my_class_mock.megainstance` is the instance returned when the class is instantiated. Note that you typically access the megainstance with `MegaMock(my_class_mock).megainstance` due to limitations in the type system.
The [guidance document](GUIDANCE.md) is available to provide in-depth information on using mocking and MegaMock. Continuing reading to
quickly jump in to examples.
-----------------------
### Learning By Example
All examples below have the following imports:
```python
from my_module import MyClass
from megamock import Mega, MegaMock, MegaPatch
```
Creating a mock instance of a class:
```python
mock_instance = MegaMock.it(MyClass)
```
Creating a mock class itself:
```python
mock_class = MegaMock.the_class(MyClass)
func_that_wants_a_type(mock_class)
```
Spying an object:
```python
my_thing = MyClass()
spied_class = MegaMock.this(spy=my_thing)
# ... do stuff with spied_class...
Mega(spied_class.some_method).call_args_list # same as wraps
# check whether a value was accessed
# if things aren't as expected, you can pull up the debugger and see the stack traces
assert len(spied_class.megamock.spied_access["some_attribute"]) == 1
spy_access_list = spied_class.megamock.spied_access["some_attribute"]
spy_access: SpyAccess = spy_access_list[0]
spy_access.attr_value # shallow copy of what was returned
spy_access.stacktrace # where the access happened
spy_access.time # when it happened (from time.time())
spy_access.top_of_stacktrace # a shorthand property intended to be used when debugging in the IDE
spy_access.format_stacktrace() # return a list of strings for the stacktrace
spy_access.print_stacktrace() # display the stacktrace to the console
```
Patching a class:
```python
mock_patch = MegaPatch.it(MyClass)
# the class itself
mock_patch.new_value
# the class instance
mock_patch.megainstance
# the return value of the __call__ method on the class
mock_patch.megainstance.return_value
```
Patching a class attribute:
```python
# temporarily update the max retries to 0
mega_patch = MegaPatch.it(MyClass.max_retries, new=0)
```
Patching a class method:
```python
mega_patch = MegaPatch.it(MyClass.my_method, return_value=...)
```
Alternatively:
```python
mega_patch = MegaPatch.it(MyClass.my_method)
mega_patch.mock.return_value = ...
```
```python
mega_patch = MegaPatch.it(MyClass.my_method)
mega_patch.new_value.return_value = ...
```
You can also alter the return value of your mock without creating a separate mock object first.
```python
mega_patch.return_value.user = SomeUser()
```
Working with `MegaPatch` and classes:
`mega_patch.new_value` is the class _type_ itself
```python
mega_patch = MegaPatch.it(MyClass)
mega_patch.new_value.x is MyClass.x
```
`mega_patch.return_value` is the class _instance_ returned. However, there is the property
`megainstance` which is preferred because it has better type hinting.
```python
mega_patch = MegaPatch.it(MyClass)
# instead of this, for which the static type is Any:
mega_patch.return_value is MyClass()
# use this, which has a static type of MegaMock | MyClass:
mega_patch.megainstance is MyClass()
```
Patching a module attribute:
```python
import my_module
MegaPatch.it(my_module.some_attribute, new=...)
```
Patching a method of a nested class:
```python
import my_module
MegaPatch.it(
my_module.MyClass.MyNestedClass.some_method,
return_value=...
)
```
Setting the return value:
```python
my_mock.my_method.return_value = "foo"
```
Turning on real logic:
```python
import my_module
mega_patch = MegaPatch.it(my_module.SomeClass)
Mega(mega_patch.megainstance.some_pure_logic_method).use_real_logic()
do_something_that_invokes_that_function(...)
```
# Congrats on Reading This Far! Here's an Art Gallery!
![MegaMock](docs/img/megamock-v2-cropped.png)
Nobody said it was a big art gallery. Feel free to submit a PR that helps fix that. No artistic skill required.
Raw data
{
"_id": null,
"home_page": "https://github.com/JamesHutchison/megamock",
"name": "megamock",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.10,<4.0",
"maintainer_email": "",
"keywords": "mock,test",
"author": "James Hutchison",
"author_email": "jamesghutchison@proton.me",
"download_url": "https://files.pythonhosted.org/packages/ad/98/d18b04b36ae626bd3797d79099b020dcfeb153ff88226373997e1ef2b19b/megamock-0.1.0b11.tar.gz",
"platform": null,
"description": "# **MegaMock** - _The Developer Experience Upgrade for Python Mocking_\n\nPew pew! Sane defaults for mocking behavior! Patch objects, variables, attributes, etc by passing in the thing in question, rather than passing in dot-delimited path strings! Create tests faster than ever!\n\nSupported Python Versions: 3.10+\n\n## New! Use the official GPT!\nAn OpenAI ChatGPT+ GPT has been created for MegaMock! Ask questions about library usage or have it generate tests! The GPT has been coached on test generation and should outperform vanilla GPT-4. The GPT is available at: https://chat.openai.com/g/g-DtZiDVQsz-python-megamock-test-generation-assistant\n\nIf the GPT can't find info or gives bad answers, try asking it to consult the reference file. See this example: https://chat.openai.com/share/b942b5cc-bfa5-4844-8c46-922a3c2c99fc\n\nThe GPT is experimental. It has a tendency to regress during conversations. If it starts mixing MegaMock and mock, remind it to double check that its following its instructions. Its been coached on a specific pytest style but you can tell it do something else. It tends to be aggressive with the mocking, so you'll need to reel it in and use your judgement on what ultimately makes sense to mock. Don't mock something you don't need to. Don't create unit tests using mocks that will just shadow required integration tests.\n\n### Installation\n\nPip installation:\n```\npip install megamock\n```\n\n[poetry](https://python-poetry.org/) (as a development dependency):\n```\npoetry add megamock --group=dev\n```\n\n# Why Use MegaMock? (short version)\nMegaMock is a library that provides a better interface for mocking and patching in Python. Its version\nof patch doesn't have any gotchas based on how you import something, and it also automatically\ncreates mocks using best practices. Additionally, the generated mock types are unions of the mocked object\nand `MegaMock`, allowing you to better leverage your IDE's autocomplete.\n\n![Sample MegaMock vs Mock Comparison](docs/img/megamock-example.gif)\n\nMock:\n\n```python\nclass_mock = mock.create_autospec(ClassICareAbout, instance=True)\n# cmd / alt clicking on \"method_call\" doesn't direct you to the definition\nclass_mock.method_call.return_value = \"some value\"\n\n# can't simply cmd / alt click and go to ClassICareAbout\nwith mock.patch(\"some.hard.to.remember.and.long.dot.path.ClassICareAbout\", class_mock) as mock_instance:\n do_something()\n```\n\nMegaMock:\n\n```python\n# cmd / alt clicking on ClassICareAbout takes you to the definition\npatch = MegaPatch.it(ClassICareAbout)\nmock_instance = patch.megainstance\n# cmd / alt clicking on \"method_call\" directs you to the definition\nmock_instance.method_call.return_value = \"some value\"\n\ndo_something()\n```\n\n# Why Use MegaMock? (long version)\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! Additionally, your IDE's autocomplete for attributes\n will work in many situations as well!\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## Features\n\nSee the [full features list](FEATURES.md).\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 patch = MegaPatch.it(MyClassToMock.some_method)\n patch.return_value = \"a value\"\n\n my_method(...)\n```\n\n## Documentation\n\n### Usage (pytest)\n\nWith [pytest](https://pytest.org), MegaMock is easily leveraged 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. If `pytest-mock` is installed, the default mocker will be switched to the `pytest-mock` `mocker`.\n\n### Usage (other test frameworks)\n\nIf you're not using the pytest plugin, import 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\n-------------------\n\n**Core Classes**\n\n`MegaMock` - the primary class for a mocked object. This is similar to `MagicMock`. To create a mock instance of a class, use `MegaMock.it(MyClass)` to make `MyClass` the [spec](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.create_autospec). To create a mock class (the type) use `MegaMock.the_class(MyClass)`. To create mock instances of instantiated objects, functions, etc, use `MegaMock.this(some_object)`.\n\n`MegaPatch` - the class for patching. This is similar to `patch`. Use `MegaPath.it(MyObject)` to replace new instances of the `MyObject` class.\n\n`Mega` - helper class for accessing mock attributes without having to memorize them due to lost type inference. Use `Mega(some_megamock)`.\nNote that the `assert_` methods, such as `assert_called_once`, is now `called_once` and returns a boolean. The assertion error\nis stored in `Mega.last_assertion_error`. This is typically for doing asserts against mocked functions and methods.\n\n--------------------\n\nDependency injection example:\n```python\n\nfrom megamock import MegaMock\n\ndef test_something(...):\n manager = MegaMock.it(MyManagerClass)\n service = SomeService(manager)\n ...\n```\n\nMegaPatch example:\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\n`MegaMock` objects have the same attributes as regular `MagicMock`s plus `megamock` and `megainstance`.\nFor example, `my_mega_mock.megamock.spy` is the object being spied, if set. `my_class_mock.megainstance` is the instance returned when the class is instantiated. Note that you typically access the megainstance with `MegaMock(my_class_mock).megainstance` due to limitations in the type system.\n\nThe [guidance document](GUIDANCE.md) is available to provide in-depth information on using mocking and MegaMock. Continuing reading to\nquickly jump in to examples.\n\n-----------------------\n\n### Learning By Example\n\nAll examples below have the following imports:\n\n```python\nfrom my_module import MyClass\nfrom megamock import Mega, MegaMock, MegaPatch\n```\n\nCreating a mock instance of a class:\n\n```python\nmock_instance = MegaMock.it(MyClass)\n```\n\nCreating a mock class itself:\n\n```python\nmock_class = MegaMock.the_class(MyClass)\nfunc_that_wants_a_type(mock_class)\n```\n\nSpying an object:\n\n```python\nmy_thing = MyClass()\nspied_class = MegaMock.this(spy=my_thing)\n\n# ... do stuff with spied_class...\n\nMega(spied_class.some_method).call_args_list # same as wraps\n\n# check whether a value was accessed\n# if things aren't as expected, you can pull up the debugger and see the stack traces\nassert len(spied_class.megamock.spied_access[\"some_attribute\"]) == 1\n\nspy_access_list = spied_class.megamock.spied_access[\"some_attribute\"]\nspy_access: SpyAccess = spy_access_list[0]\nspy_access.attr_value # shallow copy of what was returned\nspy_access.stacktrace # where the access happened\nspy_access.time # when it happened (from time.time())\nspy_access.top_of_stacktrace # a shorthand property intended to be used when debugging in the IDE\nspy_access.format_stacktrace() # return a list of strings for the stacktrace\nspy_access.print_stacktrace() # display the stacktrace to the console\n```\n\n\nPatching a class:\n\n```python\nmock_patch = MegaPatch.it(MyClass)\n\n# the class itself\nmock_patch.new_value\n\n# the class instance\nmock_patch.megainstance\n\n# the return value of the __call__ method on the class\nmock_patch.megainstance.return_value\n```\n\nPatching a class attribute:\n\n```python\n# temporarily update the max retries to 0\nmega_patch = MegaPatch.it(MyClass.max_retries, new=0)\n```\n\nPatching a class method:\n\n```python\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. However, there is the property\n`megainstance` which is preferred because it has better type hinting.\n\n```python\nmega_patch = MegaPatch.it(MyClass)\n\n# instead of this, for which the static type is Any:\nmega_patch.return_value is MyClass()\n\n# use this, which has a static type of MegaMock | MyClass:\nmega_patch.megainstance 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\nSetting the return value:\n\n```python\nmy_mock.my_method.return_value = \"foo\"\n```\n\nTurning on real logic:\n\n```python\nimport my_module\n\nmega_patch = MegaPatch.it(my_module.SomeClass)\nMega(mega_patch.megainstance.some_pure_logic_method).use_real_logic()\n\ndo_something_that_invokes_that_function(...)\n```\n\n# Congrats on Reading This Far! Here's an Art Gallery!\n\n![MegaMock](docs/img/megamock-v2-cropped.png)\n\nNobody said it was a big art gallery. Feel free to submit a PR that helps fix that. No artistic skill required.\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Mega mocking capabilities - stop using dot-notated paths!",
"version": "0.1.0b11",
"project_urls": {
"Homepage": "https://github.com/JamesHutchison/megamock",
"Repository": "https://github.com/JamesHutchison/megamock"
},
"split_keywords": [
"mock",
"test"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "9bb3c141c94cf3413d0fda34270a42721853a23fa47f4daf58ccc87576f59827",
"md5": "cf8043bb36f6971314d5e6017672899d",
"sha256": "7a9f56773ff8952e25f97615e71cc854512679b25fb2307d83ec1f3b8c3b17f3"
},
"downloads": -1,
"filename": "megamock-0.1.0b11-py3-none-any.whl",
"has_sig": false,
"md5_digest": "cf8043bb36f6971314d5e6017672899d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10,<4.0",
"size": 26575,
"upload_time": "2024-01-28T15:31:02",
"upload_time_iso_8601": "2024-01-28T15:31:02.549226Z",
"url": "https://files.pythonhosted.org/packages/9b/b3/c141c94cf3413d0fda34270a42721853a23fa47f4daf58ccc87576f59827/megamock-0.1.0b11-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "ad98d18b04b36ae626bd3797d79099b020dcfeb153ff88226373997e1ef2b19b",
"md5": "9302fe34d4f1e7ffe7bf56abd1fbf910",
"sha256": "38a1979814e78d52f2a8d915aab2e7ac4f266ffc29e1525e6caa84c291198e24"
},
"downloads": -1,
"filename": "megamock-0.1.0b11.tar.gz",
"has_sig": false,
"md5_digest": "9302fe34d4f1e7ffe7bf56abd1fbf910",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10,<4.0",
"size": 26941,
"upload_time": "2024-01-28T15:31:04",
"upload_time_iso_8601": "2024-01-28T15:31:04.674908Z",
"url": "https://files.pythonhosted.org/packages/ad/98/d18b04b36ae626bd3797d79099b020dcfeb153ff88226373997e1ef2b19b/megamock-0.1.0b11.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-01-28 15:31:04",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "JamesHutchison",
"github_project": "megamock",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "megamock"
}