{"id":38522305,"url":"https://github.com/jejung/expecting","last_synced_at":"2026-01-17T06:42:31.656Z","repository":{"id":228208940,"uuid":"773390388","full_name":"jejung/expecting","owner":"jejung","description":"Elegant assertions library","archived":false,"fork":false,"pushed_at":"2025-04-06T16:57:48.000Z","size":23,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-06T17:34:59.666Z","etag":null,"topics":["python","python3","testing","testing-tools","unit-testing"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/expecting/","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/jejung.png","metadata":{"files":{"readme":"README.md","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-03-17T14:37:41.000Z","updated_at":"2025-04-06T16:57:51.000Z","dependencies_parsed_at":"2024-03-23T23:31:42.471Z","dependency_job_id":"2b8762be-d81f-47ab-9573-3bc3bec1ab01","html_url":"https://github.com/jejung/expecting","commit_stats":null,"previous_names":["jejung/expecting"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/jejung/expecting","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jejung%2Fexpecting","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jejung%2Fexpecting/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jejung%2Fexpecting/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jejung%2Fexpecting/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jejung","download_url":"https://codeload.github.com/jejung/expecting/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jejung%2Fexpecting/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28502819,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T04:31:57.058Z","status":"ssl_error","status_checked_at":"2026-01-17T04:31:45.816Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["python","python3","testing","testing-tools","unit-testing"],"created_at":"2026-01-17T06:42:31.510Z","updated_at":"2026-01-17T06:42:31.652Z","avatar_url":"https://github.com/jejung.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# expecting\n\nElegant assertions library.\n\nThis is currently a work in progress.\n\n* [`expecting.dict`](#expectingdict): Dictionary assertions, combined with other assertions makes it easier to verify complex dictionary schemas.\n* [`expecting.list`](./src/expecting/dict): Utility assertions, like order agnostic comparisons.\n* [`expecting.enum`](./src/expecting/enum): Enum related assertions, checking values, names, or instances.\n* [`expecting.number`](./src/expecting/number): Simple number comparisons, the small building blocks for more complex structured data checking.\n* [`expecting.string`](./src/expecting/string): A variety of formats like date and time, URL, UUID.\n\n\n## Installation options\n\n```bash\npip install expecting\n```\n```bash\npoetry add expecting --group dev\n```\n\n## Usage\n\nExpecting consists of a set of assertion objects that can be used with `assert` statements in a clear, readable way.\nMost common assertion will be covered under a structured set of modules, following an intuitive naming schema:\n\n```python\nimport expecting\n\nassert '2023-10-11' == expecting.string.datetime.iso8601_day()\n```\n\nHere, the `expcting.string.datetime` module introduces a handful of factory methods for asserting that the value is a\nstring representing a date and time format.\n\nIt's specially useful with [pytest](https://docs.pytest.org/)  and its amazing error messages, where an assertion\nfailure message would look something like:\n\n```text\nstring/test_datetime.py:7 (test_iso8601_full_matches[2023/10/11 13:01:10])\n'2023/10/11 13:01:10' != ~= \u003cdatetime as \"%Y-%m-%dT%H:%M:%S.%f%z\"\u003e\n\nExpected :~= \u003cdatetime as \"%Y-%m-%dT%H:%M:%S.%f%z\"\u003e\nActual   :'2023/10/11 13:01:10'\n\u003cClick to see difference\u003e\n\ndatetime_str = '2023/10/11 13:01:10'\n\n    @pytest.mark.parametrize(\n        'datetime_str',\n        (\n            '2023/10/11 13:01:10',\n        )\n    )\n    def test_iso8601_full_matches(datetime_str: str):\n\u003e       assert datetime_str == expecting.string.datetime.iso8601_full()\nE       assert '2023/10/11 13:01:10' == ~= \u003cdatetime as \"%Y-%m-%dT%H:%M:%S.%f%z\"\u003e\n...\n```\n\nThe `~=` symbol prefixing the expected value is used denote this value is an \"expecting object\".\n\n## Contributing\n\nFeel free to create issues or merge requests with any improvement or fix you might find useful.\n\n## API reference\n\n* [`expecting.dict`](#expectingdict)\n  * [`containing`](#expectingdictcontaining)\n* [`expecting.enum`](#expectingenum)\n  * [`any_value_of`](#expectingenumany_value_of)\n* [`expecting.list`](#expectinglist)\n  * [`containing`](#expectinglistcontaining)\n  * [`unordered`](#expectinglistunordered)\n* [`expecting.number`](#expectingnumber)\n  * [`expecting.number.any`](#expectingnumberany)\n  * [`expecting.number.ge`](#expectingnumberge)\n  * [`expecting.number.le`](#expectingnumberle)\n  * [`expecting.number.gt`](#expectingnumbergt)\n  * [`expecting.number.lt`](#expectingnumberlt)\n  * [`expecting.number.eq`](#expectingnumbereq)\n  * [`expecting.number.ne`](#expectingnumberne)\n* [`expecting.string`](#expectingstring)\n  * [`expecting.string.datetime`](#expectingstringdatetime)\n    * [`expecting.string.datetime.iso8601_full`](#expectingstringdatetimeiso8601_full)\n    * [`expecting.string.datetime.iso8601_millisecond`](#expectingstringdatetimeiso8601_millisecond)\n    * [`expecting.string.datetime.iso8601_second`](#expectingstringdatetimeiso8601_second)\n    * [`expecting.string.datetime.iso8601_minute`](#expectingstringdatetimeiso8601_minute)\n    * [`expecting.string.datetime.iso8601_hour`](#expectingstringdatetimeiso8601_hour)\n    * [`expecting.string.datetime.iso8601_day`](#expectingstringdatetimeiso8601_day)\n    * [`expecting.string.datetime.iso8601_month`](#expectingstringdatetimeiso8601_month)\n    * [`expecting.string.datetime.iso8601_year`](#expectingstringdatetimeiso8601_year)\n  * [`expecting.string.url`](#expectingstringurl)\n    * [`expecting.string.url.with_scheme`](#expectingstringurlwith_scheme)\n    * [`expecting.string.url.with_netloc`](#expectingstringurlwith_netloc)\n    * [`expecting.string.url.with_path`](#expectingstringurlwith_path)\n    * [`expecting.string.url.with_query`](#expectingstringurlwith_query)\n    * [`expecting.string.url.with_fragment`](#expectingstringurlwith_fragment)\n    * [`expecting.string.url.with_components`](#expectingstringurlwith_components)\n    * [`expecting.string.url.any`](#expectingstringurlany)\n  * [`expecting.string.uuid`](#expectingstringuuid)\n    * [`expecting.string.uuid.v1`](#expectingstringuuidv1)\n    * [`expecting.string.uuid.v3`](#expectingstringuuidv3)\n    * [`expecting.string.uuid.v4`](#expectingstringuuidv4)\n    * [`expecting.string.uuid.v5`](#expectingstringuuidv5)\n    * [`expecting.string.uuid.hex`](#expectingstringuuidhex)\n\n## `expecting.dict`\n\n### `expecting.dict.containing`\n\nAsserts that a dictionary contains a sub-dictionary.\n\n```python\nimport expecting\n\ncurrent = {\n    'color': 'yellow',\n    'positions': [(1, 1), (2, 3), (4, 2)],\n}\nassert current == expecting.dict.containing({\n    'positions': expecting.list.containing([(2, 3)]),\n    'color': 'yellow',\n})\n```\n\n## `expecting.enum`\n\n### `expecting.enum.any_value_of`\n\nAsserts that a value represents a specific enum.\n\n```python\nimport expecting\nfrom enum import Enum\n\n\nclass AnyEnum(str, Enum):\n    OK = 'OK'\n\nassert 'OK' == expecting.enum.any_value_of(AnyEnum)\nassert 'NOK' != expecting.enum.any_value_of(AnyEnum)\n```\n\n## `expecting.list`\n\n### `expecting.list.containing`\n\nAsserts that a list contains a sub-list. Order is important.\n\n```python\nimport expecting\n\ncurrent = [1, 2, 3]\nassert current == expecting.list.containing([2, 3])\n```\n\n\n### `expecting.list.unordered`\n\nAsserts that a list contains all the values, disregarding their order.\n\n\n```python\nimport expecting\n\ncurrent = [1, 2, 3]\n\nassert current == expecting.list.unordered([3, 1, 2])\n```\n\n## `expecting.number`\n\nDisclaimer: of course writing `assert a \u003e= 1` is much easier and should be the preferred way to.\n\nThe functions under this namespace are intended for combined usage with other expecting objects for complex schema validations.\n\n### `expecting.number.any`\n\nAsserts any type of number.\n\n```python\nimport expecting.number\n\n\nassert 1 == expecting.number.any()\nassert 0 == expecting.number.any()\nassert -1.4 == expecting.number.any()\nassert 'inf' == expecting.number.any()\n```\n\n### `expecting.number.ge`\n\nAsserts number is greater than or equal to (\u003e=) given value.\n\n```python\nimport expecting\n\nassert 10 == expecting.number.ge(10)\n```\n\n### `expecting.number.le`\n\nAsserts number is lesser than or equal to (\u003c=) given value.\n\n```python\nimport expecting\n\nassert 10 == expecting.number.le(10)\n```\n\n### `expecting.number.gt`\n\nAsserts number is greater than (\u003e) given value.\n\n```python\nimport expecting\n\nassert 10 == expecting.number.gt(9)\n```\n\n### `expecting.number.lt`\n\nAsserts number is lesser than (\u003c) given value.\n\n```python\nimport expecting\n\nassert 10 == expecting.number.lt(11)\n```\n\n### `expecting.number.eq`\n\nAsserts number is equals to given value.\n\n```python\nimport expecting\n\nassert 10 == expecting.number.eq(10)\n```\n\n### `expecting.number.ne`\n\nAsserts number is not equals to given value.\n\n```python\nimport expecting\n\nassert 10 == expecting.number.ne(9)\n```\n\n## `expecting.string`\n### `expecting.string.datetime`\n### `expecting.string.datetime.iso8601_full`\n\nAsserts string is a valid ISO8601 full format, considering the timezone Z or UTC offset versions.\n\n```python\nfrom datetime import datetime\nimport expecting\n\nassert datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f+000000.000000') == expecting.string.datetime.iso8601_full()\nassert datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%fZ') == expecting.string.datetime.iso8601_full()\n```\n\n### `expecting.string.datetime.iso8601_millisecond`\n\nAsserts string is a valid ISO8601 format up to the milliseconds.\n\n```python\nfrom datetime import datetime\nimport expecting\n\nassert datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f') == expecting.string.datetime.iso8601_millisecond()\n```\n\n### `expecting.string.datetime.iso8601_second`\n\nAsserts string is a valid ISO8601 format up to the seconds\n\n```python\nfrom datetime import datetime\nimport expecting\n\nassert datetime.now().strftime('%Y-%m-%dT%H:%M:%S') == expecting.string.datetime.iso8601_second()\n```\n\n### `expecting.string.datetime.iso8601_minute`\n\nAsserts string is a valid ISO8601 format up to the minutes.\n\n```python\nfrom datetime import datetime\nimport expecting\n\nassert datetime.now().strftime('%Y-%m-%dT%H:%M') == expecting.string.datetime.iso8601_minute()\n```\n\n### `expecting.string.datetime.iso8601_hour`\n\nAsserts string is a valid ISO8601 format up to the hours.\n\n```python\nfrom datetime import datetime\nimport expecting\n\nassert datetime.now().strftime('%Y-%m-%dT%H') == expecting.string.datetime.iso8601_hour()\n```\n\n### `expecting.string.datetime.iso8601_day`\n\nAsserts string is a valid ISO8601 format up to the day.\n\n```python\nfrom datetime import datetime\nimport expecting\n\nassert datetime.now().strftime('%Y-%m-%d') == expecting.string.datetime.iso8601_day()\n```\n\n### `expecting.string.datetime.iso8601_month`\n\nAsserts string is a valid ISO8601 format up to the month.\n\n```python\nfrom datetime import datetime\nimport expecting\n\nassert datetime.now().strftime('%Y-%m') == expecting.string.datetime.iso8601_month()\n```\n\n### `expecting.string.datetime.iso8601_year`\n\nAsserts string is a valid ISO8601 format up to the Year.\n\n```python\nfrom datetime import datetime\nimport expecting\n\nassert datetime.now().strftime('%Y') == expecting.string.datetime.iso8601_year()\n```\n\n### `expecting.string.url`\n### `expecting.string.url.with_scheme`\n\nAssert that a string is a valid URL with the given scheme.\n\n```python\nimport expecting\n\nassert 'https://example.com' == expecting.string.url.with_scheme('https')\n```\n\n### `expecting.string.url.with_netloc`\n\nAssert that a string is a valid URL with the given netloc (host and optionally port).\n\n```python\nimport expecting\n\nassert 'https://example.com:8080' == expecting.string.url.with_netloc('example.com:8080')\nassert 'https://example.com' == expecting.string.url.with_netloc('example.com')\nassert 'http://example.com' == expecting.string.url.with_netloc('example.com')\n```\n\n### `expecting.string.url.with_path`\n\nAssert that a string is a valid URL with the given path.\n\n```python\nimport expecting\n\nassert 'https://example.com/' == expecting.string.url.with_path('/')\nassert 'https://example.com' == expecting.string.url.with_path('')\nassert 'https://example.com/some/subfolder' == expecting.string.url.with_path('/some/subfolder')\n```\n\n\n### `expecting.string.url.with_query`\n\nAssert that a string is a valid URL with the given query string.\n\n```python\nimport expecting\n\nassert 'http://example.com?key=value' == expecting.string.url.with_query('key=value')\nassert 'http://example.com?key=value\u0026other' == expecting.string.url.with_query('key=value\u0026other')\nassert 'http://example.com?' == expecting.string.url.with_query('')\nassert 'http://example.com' == expecting.string.url.with_query('')\n```\n\n\n### `expecting.string.url.with_fragment`\n\nAssert that a string is a valid URL with the given fragment.\n\n```python\nimport expecting\n\nassert 'https://example.com/path#anchor' == expecting.string.url.with_fragment('anchor')\nassert 'https://example.com/path#' == expecting.string.url.with_fragment('')\nassert 'https://example.com/path' == expecting.string.url.with_fragment('')\nassert 'https://example.com' == expecting.string.url.with_fragment('')\n```\n\n\n### `expecting.string.url.with_components`\n\nAssert that a string is a valid URL with the given components.\n\n```python\nimport expecting\n\nassert 'https://example.com/path?query=1#anchor' == expecting.string.url.with_components(\n    scheme='https',\n    netloc='example.com',\n    path='/path',\n    query='query=1',\n    fragment='anchor',\n)\n```\n\n\n### `expecting.string.url.any`\n\nAssert that a string is a valid URL.\n\n```python\nimport expecting\n\nassert 'https://example.com/path?query=1#anchor' == expecting.string.url.any()\nassert 'ws://127.0.0.1/ws/' == expecting.string.url.any()\n```\n\n### `expecting.string.uuid`\n### `expecting.string.uuid.v1`\n\nAsserts that a string is a valid UUID v1 hex\n\n```python\nimport uuid\nimport expecting\n\nassert str(uuid.uuid1()) == expecting.string.uuid.v1()\n```\n\n### `expecting.string.uuid.v3`\n\nAsserts that a string is a valid UUID v3 hex\n\n```python\nimport uuid\nimport expecting\n\nassert str(uuid.uuid3(uuid.uuid1(), 'bogus')) == expecting.string.uuid.v3()\n```\n\n### `expecting.string.uuid.v4`\n\nAsserts that a string is a valid UUID v4 hex\n\n```python\nimport uuid\nimport expecting\n\nassert str(uuid.uuid4()) == expecting.string.uuid.v4()\n```\n\n### `expecting.string.uuid.v5`\n\nAsserts that a string is a valid UUID v5 hex\n\n```python\nimport uuid\nimport expecting\n\nassert str(uuid.uuid5(uuid.uuid1(), 'bogus')) == expecting.string.uuid.v5()\n```\n\n### `expecting.string.uuid.hex`\n\nAsserts that a string is a valid UUID hex, disregarding the version.\n\n```python\nimport uuid\nimport expecting\n\nassert str(uuid.uuid1()) == expecting.string.uuid.hex()\nassert str(uuid.uuid3(uuid.uuid1(), 'bogus')) == expecting.string.uuid.hex()\nassert str(uuid.uuid4()) == expecting.string.uuid.hex()\nassert str(uuid.uuid5(uuid.uuid1(), 'bogus')) == expecting.string.uuid.hex()\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjejung%2Fexpecting","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjejung%2Fexpecting","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjejung%2Fexpecting/lists"}