{"id":13771566,"url":"https://github.com/nyggus/easycheck","last_synced_at":"2026-02-27T15:31:58.038Z","repository":{"id":39586489,"uuid":"299679906","full_name":"nyggus/easycheck","owner":"nyggus","description":"A module offering Python functions for simple and readable assertion-like checks to be used inside code, but also in testing.","archived":false,"fork":false,"pushed_at":"2025-05-26T08:45:56.000Z","size":340,"stargazers_count":23,"open_issues_count":24,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-09-25T16:49:14.158Z","etag":null,"topics":["assertion","python3","testing","unit-testing"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nyggus.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-09-29T16:48:29.000Z","updated_at":"2025-06-11T09:37:22.000Z","dependencies_parsed_at":"2024-02-08T08:23:33.921Z","dependency_job_id":"cba82734-1ffc-4bb1-a357-4f8ee06710b4","html_url":"https://github.com/nyggus/easycheck","commit_stats":{"total_commits":181,"total_committers":5,"mean_commits":36.2,"dds":0.3812154696132597,"last_synced_commit":"750a1d33e29c77e94a8ede21681008bc73cf2f39"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/nyggus/easycheck","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyggus%2Feasycheck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyggus%2Feasycheck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyggus%2Feasycheck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyggus%2Feasycheck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nyggus","download_url":"https://codeload.github.com/nyggus/easycheck/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyggus%2Feasycheck/sbom","scorecard":{"id":699841,"data":{"date":"2025-08-11","repo":{"name":"github.com/nyggus/easycheck","commit":"5d57140a214d10011dded272af05b7ecf45acf03"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.8,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":10,"reason":"all changesets reviewed","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/check.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/check.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/nyggus/easycheck/check.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/check.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/nyggus/easycheck/check.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/check.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/nyggus/easycheck/check.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/check.yml:30","Warn: pipCommand not pinned by hash: .github/workflows/check.yml:31","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   2 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-22T04:56:36.481Z","repository_id":39586489,"created_at":"2025-08-22T04:56:36.481Z","updated_at":"2025-08-22T04:56:36.481Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280330689,"owners_count":26312547,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-21T02:00:06.614Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assertion","python3","testing","unit-testing"],"created_at":"2024-08-03T17:00:52.840Z","updated_at":"2025-10-21T20:38:52.368Z","avatar_url":"https://github.com/nyggus.png","language":"Python","funding_links":[],"categories":["Assertions"],"sub_categories":[],"readme":"easycheck\n=========\n.. image:: https://github.com/nyggus/easycheck/actions/workflows/check.yml/badge.svg\n   :target: https://github.com/nyggus/easycheck/actions/workflows/check.yml\n.. image:: https://codecov.io/github/nyggus/easycheck/branch/master/graph/badge.svg?token=EH4TLHQQWC \n   :target: https://codecov.io/github/nyggus/easycheck\n.. image:: https://img.shields.io/pypi/l/easycheck.svg\n   :target: https://pypi.org/project/easycheck     \n.. image:: https://img.shields.io/pypi/v/easycheck.svg\n   :target: https://pypi.org/project/easycheck     \n.. image:: https://img.shields.io/pypi/wheel/easycheck\n   :target: https://pypi.org/project/easycheck     \n.. image:: https://img.shields.io/pypi/pyversions/easycheck\n   :target: https://pypi.org/project/easycheck\n.. image:: https://img.shields.io/github/stars/nyggus/easycheck?style=social\n   :target: https://github.com/nyggus/easycheck\n.. image:: https://img.shields.io/github/last-commit/nyggus/easycheck\n\nThe :code:`easycheck` package offers a lightweight tool for running functionized checks within Python code; it also offers functions to be used in testing - particularly in doctests, but also in pytests, for which purpose some of the functions have dedicated aliases (starting off with :code:`assert_` instead of :code:`check_`). You can also switch off all :code:`easycheck` checks, by setting the :code:`\"EASYCHECK_RUN\"` environmental variable to :code:`\"0\"`.\n\nThe idea is to use the :code:`easycheck` functions to check conditions that are _not_ assertions. The checks work in the following general way: When a condition is met, nothing happens (in fact, the function returns :code:`None`); if it is violated, an exception is raised or a warning is issued. The main differences between :code:`easycheck` functions and assertions are as follows:\n\n* Assertions are meant to be used conditions that _must_ be true (when only the code is correct). So, if an assertion is incorrect, it means something is wrong with the code. You should never use assertions to handle regular exceptions, like those related to data or arguments.\n* Unlike assertions, :code:`easycheck` functions are to be used to check conditions related to things like data and argument values, and to handle regular exceptions.\n* While assertions only raise :code:`AssertionError`, you can choose any exception to be raised by easycheck functions.\n* When using :code:`easycheck`, instead of raising an exception, you can issue a warning.\n\nThe main :code:`easycheck` functions (with names starting off with :code:`check_`) are designed in such a way that they can be used as easy-to-understand code that checks whether one or more conditions are met. They can be used instead of :code:`if`-blocks, which are normally used to check conditions and raise exceptions (or issue warnings) if they are not met. So, you can do the following:\n\n.. code-block:: python\n\n    if not isinstance(x, (float, int)):\n        raise TypeError('x must be a number')\n    if x \u003e 10:\n        raise ValueError('Too high value of x')\n\nor you can use :code:`easycheck` for this:\n\n.. code-block:: python\n\n    check_type(x, (float, int), message='x must be a number')\n    check_if(x \u003c= 10, ValueError, 'Too high value of x')\n\nThe :code:`easycheck` approach has two main advantages over this classical approach:\n\n* It saves a little space; not much, since most often you'll end up with one line of code instead of two, but not always, particularly when you provide an exception type to be raised and a long message. \n* Mainly, it increases code simplicity and readability, since both the names of easycheck functions and their arguments are designed in such a way that the reader immediately understands what is being checked.\n\nYou can also issue a warning:\n\n.. code-block:: python\n\n    check_if(x \u003c= 10,\n             Warning,\n             'For stable functioning of the function, '\n             'x should not be greater than 10.')\n\nThe package also offers functions dedicated to testing, e.g.,\n\n.. code-block:: python\n\n    assert_type(x, (float, int))\n    assert_if(x \u003c= 10)\n\nThe :code:`message` argument has the default value of :code:`None`, which does the following. If the exception class provided in :code:`handle_with` is built-in (that is, can be found in :code:`dir(builtins)`), no message is provided. But if it is not a built-in exception (or warning) class, then the exception/warning class's docstring is taken as the message. This is a convenient way of providing a  typical message. If you want to customize the message (e.g., depending on the value of a variable), you should use a customized string (e.g., through an f-string). But if you do not want to use any message with a custom exception/warning, simply provide an empty string (:code:`message=''`).\n\n**Warning!** Note that :code:`assert_*` functions do not have the :code:`handle_with` argument. This is because they are designed to work as true assertions, so they work with :code:`AssertionError` only.\n\n\nRead about :code:`easycheck`\n----------------------------\n\nYou will find more about assertions in `this article \u003chttps://medium.com/towards-data-science/python-assertions-or-checking-if-a-cat-is-a-dog-ce11c55d143\u003e`_, entitled \"Python Assertions, or Checking If a Cat Is a Dog\" and published in *Towards Data Science*. It mentions :code:`easycheck`! You will read about :code:`easycheck` also in `the article \"Comparing floating-point numbers with easycheck\" \u003chttps://medium.com/towards-data-science/comparing-floating-point-numbers-with-easycheck-dcbae480f75f\u003e`_  (also from *Towards Data Science*). The *Better Programming* article entitiled `\"How to Overwrite AssertionError in Python and Use Custom Exceptions\" \u003chttps://medium.com/better-programming/how-to-overwrite-asserterror-in-python-and-use-custom-exceptions-c0b252989977\u003e`_, mentions the package, too.\n\n\nInstalling\n----------\n\nInstall and update using pip:\n\n.. code-block:: text\n\n    pip install easycheck\n\nTesting\n-------\n\nThe package is covered with both pytests and doctests. The latter are included in both docstrings of all the functions, but also in `documentation files \u003chttps://github.com/nyggus/easycheck/tree/master/docs\u003e`_.\n\nUse in code to raise exceptions\n-------------------------------\n\nHere are several examples of a simple use of basic :code:`easycheck` functions. The most basic usage resembles the following:\n\n.. code-block:: python\n\n    check_if(a \u003c 10)\n\t\nThis simply checks if :code:`a` is smaller than 10; if it is, nothing happens (in fact, :code:`check_if(a \u003c 10)` returns :code:`None`). But if the condition is violated, the function raises :code:`AssertionError`. :code:`AssertionError` is the default exception returned by :code:`check_if()`, but you can change this:\n\n.. code-block:: python\n\n    check_if(a \u003c 10, handle_with=ValueError)\n    # or shorter and equally readable:\n    check_if(a \u003c 10, ValueError)\n\nFor built-in exceptions, like :code:`ValueError`, the default behaviour is to not print any message. For custom exceptions, however, the exception's docstring (`.__doc__`) serves as a message. You can use this when you create custom exceptions:\n\n.. code-block:: python\n\n    class IncorrectNameTypeError(Exception):\n        \"\"\"Argument name must be a string.\"\"\"\n    \n    name = 40\n    check_type(name, IncorrectNameTypeError)\n    Traceback (most recent call last):\n      ...\n    IncorrectNameTypeError: Argument name must be a string.\n\nIf you want to ensure that no message is printed, even for a custom exception, override the default behaviour by passing an empty string :code:`message=''`. You can also add a custom message:\n\n.. code-block:: python\n\n    check_if(a \u003c 10, handle_with=ValueError, message='Too high a')\n    # or shorter and equally readable:\n    check_if(a \u003c 10, ValueError, 'Too high a')\n\nSome other functions have different default errors; for instance, this call\n\n.. code-block:: python\n\n    check_type(a, expected_type=str)\n    # or shorter:\n    check_type(a, str)\n\nwill raise :code:`TypeError` while this\n\n.. code-block:: python\n\n    check_length([1, 2, 3], 1)\n\t\nwill raise :code:`LengthError` (an exception class defined in the :code:`easycheck` module).\n\nHere is a list of :code:`easycheck` check functions the module offers, discluding assertions, which are listed in the next paragraph:\n\n* :code:`check_if()`; it's the most basic :code:`easycheck` function, similar to what you would get using :code:`if`;\n* :code:`check_if_not()`; the opposite of :code:`check_if()`, helpful when you need to assure that a condition is *not* met;\n* :code:`check_if_isclose()`; to compare two floating-point numbers, based on :code:`match.isclose()` (see `this file \u003chttps://github.com/nyggus/easycheck/blob/master/docs/compare_floats_doctest.rst\u003e`__);\n* :code:`check_if_in_limits()`; to check if a number lies between two other numbers;\n* :code:`check_length()`; to compare length (equal to, smaller than, greater than, and the like);\n* :code:`check_type()`; to check expected type, similar to :code:`isinstance()`;\n* :code:`check_if_paths_exist()`; to compare paths (or just one path) exist;\n* :code:`check_comparison()` (used to compare two items); to compare two objects, just like you would do using :code:`if obj1 != obj2: raise`\n* :code:`check_all_ifs()`; used to check multiple conditions and return all the checks;\n* :code:`check_argument()`; used to make one or more checks of a function's argument.\n\nYou can also use a :code:`catch_check()` function, if you want to catch an exception or a warning the :code:`easycheck` function you use would raise (see examples `here \u003chttps://github.com/nyggus/easycheck/blob/master/docs/catch_exceptions_doctest.rst\u003e`_). Sometimes, however, you will do better using a :code:`try-except` block to catch exceptions (`see examples \u003chttps://github.com/nyggus/easycheck/blob/master/docs/use_with_try_doctest.rst\u003e`__).\n\n\u003e Note that some :code:`easycheck` functions are simple wrappers around built-in functions, but their behavior is different, as they have the typical behavior of an :code:`easycheck` function: if a condition is not met, an exception is raised or an issue is raised.\n\n\nAssertions\n----------\n\nIn addition to the above checking functions, :code:`easycheck` provides a set of functions for assertions. They can be used in both code and tests, just like regular assertions using the :code:`assert` statement. Assertion functions do have a specific functionality that makes them different from the corresponding check functions. You can read more about it `here \u003chttps://towardsdatascience.com/python-assertions-or-checking-if-a-cat-is-a-dog-ce11c55d143\u003e`__. In short, assertions are called only in the development (non-production) mode, that is, when :code:`__debug__` is set to :code:`True`. An assertion should check a condition that should never happen; when the corresponding exception is raised, it means that something went wrong in the code, that something that should never happen has just happened.\n\nSome examples:\n\nYou are working only on integers, for example pixels when rendering images, or placing objects on a board. You are sure that output will be integer, so you can assert on integers:\n\n.. code-block:: python\n    \n    def convert_to_pixel_position(real_pos: tuple[float, float]):\n        pos_x = real_pos[0]\n        pos_y = real_pos[1]\n        pixel_pos_x = round(pos_x)\n        pixel_pos_y = round(pos_y)\n        return pixel_pos_x, pixel_pos_y\n\n    pos = convert_to_pixel_position((1.2, 3.4))\n    assert_type(pos, tuple)\n    assert_type(pos[0], int)\n\nNow consider a different example. Imagine you have output from some `len()` method, or any other method calculating the length of something:\n\n.. code-block:: python\n\n    out = len(example_object)\n    # doing something with out, like\n    number_of_elements_required = out * no_of_objects\n    assert_type(out_for_something_else, int)\n\nYou are working on subset of some data. So the size of the data should not be larger than the initial one, but also not smaller than 0:\n\n.. code-block:: python\n\n    def subset_of(data: pd.DataFrame, filter_condition: callable) -\u003e pd.DataFrame:\n        # create a data frame that is a subset of `data` based on `filter_condition`\n        ...\n    x = pd.DataFrame({'x': [1, 2, 4], 'y': [3, 3, 5]})\n    x_subset = subset_of(x, lambda value: value \u003c 3)\n    assert_if_in_limits(len(x_subset), 0, len(x))\n\nHere is full list of supported assert functions:\n\n* :code:`assert_if()`; it's the most basic :code:`easycheck` function, similar to what you would get using :code:`if`;\n* :code:`assert_if_not()`; the opposite of :code:`assert_if()`, helpful when you need to assure that a condition is *not* met;\n* :code:`assert_if_isclose()`; to assert whether two floating-point numbers are close enough, based on :code:`match.isclose()` (see `this file \u003chttps://github.com/nyggus/easycheck/blob/master/docs/compare_floats_doctest.rst\u003e`__);\n* :code:`assert_if_in_limits()`; to assert whether a number is in range of two other numbers;\n* :code:`assert_length()`; to assert length (equal to, smaller than, greater than, and the like);\n* :code:`assert_type()`;to assert that an object has a particular type, as you would do using :code:`assert isinstance`;\n* :code:`assert_paths()`; to assert that a path exists or paths exist.\n\nUse in code to issue warnings\n-----------------------------\n\nIn order to issue a warning if a condition is violated, simply use a warning class (in the :code:`handle_with` argument) instead of an exception class:\n\n.. code-block:: python\n\n    check_if(2 \u003e 1, Warning, 'Too high a value')\n    check_length([1, 2, 3], 10, Warning, 'Too short list with data')\n\nRemember to always use a message with warnings, in order to make them meaningful. (See more in `use_with_warnings_doctest.rst \u003chttps://github.com/nyggus/easycheck/blob/master/docs/use_with_warnings_doctest.rst\u003e`_).\n\n\nOf course, you can use a custom warning:\n\n.. code-block:: python\n\n    class TooSmallSampleSize(Warning):\n        \"\"\"Results for samples size below 100 can be unstable.\"\"\"\n    \n    n = 50\n    check_if(n \u003e= 100, TooSmallSampleSize)\n    ... TooSmallSampleSize: Results for samples size below 100 can be unstable.\n      warnings.warn(message, error)\n\n\nUse in code, an example\n-----------------------\n\nImagine you want to connect to a database; if the connection fails for any reason, you want to read an archived flat file. (We will use some undefined functions whose names will clearly convey what the functions do.)\n\n.. code-block:: python\n\n    from easycheck import check_if, check_if_paths_exist\n    \n    class DataBaseConnectionError(Exception):\n        pass\n    \n    def get_data_from_db(db_details, db_credentials):\n        try:\n            connect_to_db(db_details, db_credentials)\n        except:\n            return False\n        data = get_records_from_db()\n        return data\n\nThe :code:`easycheck` code could look like the following:\n\n.. code-block:: python\n\n    def get_data(db_details, db_credentials):\n        data = get_data_from_db(db_details, db_credentials)\n        check_if(\n            data,\n            handle_with=DataBaseConnectionError,\n            message='Cannot communicate with the database'\n            )\n        return data\n              \nYou can of course handle this exception, for example like here:\n\n.. code-block:: python\n\n    def get_data(db_details, db_credentials, archived_data_file):\n        data = get_data_from_db(db_details, db_credentials)\n        try:\n            check_if(\n                data,\n                handle_with=DataBaseConnectionError,\n                message='Cannot communicate with the database'\n            )\n        except DataBaseConnectionError:\n            check_if_paths_exist(archived_data_file)\n            with open(archived_data_file) as f:\n                data = f.readlines()\n        return data\n    \nOf course, you might use here a dedicated context manager. Sure, you can write it in a shorter way, without :code:`easycheck`, but the flow of information will not be as smooth, resulting in less readability:\n\n.. code-block:: python\n\n    def get_data(db_details, db_credentials, archived_data_file):\n        data = get_data_from_db(db_details, db_credentials)\n        if not data:\n            with open(archived_data_file) as f:\n                data = f.readlines()\n        return data\n\nOf course, the :code:`open()` context manager will itself throw an error, but when you use the :code:`check_if()` function and explicitly define an exception class, you clearly show the reader that you're checking if this file exists and raise a particular exception if it doesn't.\n        \nUse in testing\n--------------\n\nAs mentioned above, most :code:`easycheck` functions have their asserts counterparts which can be used in testing. Of course, you can use :code:`check_if()`, but to align with the common use of assertions, the :code:`easycheck` module offers those aliases so that the reader will immediately see that you're using these functions to test. Consider these examples:\n\n.. code-block:: python\n\n    # Using assertions\n    def test_something():\n        a, b = my_function_1(), my_function_2()\n\n        assert a == 2; \n        assert isinstance(a, int)\n        assert isinstance(b, tuple)\n        assert len(b) == 5\n\t\t\n    # Using easycheck assert-like functions:\n    def test_something():\n        a, b = my_function_1(), my_function_2()\n        \n        assert_if(a == 2)\n        assert_type(a, int)\n        assert_type(b, tuple)\n        assert_length(b, 5)\n\nNote that only the first one will raise :code:`AssertionError` while the others will raise more meaningful errors (:code:`TypeError` and :code:`LengthError`), which may better explain the reasons that the tests did not pass.\n\nYou will find more about using :code:`easycheck` in `use_in_testing_doctest.rst \u003chttps://github.com/nyggus/easycheck/blob/master/docs/use_in_testing_doctest.rst\u003e`_.\n\nOther examples\n--------------\n\nYou will find a number of examples in `doctest files \u003chttps://github.com/nyggus/easycheck/tree/master/docs/\u003e`_, which also serve as doctests.\n\n\nSwitching off :code:`easycheck`\n-------------------------------\n\nIf you want to maximize performance, you may wish to switch off :code:`easycheck` checks. You would get the greatest increase in performance by removing (or commenting out) all calls to :code:`easycheck` functions, but this can be inconvenient. Hence, :code:`easycheck` offers you a more convenient way of doing so, namely, switching off via an environmental variable. This will be less efficient, as this will mean calling an empty function instead of actual :code:`easycheck` functions. While not the most performant, this approach can increase performance quite significantly. Its obvious advantage is that you do not need to do anything else than just setting the :code:`\"EASYCHECK_RUN\"` environmental variable to :code:`\"0\"`:\n\n.. code-block:: shell\n\n    \u003e EASYCHECK_RUN = 0\n    \u003e python my_script.py\n\nThe my_script.py script will be run with all :code:`easycheck` functions replaced with an empty function.\n\nYou can also switch off easycheck directly from Python:\n\n.. code-block:: python\n\n    import os\n\n    os.environ[\"EASYCHECK_RUN\"] = \"0\"\n\n\u003e **Warning**: Do remember to use this option wisely. While it will increase performance, it can also change the behavior of the Python program.\n\n\nChangelog\n---------\n\n* Version 0.11.0 came with a change in the building backend, from setup.py-based to pyproject.toml- and `build`-based. Documentation tests are now configured to be run by :code:`pytest`, so the :code:`pytest` command runs all the :code:`pytest` and :code:`doctest` tests. Several documentation tests have been also fixed.\n* Version 0.6.0 came with significant optimization of performance. Before, :code:`easycheck` functions performed internal checks of the argument values provided to the function call. Most of these checks are not performed anymore, at least not for the most significant :code:`easycheck` functions, such as :code:`check_if()` or :code:`check_type()`. Some checks, however, are still done. These are mainly checks without which the behavior of the function would be either unwanted or unexpected. We decided to remove all checks that do not change much; for instance, they raise an error due to an incorrect type of an argument value — even though it would be raised anyway, but by the internal Python process, not by the :code:`easycheck` function itself. The point is to remove such unnecessary checks and that way remove the unnecessary :code:`if` blocks, which certainly add some cost to execution time. While one such check costs almost nothing, many of them (e.g., in a long loop) can mean a significant cost. As of version 0.6.0, we will try to optimize the performance of :code:`easycheck` by getting rid of such overhead costs, unless they are important for the behavior of the corresponding :code:`easycheck` function.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnyggus%2Feasycheck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnyggus%2Feasycheck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnyggus%2Feasycheck/lists"}