pyguarantees


Namepyguarantees JSON
Version 0.1.4 PyPI version JSON
download
home_page
Summaryguarantee testcases for callables, constrain parameters and return values of callables
upload_time2022-12-19 11:00:55
maintainer
docs_urlNone
authorSebastian Müller
requires_python>=3.8
licenseMIT License Copyright (c) 2022 Sebastian Müller Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords python unittest pytest test guarantees parameters constraints
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # pyguarantees

*Guarantee testcases for callables, constrain parameters and return values of callables.*

**Project**

![PyPI Version](https://img.shields.io/pypi/v/pyguarantees)
![Wheel](https://img.shields.io/pypi/wheel/pyguarantees)

**Info**


![License](https://img.shields.io/github/license/snimu/guarantees)
![Python Versions](https://img.shields.io/pypi/pyversions/pyguarantees)

**Tests**

![Tests](https://github.com/snimu/guarantees/actions/workflows/tests.yml/badge.svg)
![Coverage](coverage.svg)

**Installation—Pip**

```bash
pip3 install pyguarantees
```


# tests

"I will have to write a unittest for this function later", you say. This package ensures that you 
won't forget.

"Why does this function fail? I've tested it... omg I didn't even call it in my TestCase." Use this 
package to make sure that a function/method will be called or a class instance constructed 
in its respective `TestCase`.

Can be used for `unittest` and `pytest`.

## Example unittest

```python 
import unittest
import pyguarantees as pg
from some_package import some_fct_with_test_guarantee


@pg.testcase.guaranteed()
@pg.testcase.calls()  # make sure that this is called in all its tests
def add_one(a):
    return a + 1


@pg.testcase.guaranteed()
@pg.testcase.calls()  # Makes sure that __init__ is called in the test
class RegularClass:
    def __init__(self):
        self.x = 2


class ExampleTest(unittest.TestCase):
    @pg.testcase.covers(add_one, some_fct_with_test_guarantee)
    def test_some_stuff(self):
        val = add_one(1)
        self.assertEqual(val, 2)
        # some_fct_with_test_guarantees has no @pg.testcase.call
        #   -> doesn't have to be called here.
      

    @pg.testcase.covers(RegularClass)
    def test_regular_class(self):
        regular_class = RegularClass()
        ...


if __name__ == '__main__':
    pg.unittests.main()
```

As in the example, `pyguarantees` will be abbreviated with `pg` from here on out.

Failing to use an [@pg.testcase.covers](#covers) for a function or method decorated with [@pg.testcase.guaranteed](#guaranteed)
leads to a [tg.exceptions.testcase.TestsNotImplementedError](#testsnotimplementederror), while failing to use this function or method in the 
corresponding test will lead to a [tg.exceptions.testcase.NotUsedInTestsError](#notusedintestserror) if it is decorated by 
[@tg.guarantee_usage](#guarantee_usage). These exceptions are only raised if the `unittest.TestCase` are called first 
and then checked by [pg.unittests.enforce](#enforce), or [pg.unittests.main](#main) is called to do both automatically.

Currently doesn't work with nested functions (defined inside of other callables). This might be fixed at some point.


## Example pytest

```python
# These imports are unused but necessary for pytest to find the tests that 
#  enforce the guarantees from tg
from pyguarantees.pytests import
    test_all_tests_implemented, test_functions_used_in_tests
import pyguarantees as pg


class ExampleClass:
    @pg.testcase.guaranteed()  # tg.main will raise exception if there is not test for this method
    def method(self):
        return self

    @classmethod  # works for classmethods
    @pg.testcase.guaranteed()  # @pg.testcase.calls possible in any of these methods, but optional
    def class_method(cls):
        return cls

    @staticmethod  # works for staticmethods
    @pg.testcase.guaranteed()
    @pg.testcase.calls()
    def static_method():
        return "static!"


@pg.testcase.covers(
    ExampleClass.method,
    ExampleClass.class_method,
    ExampleClass.static_method
)
def test_example_class():
    assert ExampleClass.static_method() == "static!"
```

This is even simpler: just use [@pg.testcase.guaranteed](#guaranteed), [@pg.testcase.calls](#calls),
and [@pg.testcase.covers](#covers) as in [Example unittest](#example-unittest). No 
need to call [pg.unittests.main](#main) or [tg.enforce](#enforce); instead, import (but don't use) 
[pg.pytests.test_all_tests_implemented](#testalltestsimplemented) and 
[pg.pytests.test_functions_used_in_tests](#testfunctionsusedintests) and then run `pytest`.

**IMPORTANT**: If you use `pytest.mark.order` from the [pytest-order](https://pypi.org/project/pytest-order/)-package,
don't use `pytest.mark.order(-1)` or `pytest.mark.order(-2)` on your tests—it is important that 
[test_all_tests_implemented](#testalltestsimplemented) and [test_functions_used_in_tests](#testfunctionsusedintests) 
are used last by `pytest`.


## Decorators

The three decorators shown below have no effect without the [functions](#functions) 
of this package, specifically running [main](#main) or [enforce](#enforce) for `unittest`, 
and simply importing [test_all_tests_implemented](#testalltestsimplemented) and 
[test_functions_used_in_tests](#testfunctionsusedintests) into one of your test-files.


### guaranteed

Takes no arguments.

Any function, method, or class (except, for the moment, ones nested inside of other callables) 
decorated with `@pg.testcase.guaranteed`
that is in the scope of unittest will force unittest to throw an exception should 
it not be in an [@pg.testcase.covers](#covers).

Currently, it is necessary to include the brackets—`()`— so that 
the function is registered. This executes the decorator once but not the callable that 
it decorates, making it computationally inexpensive.

Having a function (or method) decorated like follows:

```python
@pg.testcase.guaranteed()
def foo():
  pass
```

but not having a test in your `unittest.TestCase` decorated by `@pg.testcase.covers(foo)` 
would lead to a [TestsNotImplementedError](#testsnotimplementederror) being raised.

The same works for classes.


### calls

Takes no arguments.

Must be used below [@pg.testcase.guaranteed](#guaranteed), otherwise it is ignored.

Just like with `@pg.testcase.guaranteed`, brackets are not optional, but the execution of 
the decorator is computationally inexpensive.

A function decorated as follows:

```python 
@pg.testcase.guaranteed()
@pg.testcase.calls()
def foo():
  pass
```

with a unittest that looks something like this:

```python 
# for unittest:
class TestExample(unittest.TestCase):
  @pg.testcase.covers(foo)
  def test_foo(self):
    ...  # some code that doesn't call foo


# for pytest:
@pg.testcase.covers(foo)
def test_foo():
  ...  # some code that doesn't call foo
```

would lead to a [NotUsedInTestsError](#notusedintestserror) being raised. 

In this scenario, if `foo` is an argument in several 
[@pg.testcase.covers](#covers),
`@pg.testcase.calls` makes certain that `foo` is used in every test-function 
decorated in such a way.

Special case: For classes, `@pg.testcase.calls` guarantees that `__init__` is called.
For a callable class, this still holds; to guarantee that the `__call__`-method is called
in the test, it has to be decorated by `@pg.testcase.calls` itself, not the class it belongs to. 


### covers

- `args`: Give any function or method that the corresponding test is meant for.
- `kwargs`: The value will be used like an `arg`, while the key will be ignored.

Functions and methods that weren't decorated by [@pg.testcase.guaranteed](#guaranteed) 
lead to a user-warning but are ignored otherwise.

Usage might look as follows:

```python 
# for unittest:
class TestExample(unittest.TestCase):
  @pg.testcase.covers(function1, function2, this_key_is_ignored=function3)
  def test_example(self):
    ...


# for pytest:
@pg.testcase.covers(function1, function2, this_key_is_ignored=function3)
def test_example():
  ...
```

## Functions

For `unittest`, at least one of [main](#main) or [enforce](#enforce) 
has to be used for the [decorators](#decorators)
to have an effect. 

For `pytest`, both [test_all_tests_implemented](#testalltestsimplemented) 
and [test_functions_used_in_tests](#testfunctionsusedintests) have to be imported 
into one of your test-files.

### enforce

Takes no arguments. This will likely change in the future to make it more adaptable.

Run this after running all your unittests. This runs additional unittests that 
check which functions violated their guarantees and raise [exceptions](#exceptionstestcase) 
accordingly.

It is recommended to only use this function when using a complicated unittest-setup.
When using `unittest.main()`, it is recommended to use `pg.testcase.main()` instead.

### main

Takes no arguments. This will likely change in the future to make it more adaptable.

Calls `unittest.main()` followed by [pg.unittests.enforce](#enforce).

### test_all_tests_implemented

Takes no arguments.

Import this into one of your files for [@pg.testcase.guaranteed](#guaranteed) and 
[@pg.testcase.covers](#covers) to have any effect.

### test_functions_used_in_tests

Takes no arguments.

Import this and [test_all_tests_implemented](#testalltestsimplemented) 
into one of your files for [@pg.testcase.guaranteed](#guaranteed) to 
have any effect.

## exceptions.testcase

`Exceptions` are located under `pg.exceptions.testcase`.

There are two custom `Exceptions` as presented below.

### TestsNotImplementedError

Arguments of `tg.exceptions.testcase.TestsNotImplementedError`:

- `functions` (type `callable`): The callables that weren't mentioned in a 
[@pg.testcase.covers](#covers).

Members of `tg.exceptions.testcase.TestsNotImplementedError`:

- `functions` (type `callable`): The callables that weren't mentioned in a 
[@pg.testcase.covers](#covers).
- `description` (type `str`): The error string printed when the exception is raised
and not caught.

The output of raising this exception might look something like:

    <Traceback...>

    pyguarantees.exceptions.testcase.TestsNotImplementedError: 

        No tests were implemented for the following methods and functions: 
    
        1. Missing test-case for the following callable: 
            Name: 		foo
            Module: 	__main__
        2. Missing test-case for the following callable: 
            Name: 		bar
            Module: 	__main__

### NotUsedInTestsError
Arguments of `tg.exceptions.testcase.NotUsedInTestsError`:

- `functions` (type: `callable`): The callables that were mentioned in a 
[@pg.testcase.covers](#covers) but not used in the corresponding
test.

Members of `tg.exceptions.NotUsedInTestsError`:

- `functions` (type: `callable`): The callables that were mentioned in a 
[@pg.testcase.covers](#covers) but not used in the corresponding
test.
- `description` (type: `str`): The error string printed when the exception is raised
and not caught.

A possible error message might look like the following:
    
    <Traceback...>

    pyguarantees.exceptions.testcase.NotUsedInTestsError:

    The following objects were not used in their assigned tests: 

	1. The following callable was not called in its assigned tests: 
		Name: 		foo
		Module: 	__main__
		This callable is tested but not called in the following test-cases: 
					- Name: 	TestFoo.test_foo1
					   Module: 	__main__
					- Name: 	TestFoo.test_foo2
					   Module: 	__main__
	2. The following callable was not called in its assigned tests: 
		Name: 		bar
		Module: 	some_module
		This callable is tested but not called in the following test-cases: 
					- Name: 	TestBar.test_bar
					   Module: 	test_some_module


# constraints

Few things are more useful in programming than the ability to constrain a program's possible behaviors 
and communicate those constraints clearly in code. Statically typed languages do this with types, scope modifiers, 
and lifetime modifiers, among others (`int`, `static`, `private`, `const`, etc.). These are static constraints 
in that they are evaluated statically, before runtime.

Oftentimes, a program also has dynamic constraints, evaluated during runtime&mdash;assertions, for example. 
A function dealing with division, for example, has to deal with the special case of division by zero. 

`pyguarantees`, abbreviated by `pg` again, enables both types of guarantees to be 
defined in Python where they should happen: function (or method) signatures. This is where statically typed 
languages put their static constraints (a typical function signature looks something like 
`scope-etc-modifiers return-type function-name(parameter-type parameter-name)`) and where in my opinion, dynamic 
constraints belong as well.

This might have the following advantages:
- Make code more readable by having constraints in a predefined place.
- Make code easier to write by providing important information about APIs in a glancable way.
- Make it possible to include information on dynamic constraints in automatically generated documentation.
- Encourage programmers to think about these constraints while writing the functions&mdash;a type of 
test-driven development directly at the function (seeing parts of the "tests" in the function-signature
might assist readability of code, as well). 

This package is an attempt to open up at least some of these advantages to Python-users at least partially, 
given the constraints of the Python-language. 

## Example

```python
import numpy as np
import pyguarantees as pg
from pyguarantees.constraints import IsInt, IsClass, DynamicCheck

from your_module import your_custom_error_callback


# One of many built-in guarantees using one of many built-in options
@pg.constrain.parameters(num=IsInt(minimum=3))
def add_one(num):
  return num + 1


# Use IsClass to guarantee all types and classes that don't have specific constraints 
#  in pg.constraints. If they do, it is recommended to use those specific constraints.
@pg.constrain.parameters(
  X=IsClass(
    class_type=np.ndarray,
    dynamic_checks=[
      DynamicCheck(check=lambda x: x.min() > 0, description="min: 0"),
      DynamicCheck(check=lambda x: x.var() < 5, description="var < 5"),
      DynamicCheck(check=lambda x: x.shape == (3, 80, 80), description="shape (3, 80, 80")
    ],
    error_callback=your_custom_error_callback
  ),
  mean=IsClass(class_type=np.ndarray),
  std=IsClass(class_type=np.ndarray)
)
@pg.constrain.returns(IsClass(class_type=np.ndarray))
def normalize(X, mean, std):
  return (X - mean) / std
```



> this README is currently under development. More is coming.

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "pyguarantees",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "python,unittest,pytest,test,guarantees,parameters,constraints",
    "author": "Sebastian M\u00fcller",
    "author_email": "sebastian.nicolas.mueller@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/b0/93/462ee07dd44d92891054b53a057e57163cdb559ef4f59b0b1a74630379be/pyguarantees-0.1.4.tar.gz",
    "platform": null,
    "description": "# pyguarantees\n\n*Guarantee testcases for callables, constrain parameters and return values of callables.*\n\n**Project**\n\n![PyPI Version](https://img.shields.io/pypi/v/pyguarantees)\n![Wheel](https://img.shields.io/pypi/wheel/pyguarantees)\n\n**Info**\n\n\n![License](https://img.shields.io/github/license/snimu/guarantees)\n![Python Versions](https://img.shields.io/pypi/pyversions/pyguarantees)\n\n**Tests**\n\n![Tests](https://github.com/snimu/guarantees/actions/workflows/tests.yml/badge.svg)\n![Coverage](coverage.svg)\n\n**Installation&mdash;Pip**\n\n```bash\npip3 install pyguarantees\n```\n\n\n# tests\n\n\"I will have to write a unittest for this function later\", you say. This package ensures that you \nwon't forget.\n\n\"Why does this function fail? I've tested it... omg I didn't even call it in my TestCase.\" Use this \npackage to make sure that a function/method will be called or a class instance constructed \nin its respective `TestCase`.\n\nCan be used for `unittest` and `pytest`.\n\n## Example unittest\n\n```python \nimport unittest\nimport pyguarantees as pg\nfrom some_package import some_fct_with_test_guarantee\n\n\n@pg.testcase.guaranteed()\n@pg.testcase.calls()  # make sure that this is called in all its tests\ndef add_one(a):\n    return a + 1\n\n\n@pg.testcase.guaranteed()\n@pg.testcase.calls()  # Makes sure that __init__ is called in the test\nclass RegularClass:\n    def __init__(self):\n        self.x = 2\n\n\nclass ExampleTest(unittest.TestCase):\n    @pg.testcase.covers(add_one, some_fct_with_test_guarantee)\n    def test_some_stuff(self):\n        val = add_one(1)\n        self.assertEqual(val, 2)\n        # some_fct_with_test_guarantees has no @pg.testcase.call\n        #   -> doesn't have to be called here.\n      \n\n    @pg.testcase.covers(RegularClass)\n    def test_regular_class(self):\n        regular_class = RegularClass()\n        ...\n\n\nif __name__ == '__main__':\n    pg.unittests.main()\n```\n\nAs in the example, `pyguarantees` will be abbreviated with `pg` from here on out.\n\nFailing to use an [@pg.testcase.covers](#covers) for a function or method decorated with [@pg.testcase.guaranteed](#guaranteed)\nleads to a [tg.exceptions.testcase.TestsNotImplementedError](#testsnotimplementederror), while failing to use this function or method in the \ncorresponding test will lead to a [tg.exceptions.testcase.NotUsedInTestsError](#notusedintestserror) if it is decorated by \n[@tg.guarantee_usage](#guarantee_usage). These exceptions are only raised if the `unittest.TestCase` are called first \nand then checked by [pg.unittests.enforce](#enforce), or [pg.unittests.main](#main) is called to do both automatically.\n\nCurrently doesn't work with nested functions (defined inside of other callables). This might be fixed at some point.\n\n\n## Example pytest\n\n```python\n# These imports are unused but necessary for pytest to find the tests that \n#  enforce the guarantees from tg\nfrom pyguarantees.pytests import\n    test_all_tests_implemented, test_functions_used_in_tests\nimport pyguarantees as pg\n\n\nclass ExampleClass:\n    @pg.testcase.guaranteed()  # tg.main will raise exception if there is not test for this method\n    def method(self):\n        return self\n\n    @classmethod  # works for classmethods\n    @pg.testcase.guaranteed()  # @pg.testcase.calls possible in any of these methods, but optional\n    def class_method(cls):\n        return cls\n\n    @staticmethod  # works for staticmethods\n    @pg.testcase.guaranteed()\n    @pg.testcase.calls()\n    def static_method():\n        return \"static!\"\n\n\n@pg.testcase.covers(\n    ExampleClass.method,\n    ExampleClass.class_method,\n    ExampleClass.static_method\n)\ndef test_example_class():\n    assert ExampleClass.static_method() == \"static!\"\n```\n\nThis is even simpler: just use [@pg.testcase.guaranteed](#guaranteed), [@pg.testcase.calls](#calls),\nand [@pg.testcase.covers](#covers) as in [Example unittest](#example-unittest). No \nneed to call [pg.unittests.main](#main) or [tg.enforce](#enforce); instead, import (but don't use) \n[pg.pytests.test_all_tests_implemented](#testalltestsimplemented) and \n[pg.pytests.test_functions_used_in_tests](#testfunctionsusedintests) and then run `pytest`.\n\n**IMPORTANT**: If you use `pytest.mark.order` from the [pytest-order](https://pypi.org/project/pytest-order/)-package,\ndon't use `pytest.mark.order(-1)` or `pytest.mark.order(-2)` on your tests&mdash;it is important that \n[test_all_tests_implemented](#testalltestsimplemented) and [test_functions_used_in_tests](#testfunctionsusedintests) \nare used last by `pytest`.\n\n\n## Decorators\n\nThe three decorators shown below have no effect without the [functions](#functions) \nof this package, specifically running [main](#main) or [enforce](#enforce) for `unittest`, \nand simply importing [test_all_tests_implemented](#testalltestsimplemented) and \n[test_functions_used_in_tests](#testfunctionsusedintests) into one of your test-files.\n\n\n### guaranteed\n\nTakes no arguments.\n\nAny function, method, or class (except, for the moment, ones nested inside of other callables) \ndecorated with `@pg.testcase.guaranteed`\nthat is in the scope of unittest will force unittest to throw an exception should \nit not be in an [@pg.testcase.covers](#covers).\n\nCurrently, it is necessary to include the brackets&mdash;`()`&mdash; so that \nthe function is registered. This executes the decorator once but not the callable that \nit decorates, making it computationally inexpensive.\n\nHaving a function (or method) decorated like follows:\n\n```python\n@pg.testcase.guaranteed()\ndef foo():\n  pass\n```\n\nbut not having a test in your `unittest.TestCase` decorated by `@pg.testcase.covers(foo)` \nwould lead to a [TestsNotImplementedError](#testsnotimplementederror) being raised.\n\nThe same works for classes.\n\n\n### calls\n\nTakes no arguments.\n\nMust be used below [@pg.testcase.guaranteed](#guaranteed), otherwise it is ignored.\n\nJust like with `@pg.testcase.guaranteed`, brackets are not optional, but the execution of \nthe decorator is computationally inexpensive.\n\nA function decorated as follows:\n\n```python \n@pg.testcase.guaranteed()\n@pg.testcase.calls()\ndef foo():\n  pass\n```\n\nwith a unittest that looks something like this:\n\n```python \n# for unittest:\nclass TestExample(unittest.TestCase):\n  @pg.testcase.covers(foo)\n  def test_foo(self):\n    ...  # some code that doesn't call foo\n\n\n# for pytest:\n@pg.testcase.covers(foo)\ndef test_foo():\n  ...  # some code that doesn't call foo\n```\n\nwould lead to a [NotUsedInTestsError](#notusedintestserror) being raised. \n\nIn this scenario, if `foo` is an argument in several \n[@pg.testcase.covers](#covers),\n`@pg.testcase.calls` makes certain that `foo` is used in every test-function \ndecorated in such a way.\n\nSpecial case: For classes, `@pg.testcase.calls` guarantees that `__init__` is called.\nFor a callable class, this still holds; to guarantee that the `__call__`-method is called\nin the test, it has to be decorated by `@pg.testcase.calls` itself, not the class it belongs to. \n\n\n### covers\n\n- `args`: Give any function or method that the corresponding test is meant for.\n- `kwargs`: The value will be used like an `arg`, while the key will be ignored.\n\nFunctions and methods that weren't decorated by [@pg.testcase.guaranteed](#guaranteed) \nlead to a user-warning but are ignored otherwise.\n\nUsage might look as follows:\n\n```python \n# for unittest:\nclass TestExample(unittest.TestCase):\n  @pg.testcase.covers(function1, function2, this_key_is_ignored=function3)\n  def test_example(self):\n    ...\n\n\n# for pytest:\n@pg.testcase.covers(function1, function2, this_key_is_ignored=function3)\ndef test_example():\n  ...\n```\n\n## Functions\n\nFor `unittest`, at least one of [main](#main) or [enforce](#enforce) \nhas to be used for the [decorators](#decorators)\nto have an effect. \n\nFor `pytest`, both [test_all_tests_implemented](#testalltestsimplemented) \nand [test_functions_used_in_tests](#testfunctionsusedintests) have to be imported \ninto one of your test-files.\n\n### enforce\n\nTakes no arguments. This will likely change in the future to make it more adaptable.\n\nRun this after running all your unittests. This runs additional unittests that \ncheck which functions violated their guarantees and raise [exceptions](#exceptionstestcase) \naccordingly.\n\nIt is recommended to only use this function when using a complicated unittest-setup.\nWhen using `unittest.main()`, it is recommended to use `pg.testcase.main()` instead.\n\n### main\n\nTakes no arguments. This will likely change in the future to make it more adaptable.\n\nCalls `unittest.main()` followed by [pg.unittests.enforce](#enforce).\n\n### test_all_tests_implemented\n\nTakes no arguments.\n\nImport this into one of your files for [@pg.testcase.guaranteed](#guaranteed) and \n[@pg.testcase.covers](#covers) to have any effect.\n\n### test_functions_used_in_tests\n\nTakes no arguments.\n\nImport this and [test_all_tests_implemented](#testalltestsimplemented) \ninto one of your files for [@pg.testcase.guaranteed](#guaranteed) to \nhave any effect.\n\n## exceptions.testcase\n\n`Exceptions` are located under `pg.exceptions.testcase`.\n\nThere are two custom `Exceptions` as presented below.\n\n### TestsNotImplementedError\n\nArguments of `tg.exceptions.testcase.TestsNotImplementedError`:\n\n- `functions` (type `callable`): The callables that weren't mentioned in a \n[@pg.testcase.covers](#covers).\n\nMembers of `tg.exceptions.testcase.TestsNotImplementedError`:\n\n- `functions` (type `callable`): The callables that weren't mentioned in a \n[@pg.testcase.covers](#covers).\n- `description` (type `str`): The error string printed when the exception is raised\nand not caught.\n\nThe output of raising this exception might look something like:\n\n    <Traceback...>\n\n    pyguarantees.exceptions.testcase.TestsNotImplementedError: \n\n        No tests were implemented for the following methods and functions: \n    \n        1. Missing test-case for the following callable: \n            Name: \t\tfoo\n            Module: \t__main__\n        2. Missing test-case for the following callable: \n            Name: \t\tbar\n            Module: \t__main__\n\n### NotUsedInTestsError\nArguments of `tg.exceptions.testcase.NotUsedInTestsError`:\n\n- `functions` (type: `callable`): The callables that were mentioned in a \n[@pg.testcase.covers](#covers) but not used in the corresponding\ntest.\n\nMembers of `tg.exceptions.NotUsedInTestsError`:\n\n- `functions` (type: `callable`): The callables that were mentioned in a \n[@pg.testcase.covers](#covers) but not used in the corresponding\ntest.\n- `description` (type: `str`): The error string printed when the exception is raised\nand not caught.\n\nA possible error message might look like the following:\n    \n    <Traceback...>\n\n    pyguarantees.exceptions.testcase.NotUsedInTestsError:\n\n    The following objects were not used in their assigned tests: \n\n\t1. The following callable was not called in its assigned tests: \n\t\tName: \t\tfoo\n\t\tModule: \t__main__\n\t\tThis callable is tested but not called in the following test-cases: \n\t\t\t\t\t- Name: \tTestFoo.test_foo1\n\t\t\t\t\t   Module: \t__main__\n\t\t\t\t\t- Name: \tTestFoo.test_foo2\n\t\t\t\t\t   Module: \t__main__\n\t2. The following callable was not called in its assigned tests: \n\t\tName: \t\tbar\n\t\tModule: \tsome_module\n\t\tThis callable is tested but not called in the following test-cases: \n\t\t\t\t\t- Name: \tTestBar.test_bar\n\t\t\t\t\t   Module: \ttest_some_module\n\n\n# constraints\n\nFew things are more useful in programming than the ability to constrain a program's possible behaviors \nand communicate those constraints clearly in code. Statically typed languages do this with types, scope modifiers, \nand lifetime modifiers, among others (`int`, `static`, `private`, `const`, etc.). These are static constraints \nin that they are evaluated statically, before runtime.\n\nOftentimes, a program also has dynamic constraints, evaluated during runtime&mdash;assertions, for example. \nA function dealing with division, for example, has to deal with the special case of division by zero. \n\n`pyguarantees`, abbreviated by `pg` again, enables both types of guarantees to be \ndefined in Python where they should happen: function (or method) signatures. This is where statically typed \nlanguages put their static constraints (a typical function signature looks something like \n`scope-etc-modifiers return-type function-name(parameter-type parameter-name)`) and where in my opinion, dynamic \nconstraints belong as well.\n\nThis might have the following advantages:\n- Make code more readable by having constraints in a predefined place.\n- Make code easier to write by providing important information about APIs in a glancable way.\n- Make it possible to include information on dynamic constraints in automatically generated documentation.\n- Encourage programmers to think about these constraints while writing the functions&mdash;a type of \ntest-driven development directly at the function (seeing parts of the \"tests\" in the function-signature\nmight assist readability of code, as well). \n\nThis package is an attempt to open up at least some of these advantages to Python-users at least partially, \ngiven the constraints of the Python-language. \n\n## Example\n\n```python\nimport numpy as np\nimport pyguarantees as pg\nfrom pyguarantees.constraints import IsInt, IsClass, DynamicCheck\n\nfrom your_module import your_custom_error_callback\n\n\n# One of many built-in guarantees using one of many built-in options\n@pg.constrain.parameters(num=IsInt(minimum=3))\ndef add_one(num):\n  return num + 1\n\n\n# Use IsClass to guarantee all types and classes that don't have specific constraints \n#  in pg.constraints. If they do, it is recommended to use those specific constraints.\n@pg.constrain.parameters(\n  X=IsClass(\n    class_type=np.ndarray,\n    dynamic_checks=[\n      DynamicCheck(check=lambda x: x.min() > 0, description=\"min: 0\"),\n      DynamicCheck(check=lambda x: x.var() < 5, description=\"var < 5\"),\n      DynamicCheck(check=lambda x: x.shape == (3, 80, 80), description=\"shape (3, 80, 80\")\n    ],\n    error_callback=your_custom_error_callback\n  ),\n  mean=IsClass(class_type=np.ndarray),\n  std=IsClass(class_type=np.ndarray)\n)\n@pg.constrain.returns(IsClass(class_type=np.ndarray))\ndef normalize(X, mean, std):\n  return (X - mean) / std\n```\n\n\n\n> this README is currently under development. More is coming.\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2022 Sebastian M\u00fcller  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "guarantee testcases for callables, constrain parameters and return values of callables",
    "version": "0.1.4",
    "split_keywords": [
        "python",
        "unittest",
        "pytest",
        "test",
        "guarantees",
        "parameters",
        "constraints"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "8758c9b3ccff8358a3ee8fbdb0b282d9",
                "sha256": "59b450675ffca3dbd94fbda1b7f841741fdec10a5d1a08561cffa6df4056f9dc"
            },
            "downloads": -1,
            "filename": "pyguarantees-0.1.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8758c9b3ccff8358a3ee8fbdb0b282d9",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 29650,
            "upload_time": "2022-12-19T11:00:53",
            "upload_time_iso_8601": "2022-12-19T11:00:53.663722Z",
            "url": "https://files.pythonhosted.org/packages/9e/b9/ba5c4ff1939246c6056bb33fca85d9dc23ed59252306b6ffbabfe153dd5a/pyguarantees-0.1.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "md5": "26892773545380f75640661f8a6757a4",
                "sha256": "5d4e7c5013021291527adba92fcd68ad113acc9dad1e696adfdd600908f99717"
            },
            "downloads": -1,
            "filename": "pyguarantees-0.1.4.tar.gz",
            "has_sig": false,
            "md5_digest": "26892773545380f75640661f8a6757a4",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 23924,
            "upload_time": "2022-12-19T11:00:55",
            "upload_time_iso_8601": "2022-12-19T11:00:55.232356Z",
            "url": "https://files.pythonhosted.org/packages/b0/93/462ee07dd44d92891054b53a057e57163cdb559ef4f59b0b1a74630379be/pyguarantees-0.1.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2022-12-19 11:00:55",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "lcname": "pyguarantees"
}
        
Elapsed time: 0.03065s