{ "info": { "author": null, "author_email": "Manuel Da Pena ", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed" ], "description": "\n
\n\n

\n \"Pyventus\"\n

\n\n
\n\n

\n\n\n \"Tests\"\n\n\n\n \"Docs\"\n\n\n\n\tCoverage Status\n\n\n\n \"Package\n\n\n\n \"Supported\n\n\n\n\t\"Code\n\n\n

\n\n
\n\n---\n\n**Documentation**: https://mdapena.github.io/pyventus\n\n**Source Code**: https://github.com/mdapena/pyventus\n\n---\n\n

\n   Pyventus is a powerful Python package for event-driven programming. It offers a comprehensive suite\n\tof tools to easily define, emit, and orchestrate events. With Pyventus, you can build scalable, extensible, and\n\tloosely-coupled event-driven applications.\n

\n\n[//]: # (--------------------------------------------------------------------------------------------------------------)\n\n## Key Features\n\n

\n Pyventus offers several key features, such as:\n

\n\n\n\n[//]: # (--------------------------------------------------------------------------------------------------------------)\n\n## Quick Start\n\n

\n\t  Pyventus is published as a Python package \n\tand can be installed using pip, ideally in a virtual environment\n\tfor proper dependency isolation. To get started, open up a terminal and install Pyventus with the following command:\n

\n\n```console\npip install pyventus\n```\n\n

\n\t  Pyventus by default relies on the Python standard library and requires Python 3.10 or higher with no \n\tadditional dependencies. However, this package also includes alternative integrations to access additional features \n\tsuch as Redis Queue, Celery, and FastAPI. For more information on this matter, please refer to the \n\tOptional Dependencies\n\tsection.\n

\n\n[//]: # (--------------------------------------------------------------------------------------------------------------)\n\n## A Simple Example\n\n

\n   Experience the power of Pyventus through a simple Hello, World! example that illustrates\n\tthe core concepts and basic usage of the package. By following this example, you\u2019ll learn how to subscribe to events\n\tand emit them within your application.\n

\n\n```Python title=\"Hello, World! Example\" linenums=\"1\"\nfrom pyventus import EventLinker, EventEmitter, AsyncIOEventEmitter\n\n\n@EventLinker.on(\"GreetEvent\")\ndef handle_greet_event():\n print(\"Hello, World!\")\n\n\nevent_emitter: EventEmitter = AsyncIOEventEmitter()\nevent_emitter.emit(\"GreetEvent\")\n```\n\n
\nYou can also work with async functions and contexts...\n\n```Python title=\"Hello, World! Example (Async version)\" linenums=\"1\" hl_lines=\"5\"\nfrom pyventus import EventLinker, EventEmitter, AsyncIOEventEmitter\n\n\n@EventLinker.on(\"GreetEvent\")\nasync def handle_greet_event():\n print(\"Hello, World!\")\n\n\nevent_emitter: EventEmitter = AsyncIOEventEmitter()\nevent_emitter.emit(\"GreetEvent\")\n```\n\n
\n\n

\n   As we can see from the Hello, World! example, Pyventus follows a simple and intuitive \n\tworkflow for defining and emitting events. Let's recap the essential steps involved:\n

\n\n
    \n\n
  1. \nImporting Necessary Modules: \nWe first imported the required modules from Pyventus, which encompassed the EventLinker\nclass, the EventEmitter interface, and the AsyncIOEventEmitter implementation.\n
  2. \n\n
  3. \nLinking Events to Callbacks: \nNext, we used the @EventLinker.on() decorator to define and link the string event GreetEvent \nto the function handle_greet_event(), which will print 'Hello, World!' to the console whenever the\nGreetEvent is emitted.\n
  4. \n\n
  5. \nInstantiating an Event Emitter: \nAfter that, and in order to trigger our event, we needed to create an instance of the event emitter class. While \nAsyncIOEventEmitter was utilized, any built-in\nor custom implementation could be employed.\n
  6. \n\n
  7. \nTriggering the Event:\nFinally, by using the emit() method of the event emitter instance, we were able to trigger the \nGreetEvent, which resulted in the execution of the handle_greet_event() callback.\n
  8. \n\n
\n\n

\n   Having gained a clear understanding of the workflow showcased in the Hello, World! example,\n\tyou are now well-equipped to explore more intricate event-driven scenarios and fully harness the capabilities of \n\tPyventus in your own projects. For a deep dive into the package's functionalities, you can refer to the \n\tPyventus Tutorials or \n\tAPI.\n

\n\n[//]: # (--------------------------------------------------------------------------------------------------------------)\n\n## A Practical Example\n\n

\n   To showcase Pyventus' event-driven capabilities in a real-world scenario, we will explore a practical \n\texample of implementing a voltage sensor using an event-driven architecture (crucial for such scenarios). The \n\tpurpose of this example is to create an efficient voltage sensor that can seamlessly handle real-time data \n\tand respond appropriately to specific voltage conditions.\n

\n\n\n
\nExample \u2500 Monitoring Voltage Levels Across Devices (Context)\n\n\n\t\"Macro\n\n\n

\n\t  A common aspect found in many systems is the need to monitor and respond to changes in sensor data.\n\tWhether it's pressure sensors, temperature sensors, or other types, capturing and reacting to sensor data is crucial\n\tfor effective system operation. In our practical example, we will focus on a specific scenario: building a sensor \n\tsystem that monitors voltage levels across devices. The goal of our voltage sensor is to detect potential issues,\n\tsuch as low or high voltage conditions, and respond appropriately in real-time.\n

\n\n
\n\n\n

\n   To accomplish our goal, we will define a VoltageSensor class to read voltage levels and emit \n\tevents based on predefined thresholds. We will create event handlers to respond to these events, performing actions \n\tsuch as activating eco-mode for low voltage or implementing high-voltage protection. Additionally, a shared event \n\thandler will provide general notifications for out-of-range voltage situations. The code example below illustrates \n\tthe implementation of this system.\n

\n\n```Python title=\"Voltage Sensor System with Pyventus (Practical Example)\" linenums=\"1\" hl_lines=\"9 14 27-30 35-36 41-42 47-48 55\"\nimport asyncio\nimport random\n\nfrom pyventus import EventEmitter, EventLinker, AsyncIOEventEmitter\n\n\nclass VoltageSensor:\n\n def __init__(self, name: str, low: float, high: float, event_emitter: EventEmitter) -> None:\n # Initialize the VoltageSensor object with the provided parameters\n self._name: str = name\n self._low: float = low\n self._high: float = high\n self._event_emitter: EventEmitter = event_emitter\n\n async def __call__(self) -> None:\n # Start voltage readings for the sensor\n print(f\"Starting voltage readings for: {self._name}\")\n print(f\"Low: {self._low:.3g}v | High: {self._high:.3g}v\\n-----------\\n\")\n\n while True:\n # Simulate sensor readings\n voltage: float = random.uniform(0, 5)\n print(\"\\tSensor Reading:\", \"\\033[32m\", f\"{voltage:.3g}v\", \"\\033[0m\")\n\n # Emit events based on voltage readings\n if voltage < self._low:\n self._event_emitter.emit(\"LowVoltageEvent\", sensor=self._name, voltage=voltage)\n elif voltage > self._high:\n self._event_emitter.emit(\"HighVoltageEvent\", sensor=self._name, voltage=voltage)\n\n await asyncio.sleep(1)\n\n\n@EventLinker.on(\"LowVoltageEvent\")\ndef handle_low_voltage_event(sensor: str, voltage: float):\n print(f\"\ud83e\udeab Turning on eco-mode for '{sensor}'. ({voltage:.3g}v)\\n\")\n # Perform action for low voltage...\n\n\n@EventLinker.on(\"HighVoltageEvent\")\nasync def handle_high_voltage_event(sensor: str, voltage: float):\n print(f\"\u26a1 Starting high-voltage protection for '{sensor}'. ({voltage:.3g}v)\\n\")\n # Perform action for high voltage...\n\n\n@EventLinker.on(\"LowVoltageEvent\", \"HighVoltageEvent\")\ndef handle_voltage_event(sensor: str, voltage: float):\n print(f\"\\033[31m\\nSensor '{sensor}' out of range.\\033[0m (Voltage: {voltage:.3g})\")\n # Perform notification for out of range voltage...\n\n\nasync def main():\n # Initialize the sensor and run the sensor readings\n sensor = VoltageSensor(name=\"PressureSensor\", low=0.5, high=3.9, event_emitter=AsyncIOEventEmitter())\n await asyncio.gather(sensor(), ) # Add new sensors inside the 'gather' for multi-device monitoring\n\n\nasyncio.run(main())\n```\n\n

\n   As we can see from this practical example, Pyventus enables us to easily build an event-driven system \n\tfor voltage sensors that is flexible, efficient, and highly responsive. With its intuitive API and support for both\n\tsynchronous and asynchronous operations, we were able to effectively monitor voltage levels, detect anomalies, and \n\ttrigger appropriate actions in real-time.\n

\n\n[//]: # (--------------------------------------------------------------------------------------------------------------)\n\n## Support for Synchronous and Asynchronous Code\n\n

\n   Pyventus is designed from the ground up to seamlessly support both synchronous and asynchronous\n\tprogramming models. Its unified sync/async API allows you to define event callbacks and emit events across \n\tsync and async contexts.\n

\n\n### Subscribing Event Handlers with Sync and Async Callbacks\n\n```Python linenums=\"1\" hl_lines=\"2 7\"\n@EventLinker.on(\"MyEvent\")\ndef sync_event_callback():\n pass # Synchronous event handling\n\n\n@EventLinker.on(\"MyEvent\")\nasync def async_event_callback():\n\tpass # Asynchronous event handling\n```\n\n
\nYou can optimize the execution of your callbacks based on their workload...\n\n

\n   By default, event handlers in Pyventus are executed concurrently during an event emission, running their\n\tsync and async callbacks as defined. However, if you have a sync callback\n\tthat involves I/O or non-CPU bound operations, you can enable the force_async parameter to offload it\n\tto a thread pool, ensuring optimal performance and responsiveness. The force_async parameter utilizes \n\tthe asyncio.to_thread()\n\tfunction to execute sync callbacks asynchronously.\n

\n\n```Python linenums=\"1\" hl_lines=\"1\"\n@EventLinker.on(\"BlockingIO\", force_async=True)\ndef blocking_io():\n print(f\"start blocking_io at {time.strftime('%X')}\")\n # Note that time.sleep() can be replaced with any blocking\n # IO-bound operation, such as file operations.\n time.sleep(1)\n print(f\"blocking_io complete at {time.strftime('%X')}\")\n```\n\n
\n\n### Emitting Events from Sync and Async Contexts\n\n```Python linenums=\"1\" hl_lines=\"3 8\"\n# Emitting an event within a sync function\ndef sync_function(event_emitter: EventEmitter):\n event_emitter.emit(\"MyEvent\")\n\n\n# Emitting an event within an async function\nasync def async_function(event_emitter: EventEmitter):\n event_emitter.emit(\"MyEvent\")\n```\n\n
\nEvent propagation within different contexts...\n\n

\n   While Pyventus provides a base EventEmitter class with a unified sync/async API, the \n\tspecific propagation behavior when emitting events may vary depending on the concrete EventEmitter\n\tused. For example, the AsyncIOEventEmitter implementation leverages the AsyncIO event\n\tloop to schedule callbacks added from asynchronous contexts without blocking. But alternative emitters could \n\tstructure propagation differently to suit their needs.\n

\n\n
\n\n[//]: # (--------------------------------------------------------------------------------------------------------------)\n\n## Runtime Flexibility and Customization\n\n

\n   At its core, Pyventus utilizes a modular event emitter design that allows you to switch seamlessly\n\tbetween different built-in\n\tor custom event emitter implementations on the fly. Whether you opt for official emitters or decide to create your \n\tcustom ones, Pyventus allows you to tailor the behavior and capabilities of the event emitters to perfectly align \n\twith your unique requirements.\n

\n\n### Swapping Event Emitter Implementations at Runtime\n\n

\n   By leveraging the principle of dependency inversion and using the base EventEmitter as a\n\tdependency, you can change the concrete implementation on the fly. Let's demonstrate this using the AsyncIO \n\tEvent Emitter and the Executor Event Emitter: \n

\n\n```Python title=\"Event Emitter Runtime Flexibility Example\" linenums=\"1\" hl_lines=\"10-11 14 16\"\nfrom pyventus import EventLinker, EventEmitter, AsyncIOEventEmitter, ExecutorEventEmitter\n\n\n@EventLinker.on(\"GreetEvent\")\ndef handle_greet_event(name: str = \"World\"):\n print(f\"Hello, {name}!\")\n\n\nif __name__ == \"__main__\":\n def main(event_emitter: EventEmitter) -> None:\n event_emitter.emit(\"GreetEvent\", name=type(event_emitter).__name__)\n\n\n main(event_emitter=AsyncIOEventEmitter())\n with ExecutorEventEmitter() as executor_event_emitter:\n main(event_emitter=executor_event_emitter)\n```\n\n### Defining Custom Event Emitters\n\n

\n   To illustrate Pyventus' customization capabilities, we will define and implement a custom event emitter\n\tclass for the FastAPI framework. This class will efficiently handle the execution of event emissions through its \n\tbackground tasks workflow.\n

\n\n```Python title=\"Custom Event Emitter Example\" linenums=\"1\" hl_lines=\"6 10-11 13-14\"\nfrom fastapi import BackgroundTasks\n\nfrom pyventus import EventEmitter, EventLinker\n\n\nclass FastAPIEventEmitter(EventEmitter):\n \"\"\"A custom event emitter that uses the FastAPI background tasks.\"\"\"\n\n def __init__(self, background_tasks: BackgroundTasks):\n super().__init__(event_linker=EventLinker, debug=False)\n self._background_tasks = background_tasks\n\n def _process(self, event_emission: EventEmitter.EventEmission) -> None:\n self._background_tasks.add_task(event_emission) # Process the event emission as a background task\n```\n\n
\nOfficial FastAPIEventEmitter Integration.\n\n

\n In case you're interested in integrating Pyventus with FastAPI, you can refer to the official Pyventus \n\tFastAPI Event Emitter \n\timplementation.\n

\n\n
\n\n[//]: # (--------------------------------------------------------------------------------------------------------------)\n\n## Event Objects and Global Events\n\n

\n   In addition to string events, Pyventus also supports Event Objects, which provide a structured way to \n\tdefine events and encapsulate relevant data payloads.\n

\n\n```Python title=\"Event Object Example\" linenums=\"1\" hl_lines=\"1-2 7-8 16-19\"\n@dataclass # Define a Python dataclass representing the event and its payload.\nclass OrderCreatedEvent:\n order_id: int\n payload: dict[str, any]\n\n\n@EventLinker.on(OrderCreatedEvent) # Subscribe event handlers to the event.\ndef handle_order_created_event(event: OrderCreatedEvent):\n # Pyventus will automatically pass the Event Object \n # as the first positional argument.\n print(f\"Event Object: {event}\")\n\n\nevent_emitter: EventEmitter = AsyncIOEventEmitter()\nevent_emitter.emit(\n event=OrderCreatedEvent( # Emit an instance of the event!\n order_id=6452879,\n payload={},\n ),\n)\n```\n\n

\n   Furthermore, Pyventus provides support for Global Events, which are particularly useful for \n\timplementing cross-cutting concerns such as logging, monitoring, or analytics. By subscribing event handlers to\n\t... or Ellipsis, you can capture all events that may occur within that \n\tEventLinker context.\n

\n\n```Python title=\"Global Event Example\" linenums=\"1\" hl_lines=\"1\"\n@EventLinker.on(...)\ndef handle_any_event(*args, **kwargs):\n print(f\"Perform logging...\\nArgs: {args}\\tKwargs: {kwargs}\")\n\n\nevent_emitter: EventEmitter = AsyncIOEventEmitter()\nevent_emitter.emit(\"GreetEvent\", name=\"Pyventus\")\n```\n\n[//]: # (--------------------------------------------------------------------------------------------------------------)\n\n## Success and Error Handling\n\n

\n   With Pyventus, you can customize how events are handled upon completion, whether they succeed or \n\tencounter errors. This customization is achieved by using either the EventLinker's on() or \n\tonce() decorator within a with statement block. Inside this block, you can \n\tdefine not only the event callbacks but also the overall workflow of the event. Now, let\u2019s explore \n\tthis simple yet powerful Pythonic syntax of Pyventus through an example.\n

\n\n```Python title=\"Success and Error Handling Example\" linenums=\"1\" hl_lines=\"4 6-7 10-11 14-15\"\nfrom pyventus import EventLinker, EventEmitter, AsyncIOEventEmitter\n\n# Create an event linker for the \"DivisionEvent\"\nwith EventLinker.on(\"DivisionEvent\") as linker:\n @linker.on_event\n def divide(a: float, b: float) -> float:\n return a / b\n\n @linker.on_success\n def handle_success(result: float) -> None:\n print(f\"Division result: {result:.3g}\")\n\n @linker.on_failure\n def handle_failure(e: Exception) -> None:\n print(f\"Oops, something went wrong: {e}\")\n\nevent_emitter: EventEmitter = AsyncIOEventEmitter() # Create an event emitter\nevent_emitter.emit(\"DivisionEvent\", a=1, b=0) # Example: Division by zero\nevent_emitter.emit(\"DivisionEvent\", a=1, b=2) # Example: Valid division\n```\n\n

\n   As we have seen from the example, Pyventus offers a reliable and Pythonic solution for customizing \n\tevent handling. By utilizing the EventLinker and its decorators within a with statement block, we\n\twere able to define the DivisionEvent and specify the callbacks for division, success, and failure\n\tcases.\n

\n\n[//]: # (--------------------------------------------------------------------------------------------------------------)\n\n## Continuous Evolution\n\n

\n\t  Pyventus continuously adapts to support developers across technological and programming domains. Its\n\taim is to remain at the forefront of event-driven design. Future development may introduce new official event \n\temitters, expanding compatibility with different technologies through seamless integration.\n

\n\n

\n\t  Current default emitters provide reliable out-of-the-box capabilities for common use cases. They\n\tefficiently handle core event operations and lay the foundation for building event-driven applications.\n

\n\n
\nDriving Innovation Through Collaboration\n\n

\n   Pyventus is an open source project that welcomes community involvement. If you wish to contribute\n\tadditional event emitters, improvements, or bug fixes, please check the Contributing \n\tsection for guidelines on collaborating. Together, we can further the possibilities of event-driven development.\n

\n\n
\n\n[//]: # (--------------------------------------------------------------------------------------------------------------)\n\n## License\n\n

\n   Pyventus is distributed as open source software and is released under the MIT License. \n You can view the full text of the license in the LICENSE \n\tfile located in the Pyventus repository.\n

\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": null, "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "dynamic": null, "home_page": null, "keywords": "event-dispatchers, event-driven, event-emitters, event-handlers, event-linkers, events, python", "license": null, "maintainer": null, "maintainer_email": null, "name": "pyventus", "package_url": "https://pypi.org/project/pyventus/", "platform": null, "project_url": "https://pypi.org/project/pyventus/", "project_urls": { "Changelog": "https://mdapena.github.io/pyventus/release-notes", "Documentation": "https://mdapena.github.io/pyventus", "Homepage": "https://github.com/mdapena/pyventus", "Repository": "https://github.com/mdapena/pyventus" }, "provides_extra": null, "release_url": "https://pypi.org/project/pyventus/0.5.0/", "requires_dist": [ "pyventus[celery]; extra == \"all\"", "pyventus[fastapi]; extra == \"all\"", "pyventus[rq]; extra == \"all\"", "celery>=5.3.5; extra == \"celery\"", "hatch>=1.8.1; extra == \"dev\"", "pyventus[docs]; extra == \"dev\"", "pyventus[tests]; extra == \"dev\"", "mkdocs-git-committers-plugin-2>=2.3.0; extra == \"docs\"", "mkdocs-git-revision-date-localized-plugin>=1.2.1; extra == \"docs\"", "mkdocs-material>=9.5.17; extra == \"docs\"", "mkdocs-material[imaging]; extra == \"docs\"", "mkdocstrings[python]>=0.24.0; extra == \"docs\"", "fastapi>=0.95.2; extra == \"fastapi\"", "rq>=1.15.0; extra == \"rq\"", "black>=23.12.0; extra == \"tests\"", "coverage[toml]>=7.3.3; extra == \"tests\"", "fakeredis>=2.20.0; extra == \"tests\"", "httpx>=0.23.0; extra == \"tests\"", "mypy>=1.7.1; extra == \"tests\"", "pytest-asyncio>=0.21.0; extra == \"tests\"", "pytest>=7.4.0; extra == \"tests\"", "pyventus[all]; extra == \"tests\"" ], "requires_python": ">=3.10", "summary": "A powerful Python package for event-driven programming; define, emit, and orchestrate events with ease.", "version": "0.5.0", "yanked": false, "yanked_reason": null }, "last_serial": 22691294, "releases": { "0.2.0": [ { "comment_text": "", "digests": { "blake2b_256": "922acf4a440f1d6ccff8305babc7ffaf36b3dc19fea718bb95965249f5d7b72f", "md5": "dadc68892fbdcdb9e4a5405d64cdb73f", "sha256": "b1fdf57a50b827c12f50bd8d0298c57e598fb96dab41c30c61db6754fd227dc2" }, "downloads": -1, "filename": "pyventus-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "dadc68892fbdcdb9e4a5405d64cdb73f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.10", "size": 31477, "upload_time": "2023-12-17T00:44:31", "upload_time_iso_8601": "2023-12-17T00:44:31.508241Z", "url": "https://files.pythonhosted.org/packages/92/2a/cf4a440f1d6ccff8305babc7ffaf36b3dc19fea718bb95965249f5d7b72f/pyventus-0.2.0-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "blake2b_256": "b721b7628d7be5611d0a1e8fe56a9f12f4d66c7cc1d88a84136c71aec1f03f49", "md5": "c75745818a4afb483ace08be8777a9da", "sha256": "81fdaace0ccf204f0ed6c9ec0d4d07b35064df7e98ab6b6dead85b0327559827" }, "downloads": -1, "filename": "pyventus-0.2.0.tar.gz", "has_sig": false, "md5_digest": "c75745818a4afb483ace08be8777a9da", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.10", "size": 865103, "upload_time": "2023-12-17T00:44:33", "upload_time_iso_8601": "2023-12-17T00:44:33.392775Z", "url": "https://files.pythonhosted.org/packages/b7/21/b7628d7be5611d0a1e8fe56a9f12f4d66c7cc1d88a84136c71aec1f03f49/pyventus-0.2.0.tar.gz", "yanked": false, "yanked_reason": null } ], "0.2.1": [ { "comment_text": "", "digests": { "blake2b_256": "3fae6113ea82a40e38dbb49a651783ac5fc44a8c750424c54791c702d994eaa1", "md5": "58aee118fdfc7f6a3462b56d20d5845f", "sha256": "f7f6d893389cb7bf0e3842d3106e3455c30f43ff2ae44fc44d1d09f8f87c9e08" }, "downloads": -1, "filename": "pyventus-0.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "58aee118fdfc7f6a3462b56d20d5845f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.10", "size": 31450, "upload_time": "2023-12-17T04:12:35", "upload_time_iso_8601": "2023-12-17T04:12:35.570428Z", "url": "https://files.pythonhosted.org/packages/3f/ae/6113ea82a40e38dbb49a651783ac5fc44a8c750424c54791c702d994eaa1/pyventus-0.2.1-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "blake2b_256": "6d865de191a53f8401681c75fac61e19793e66cbe3335ae9fb34e89a9da2439f", "md5": "b5782c13ff9246a3bf67c9bb9f7e4cd4", "sha256": "fc845c9426e1780b4c70527848a93c6ee82b87fab9df0bb7fb98056d6fd0eb35" }, "downloads": -1, "filename": "pyventus-0.2.1.tar.gz", "has_sig": false, "md5_digest": "b5782c13ff9246a3bf67c9bb9f7e4cd4", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.10", "size": 865235, "upload_time": "2023-12-17T04:12:37", "upload_time_iso_8601": "2023-12-17T04:12:37.892966Z", "url": "https://files.pythonhosted.org/packages/6d/86/5de191a53f8401681c75fac61e19793e66cbe3335ae9fb34e89a9da2439f/pyventus-0.2.1.tar.gz", "yanked": false, "yanked_reason": null } ], "0.3.0": [ { "comment_text": "", "digests": { "blake2b_256": "de76e4ce221e961314f5ea962e62e70125268402d00e30a560e8bd19ab1e98a2", "md5": "b08e241fbdcbfb35ef0a62daeb2197a8", "sha256": "15c166dadac83bca61c3fb1ec2a3081e40460785023c9b732110b321e97e2098" }, "downloads": -1, "filename": "pyventus-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "b08e241fbdcbfb35ef0a62daeb2197a8", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.10", "size": 35273, "upload_time": "2023-12-29T19:32:06", "upload_time_iso_8601": "2023-12-29T19:32:06.702385Z", "url": "https://files.pythonhosted.org/packages/de/76/e4ce221e961314f5ea962e62e70125268402d00e30a560e8bd19ab1e98a2/pyventus-0.3.0-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "blake2b_256": "3c1a34c408f3d584f91c6aafdcb23b63f7a3c1b648406fb6f42efef8e97364a2", "md5": "1c86f25af8f375a7157cc9b86d692d9b", "sha256": "2db96bd59aaadf4e25368c2a48b1d7a17e836f46d2355d181eff993698126281" }, "downloads": -1, "filename": "pyventus-0.3.0.tar.gz", "has_sig": false, "md5_digest": "1c86f25af8f375a7157cc9b86d692d9b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.10", "size": 880002, "upload_time": "2023-12-29T19:32:08", "upload_time_iso_8601": "2023-12-29T19:32:08.525810Z", "url": "https://files.pythonhosted.org/packages/3c/1a/34c408f3d584f91c6aafdcb23b63f7a3c1b648406fb6f42efef8e97364a2/pyventus-0.3.0.tar.gz", "yanked": false, "yanked_reason": null } ], "0.4.0": [ { "comment_text": "", "digests": { "blake2b_256": "0b90099ec92c925441e643c25b59330b93946097b67e9516b94fdcdfdb245198", "md5": "6c1d39ce744f6f71b94c98aec764f034", "sha256": "979dcc7158b255e5ffc3efacd13b76ad7cee5312cf995bf7f697c785b5d55185" }, "downloads": -1, "filename": "pyventus-0.4.0-py3-none-any.whl", "has_sig": false, "md5_digest": "6c1d39ce744f6f71b94c98aec764f034", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.10", "size": 36738, "upload_time": "2024-01-06T07:51:55", "upload_time_iso_8601": "2024-01-06T07:51:55.275325Z", "url": "https://files.pythonhosted.org/packages/0b/90/099ec92c925441e643c25b59330b93946097b67e9516b94fdcdfdb245198/pyventus-0.4.0-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "blake2b_256": "44c0705777c4e40ef4736eb7d5f03c96acd1891fd3946fab1a890f9392946421", "md5": "50b3bad914a440624554623f8f00baec", "sha256": "c4ec820df45f0121f5904a199e7d29946556c95b1e51830a989cfd5d58b5ca0f" }, "downloads": -1, "filename": "pyventus-0.4.0.tar.gz", "has_sig": false, "md5_digest": "50b3bad914a440624554623f8f00baec", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.10", "size": 883773, "upload_time": "2024-01-06T07:51:56", "upload_time_iso_8601": "2024-01-06T07:51:56.949486Z", "url": "https://files.pythonhosted.org/packages/44/c0/705777c4e40ef4736eb7d5f03c96acd1891fd3946fab1a890f9392946421/pyventus-0.4.0.tar.gz", "yanked": false, "yanked_reason": null } ], "0.4.1": [ { "comment_text": "", "digests": { "blake2b_256": "6573b60de39f6295db02bce61899d238f957f2bd4ce5499bd72001c39e5e86b4", "md5": "a7c1024a1ba4e5b03190ba48eb6e8d41", "sha256": "ce10ef86eda58f8d0ac00301c8d2a06f759ee12bb82b39152cf79c03fb4adee6" }, "downloads": -1, "filename": "pyventus-0.4.1-py3-none-any.whl", "has_sig": false, "md5_digest": "a7c1024a1ba4e5b03190ba48eb6e8d41", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.10", "size": 36862, "upload_time": "2024-01-31T03:13:59", "upload_time_iso_8601": "2024-01-31T03:13:59.368585Z", "url": "https://files.pythonhosted.org/packages/65/73/b60de39f6295db02bce61899d238f957f2bd4ce5499bd72001c39e5e86b4/pyventus-0.4.1-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "blake2b_256": "c2dd4c0e0735e456787b1b5e475432228c655641a54793e05ca0784c066095be", "md5": "0adf009566532610e13405f1dae17f9b", "sha256": "afe934437ca5551bb49774f5108264f4bbb4f81c88f68896722101e20df24328" }, "downloads": -1, "filename": "pyventus-0.4.1.tar.gz", "has_sig": false, "md5_digest": "0adf009566532610e13405f1dae17f9b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.10", "size": 37650, "upload_time": "2024-01-31T03:14:01", "upload_time_iso_8601": "2024-01-31T03:14:01.261472Z", "url": "https://files.pythonhosted.org/packages/c2/dd/4c0e0735e456787b1b5e475432228c655641a54793e05ca0784c066095be/pyventus-0.4.1.tar.gz", "yanked": false, "yanked_reason": null } ], "0.5.0": [ { "comment_text": "", "digests": { "blake2b_256": "952b0fec95bd1a5bfec6e5d5b6a330ca256a1f6a29139f78d99b958b96882568", "md5": "8b8c718a874a17de62ac905a79cf4311", "sha256": "6bd24e96f45e195003a6947a18c4f422754bc8298e3d7ff685fd7117f4d470e9" }, "downloads": -1, "filename": "pyventus-0.5.0-py3-none-any.whl", "has_sig": false, "md5_digest": "8b8c718a874a17de62ac905a79cf4311", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.10", "size": 37102, "upload_time": "2024-04-09T22:21:31", "upload_time_iso_8601": "2024-04-09T22:21:31.661308Z", "url": "https://files.pythonhosted.org/packages/95/2b/0fec95bd1a5bfec6e5d5b6a330ca256a1f6a29139f78d99b958b96882568/pyventus-0.5.0-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "blake2b_256": "c1289eb03980dc59954aed240310a135651d50f564cd2371938aeb524a3c57a2", "md5": "6527851cf69e764a0da230a2610b5659", "sha256": "536b5f0843c8528a7fcec77ae3a5851c118cf0d86fc3098951ae7802ced594f5" }, "downloads": -1, "filename": "pyventus-0.5.0.tar.gz", "has_sig": false, "md5_digest": "6527851cf69e764a0da230a2610b5659", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.10", "size": 45031, "upload_time": "2024-04-09T22:21:32", "upload_time_iso_8601": "2024-04-09T22:21:32.826560Z", "url": "https://files.pythonhosted.org/packages/c1/28/9eb03980dc59954aed240310a135651d50f564cd2371938aeb524a3c57a2/pyventus-0.5.0.tar.gz", "yanked": false, "yanked_reason": null } ] }, "urls": [ { "comment_text": "", "digests": { "blake2b_256": "952b0fec95bd1a5bfec6e5d5b6a330ca256a1f6a29139f78d99b958b96882568", "md5": "8b8c718a874a17de62ac905a79cf4311", "sha256": "6bd24e96f45e195003a6947a18c4f422754bc8298e3d7ff685fd7117f4d470e9" }, "downloads": -1, "filename": "pyventus-0.5.0-py3-none-any.whl", "has_sig": false, "md5_digest": "8b8c718a874a17de62ac905a79cf4311", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.10", "size": 37102, "upload_time": "2024-04-09T22:21:31", "upload_time_iso_8601": "2024-04-09T22:21:31.661308Z", "url": "https://files.pythonhosted.org/packages/95/2b/0fec95bd1a5bfec6e5d5b6a330ca256a1f6a29139f78d99b958b96882568/pyventus-0.5.0-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "blake2b_256": "c1289eb03980dc59954aed240310a135651d50f564cd2371938aeb524a3c57a2", "md5": "6527851cf69e764a0da230a2610b5659", "sha256": "536b5f0843c8528a7fcec77ae3a5851c118cf0d86fc3098951ae7802ced594f5" }, "downloads": -1, "filename": "pyventus-0.5.0.tar.gz", "has_sig": false, "md5_digest": "6527851cf69e764a0da230a2610b5659", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.10", "size": 45031, "upload_time": "2024-04-09T22:21:32", "upload_time_iso_8601": "2024-04-09T22:21:32.826560Z", "url": "https://files.pythonhosted.org/packages/c1/28/9eb03980dc59954aed240310a135651d50f564cd2371938aeb524a3c57a2/pyventus-0.5.0.tar.gz", "yanked": false, "yanked_reason": null } ], "vulnerabilities": [] }