aistac-foundation


Nameaistac-foundation JSON
Version 2.17.5 PyPI version JSON
download
home_pagehttp://github.com/gigas64/aistac-foundation
SummaryAugmented Intent Single Task Adaptive Components
upload_time2023-06-08 13:32:59
maintainer
docs_urlNone
authorGigas64
requires_python>=3.7
licenseBSD
keywords foundation sdk machine learning ai component intent data science
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            Project Hadron Foundation Package
#################################

.. class:: no-web no-pdf

.. contents::

.. section-numbering::

What is Project Hadron
======================

Project Hadron provides a clear separation of concerns between components and their actions and data
and its content, whilst maintaining the original intentions of the data scientist, that can be passed
to a production team. It offers trust between the data scientists teams and product teams. It brings
with it transparency and traceability, dealing with bias, fairness, and knowledge. The resulting
outcome provides the product engineers with adaptability, robustness, and reuse; fitting seamlessly
into a microservices solution that can be language agnostic.

Project Hadron is designed using Microservices. Microservices - also known as the microservice
architecture - is an architectural pattern that structures an application as a collection of
component services that are:

* Highly maintainable and testable
* Loosely coupled
* Independently deployable
* Highly reusable
* Resilient
* Technically independent

Component services are built for business capabilities and each service performs a single function.
Because they are independently run, each service can be updated, deployed, and scaled to meet demand
for specific functions of an application. Project Hadron microservices enable the rapid, frequent
and reliable delivery of large, complex applications. It also enables an organization to evolve its
technology stack and experiment with innovative ideas.

At the heart of Project Hadron is a multi-tenant, NoSQL, singleton, in memory data store that has
minimal code and functionality and has been custom built specifically for Hadron tasks in  mind.
Abstracted from this is the component store which allows us to build a reusable set of methods
that define each tenanted component that sits separately from the store itself. In addition, a
dynamic key value class provides labeling so that each tenant is not tied to a fixed set of
reference values unless by specificity. Each of the classes, the data store, the component
property manager, and the key value pairs that make up the component are all independent,
giving complete flexibility and minimum code footprint to the build process of new components.

This is what gives us the Domain Contract for each tenant which sits at the heart of what makes
the contracts reusable, translatable, transferable and brings the data scientist closer to the
production engineer along with building a production ready component solution.

Installation
============

package install
---------------

The best way to install this package is directly from the Python Package Index repository using pip

.. code-block:: bash

    $ pip install aistac-foundation

if you want to upgrade your current version then using pip

.. code-block:: bash

    $ pip install --upgrade aistac-foundation

Package Overview
================

AbstractComponent
-----------------

The ``AbstractComponent`` class is a foundation class for the component build. It provides an encapsulated view of
the Property Management and Parameterised Intent

Abstract AI Single Task Application Component (AI-STAC) component class provides all the basic building blocks
of a components build including property management, augmented knowledge notes and parameterised intent pipeline.

For convenience there are three Factory Initialisation methods available``from_env(...)``, ``from_memory(...)`` and
``from_uri(...)`` the first two being abstract methods. The thrid factory method initialises the concrete
PropertyManager and IntentModel classes and use the parent ``_init_properties(...)`` methods to set the properties
connector. When creating the concrete class the ``from_uri(...)`` should be implemented. The following method can be
used as a template replacing ``ExamplePropertyManager`` and ``ExampleIntentModel`` with your oen concrete
implementations

.. code-block:: python

    @classmethod
    def from_uri(cls, task_name: str, uri_pm_path: str, username: str, uri_pm_repo: str=None,
                 pm_file_type: str=None, pm_module: str=None, pm_handler: str=None, pm_kwargs: dict=None,
                 default_save=None, reset_templates: bool=None, template_path: str=None, template_module: str=None,
                 template_source_handler: str=None, template_persist_handler: str=None, align_connectors: bool=None,
                 default_save_intent: bool=None, default_intent_level: bool=None, order_next_available: bool=None,
                 default_replace_intent: bool=None, has_contract: bool=None):
        pm_file_type = pm_file_type if isinstance(pm_file_type, str) else 'json'
        pm_module = pm_module if isinstance(pm_module, str) else cls.DEFAULT_MODULE
        pm_handler = pm_handler if isinstance(pm_handler, str) else cls.DEFAULT_PERSIST_HANDLER
        _pm = ExamplePropertyManager(task_name=task_name, username=username)
        _intent_model = ExampleIntentModel(property_manager=_pm, default_save_intent=default_save_intent,
                                           default_intent_level=default_intent_level,
                                           order_next_available=order_next_available,
                                           default_replace_intent=default_replace_intent)
        super()._init_properties(property_manager=_pm, uri_pm_path=uri_pm_path, default_save=default_save,
                                 uri_pm_repo=uri_pm_repo, pm_file_type=pm_file_type, pm_module=pm_module,
                                 pm_handler=pm_handler, pm_kwargs=pm_kwargs, has_contract=has_contract)
        return cls(property_manager=_pm, intent_model=_intent_model, default_save=default_save,
                   reset_templates=reset_templates, template_path=template_path, template_module=template_module,
                   template_source_handler=template_source_handler, template_persist_handler=template_persist_handler,
                   align_connectors=align_connectors)


AbstractPropertyManager
-----------------------
The ``AbstractPropertiesManager`` facilitates the management of all the contract properties  including that of the
connector handlers, parameterised intent and Augmented Knowledge

Abstract AI Single Task Application Component (AI-STAC) class that creates a super class for all properties
managers

The Class initialisation is abstracted and is the only abstracted method. A concrete implementation of the
overloaded ``__init__`` manages the ``root_key`` and ``knowledge_key`` for this construct. The ``root_key`` adds a key
property reference to the root of the properties and can be referenced directly with ``<name>_key``. Likewise
the ``knowledge_key`` adds a catalog key to the restricted catalog keys.

More complex ``root_key`` constructs, where a grouping of keys might be desirable, passing a dictionary of name
value pairs as part of the list allows a root base to group related next level keys. For example

.. code-block:: python

    root_key = [{base: [primary, secondary}]

would add ``base.primary_key`` and ``base.secondary_key`` to the list of keys.

Here is a default example of an initialisation method:

.. code-block:: python

        def __init__(self, task_name: str):
            # set additional keys
            root_keys = []
            knowledge_keys = []
            super().__init__(task_name=task_name, root_keys=root_keys, knowledge_keys=knowledge_keys)


The property manager is not responsible for persisting the properties but provides the methods to load and persist
its in memory structure. To initialise the load and persist a ConnectorContract must be set up.

The following is a code snippet of setting a ConnectorContract and loading its content

.. code-block:: python

            self.set_property_connector(connector_contract=connector_contract)
            if self.get_connector_handler(self.CONNECTOR_PM_CONTRACT).exists():
                self.load_properties(replace=replace)

When using the property manager it will not automatically persist its properties and must be explicitely managed in
the component class. This removes the persist decision making away from the property manager. To persist the
properties use the method call ``persist_properties()``


AbstractIntentModel
-------------------
The ``AbstractIntentModel`` facilitates the Parameterised Intent, giving the base methods to record and replay intent.

Abstract AI Single Task Application Component (AI-STAC) Class for Parameterised Intent containing parameterised
intent registration methods ``_intent_builder(...)`` and ``_set_intend_signature(...)``.

it is creating a construct initialisation to allow for the control and definition of an ``intent_param_exclude``
list, ``default_save_intent`` boolean and a ``default_intent_level`` value.

As an example of an initialisation method

.. code-block:: python

    def __init__(self, property_manager: AbstractPropertyManager, default_save_intent: bool=None,
                 default_intent_level: bool=None, order_next_available: bool=None, default_replace_intent: bool=None):
        # set all the defaults
        default_save_intent = default_save_intent if isinstance(default_save_intent, bool) else True
        default_replace_intent = default_replace_intent if isinstance(default_replace_intent, bool) else True
        default_intent_level = default_intent_level if isinstance(default_intent_level, (str, int, float)) else 0
        default_intent_order = -1 if isinstance(order_next_available, bool) and order_next_available else 0
        intent_param_exclude = ['data', 'inplace']
        intent_type_additions = []
        super().__init__(property_manager=property_manager, default_save_intent=default_save_intent,
                         intent_param_exclude=intent_param_exclude, default_intent_level=default_intent_level,
                         default_intent_order=default_intent_order, default_replace_intent=default_replace_intent,
                         intent_type_additions=intent_type_additions)

in order to define the run pattern for the component task ``run_intent_pipeline(...)`` is an abstracted method
that defines the run pipeline of the intent.

As an example of a run_pipeline that iteratively updates a canonical with each intent

.. code-block:: python

    def run_intent_pipeline(self, canonical, intent_levels: [int, str, list]=None, **kwargs):
        # test if there is any intent to run
        if self._pm.has_intent():
            # get the list of levels to run
            if isinstance(intent_levels, (int, str, list)):
                intent_levels = Commons.list_formatter(intent_levels)
            else:
                intent_levels = sorted(self._pm.get_intent().keys())
            for level in intent_levels:
                level_key = self._pm.join(self._pm.KEY.intent_key, level)
                for order in sorted(self._pm.get(level_key, {})):
                    for method, params in self._pm.get(self._pm.join(level_key, order), {}).items():
                        if method in self.__dir__():
                            # add method kwargs to the params
                            if isinstance(kwargs, dict):
                                params.update(kwargs)
                            # add excluded parameters to the params
                            params.update({'inplace': False, 'save_intent': False})
                            canonical = eval(f"self.{method}(canonical, **{params})", globals(), locals())
        return canonical

The code signature for an intent method would have the following construct

.. code-block:: python

    def <method>(self, <params>..., save_intent: bool=None, intent_level: [int, str]=None, intent_order: int=None,
                 replace_intent: bool=None, remove_duplicates: bool=None):
        # resolve intent persist options
        self._set_intend_signature(self._intent_builder(method=inspect.currentframe().f_code.co_name, params=locals()),
                                   intent_level=intent_level, intent_order=intent_order, replace_intent=replace_intent,
                                   remove_duplicates=remove_duplicates, save_intent=save_intent)
        # intend code block on the canonical
        ...


Reference
=========


Python version
--------------

Python 3.6 or less is not supported. Although Python 3.7 is supported, it is recommended to
install ``aistac-foundation`` against the latest Python 3.8.x or greater whenever possible.

GitHub Project
--------------
aistac-foundation: `<https://github.com/project-hadron/aistac-foundation>`_.

Change log
----------

See `CHANGELOG <https://github.com/project-hadron/aistac-foundation/blob/master/CHANGELOG.rst>`_.


Licence
-------

MIT License: `<https://opensource.org/license/mit/>`_.


Authors
-------

`Gigas64`_  (`@gigas64`_) created aistac-foundation.


.. _pip: https://pip.pypa.io/en/stable/installing/
.. _Github API: http://developer.github.com/v3/issues/comments/#create-a-comment
.. _Gigas64: http://opengrass.io
.. _@gigas64: https://twitter.com/gigas64


            

Raw data

            {
    "_id": null,
    "home_page": "http://github.com/gigas64/aistac-foundation",
    "name": "aistac-foundation",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "Foundation SDK Machine learning AI component intent data science",
    "author": "Gigas64",
    "author_email": "gigas64@aistac.com",
    "download_url": "https://files.pythonhosted.org/packages/6e/b1/72ec347758c416537cabca1e2424725971fa41ff03b1ec1a9167c5b5cf02/aistac-foundation-2.17.5.tar.gz",
    "platform": null,
    "description": "Project Hadron Foundation Package\n#################################\n\n.. class:: no-web no-pdf\n\n.. contents::\n\n.. section-numbering::\n\nWhat is Project Hadron\n======================\n\nProject Hadron provides a clear separation of concerns between components and their actions and data\nand its content, whilst maintaining the original intentions of the data scientist, that can be passed\nto a production team. It offers trust between the data scientists teams and product teams. It brings\nwith it transparency and traceability, dealing with bias, fairness, and knowledge. The resulting\noutcome provides the product engineers with adaptability, robustness, and reuse; fitting seamlessly\ninto a microservices solution that can be language agnostic.\n\nProject Hadron is designed using Microservices. Microservices - also known as the microservice\narchitecture - is an architectural pattern that structures an application as a collection of\ncomponent services that are:\n\n* Highly maintainable and testable\n* Loosely coupled\n* Independently deployable\n* Highly reusable\n* Resilient\n* Technically independent\n\nComponent services are built for business capabilities and each service performs a single function.\nBecause they are independently run, each service can be updated, deployed, and scaled to meet demand\nfor specific functions of an application. Project Hadron microservices enable the rapid, frequent\nand reliable delivery of large, complex applications. It also enables an organization to evolve its\ntechnology stack and experiment with innovative ideas.\n\nAt the heart of Project Hadron is a multi-tenant, NoSQL, singleton, in memory data store that has\nminimal code and functionality and has been custom built specifically for Hadron tasks in  mind.\nAbstracted from this is the component store which allows us to build a reusable set of methods\nthat define each tenanted component that sits separately from the store itself. In addition, a\ndynamic key value class provides labeling so that each tenant is not tied to a fixed set of\nreference values unless by specificity. Each of the classes, the data store, the component\nproperty manager, and the key value pairs that make up the component are all independent,\ngiving complete flexibility and minimum code footprint to the build process of new components.\n\nThis is what gives us the Domain Contract for each tenant which sits at the heart of what makes\nthe contracts reusable, translatable, transferable and brings the data scientist closer to the\nproduction engineer along with building a production ready component solution.\n\nInstallation\n============\n\npackage install\n---------------\n\nThe best way to install this package is directly from the Python Package Index repository using pip\n\n.. code-block:: bash\n\n    $ pip install aistac-foundation\n\nif you want to upgrade your current version then using pip\n\n.. code-block:: bash\n\n    $ pip install --upgrade aistac-foundation\n\nPackage Overview\n================\n\nAbstractComponent\n-----------------\n\nThe ``AbstractComponent`` class is a foundation class for the component build. It provides an encapsulated view of\nthe Property Management and Parameterised Intent\n\nAbstract AI Single Task Application Component (AI-STAC) component class provides all the basic building blocks\nof a components build including property management, augmented knowledge notes and parameterised intent pipeline.\n\nFor convenience there are three Factory Initialisation methods available``from_env(...)``, ``from_memory(...)`` and\n``from_uri(...)`` the first two being abstract methods. The thrid factory method initialises the concrete\nPropertyManager and IntentModel classes and use the parent ``_init_properties(...)`` methods to set the properties\nconnector. When creating the concrete class the ``from_uri(...)`` should be implemented. The following method can be\nused as a template replacing ``ExamplePropertyManager`` and ``ExampleIntentModel`` with your oen concrete\nimplementations\n\n.. code-block:: python\n\n    @classmethod\n    def from_uri(cls, task_name: str, uri_pm_path: str, username: str, uri_pm_repo: str=None,\n                 pm_file_type: str=None, pm_module: str=None, pm_handler: str=None, pm_kwargs: dict=None,\n                 default_save=None, reset_templates: bool=None, template_path: str=None, template_module: str=None,\n                 template_source_handler: str=None, template_persist_handler: str=None, align_connectors: bool=None,\n                 default_save_intent: bool=None, default_intent_level: bool=None, order_next_available: bool=None,\n                 default_replace_intent: bool=None, has_contract: bool=None):\n        pm_file_type = pm_file_type if isinstance(pm_file_type, str) else 'json'\n        pm_module = pm_module if isinstance(pm_module, str) else cls.DEFAULT_MODULE\n        pm_handler = pm_handler if isinstance(pm_handler, str) else cls.DEFAULT_PERSIST_HANDLER\n        _pm = ExamplePropertyManager(task_name=task_name, username=username)\n        _intent_model = ExampleIntentModel(property_manager=_pm, default_save_intent=default_save_intent,\n                                           default_intent_level=default_intent_level,\n                                           order_next_available=order_next_available,\n                                           default_replace_intent=default_replace_intent)\n        super()._init_properties(property_manager=_pm, uri_pm_path=uri_pm_path, default_save=default_save,\n                                 uri_pm_repo=uri_pm_repo, pm_file_type=pm_file_type, pm_module=pm_module,\n                                 pm_handler=pm_handler, pm_kwargs=pm_kwargs, has_contract=has_contract)\n        return cls(property_manager=_pm, intent_model=_intent_model, default_save=default_save,\n                   reset_templates=reset_templates, template_path=template_path, template_module=template_module,\n                   template_source_handler=template_source_handler, template_persist_handler=template_persist_handler,\n                   align_connectors=align_connectors)\n\n\nAbstractPropertyManager\n-----------------------\nThe ``AbstractPropertiesManager`` facilitates the management of all the contract properties  including that of the\nconnector handlers, parameterised intent and Augmented Knowledge\n\nAbstract AI Single Task Application Component (AI-STAC) class that creates a super class for all properties\nmanagers\n\nThe Class initialisation is abstracted and is the only abstracted method. A concrete implementation of the\noverloaded ``__init__`` manages the ``root_key`` and ``knowledge_key`` for this construct. The ``root_key`` adds a key\nproperty reference to the root of the properties and can be referenced directly with ``<name>_key``. Likewise\nthe ``knowledge_key`` adds a catalog key to the restricted catalog keys.\n\nMore complex ``root_key`` constructs, where a grouping of keys might be desirable, passing a dictionary of name\nvalue pairs as part of the list allows a root base to group related next level keys. For example\n\n.. code-block:: python\n\n    root_key = [{base: [primary, secondary}]\n\nwould add ``base.primary_key`` and ``base.secondary_key`` to the list of keys.\n\nHere is a default example of an initialisation method:\n\n.. code-block:: python\n\n        def __init__(self, task_name: str):\n            # set additional keys\n            root_keys = []\n            knowledge_keys = []\n            super().__init__(task_name=task_name, root_keys=root_keys, knowledge_keys=knowledge_keys)\n\n\nThe property manager is not responsible for persisting the properties but provides the methods to load and persist\nits in memory structure. To initialise the load and persist a ConnectorContract must be set up.\n\nThe following is a code snippet of setting a ConnectorContract and loading its content\n\n.. code-block:: python\n\n            self.set_property_connector(connector_contract=connector_contract)\n            if self.get_connector_handler(self.CONNECTOR_PM_CONTRACT).exists():\n                self.load_properties(replace=replace)\n\nWhen using the property manager it will not automatically persist its properties and must be explicitely managed in\nthe component class. This removes the persist decision making away from the property manager. To persist the\nproperties use the method call ``persist_properties()``\n\n\nAbstractIntentModel\n-------------------\nThe ``AbstractIntentModel`` facilitates the Parameterised Intent, giving the base methods to record and replay intent.\n\nAbstract AI Single Task Application Component (AI-STAC) Class for Parameterised Intent containing parameterised\nintent registration methods ``_intent_builder(...)`` and ``_set_intend_signature(...)``.\n\nit is creating a construct initialisation to allow for the control and definition of an ``intent_param_exclude``\nlist, ``default_save_intent`` boolean and a ``default_intent_level`` value.\n\nAs an example of an initialisation method\n\n.. code-block:: python\n\n    def __init__(self, property_manager: AbstractPropertyManager, default_save_intent: bool=None,\n                 default_intent_level: bool=None, order_next_available: bool=None, default_replace_intent: bool=None):\n        # set all the defaults\n        default_save_intent = default_save_intent if isinstance(default_save_intent, bool) else True\n        default_replace_intent = default_replace_intent if isinstance(default_replace_intent, bool) else True\n        default_intent_level = default_intent_level if isinstance(default_intent_level, (str, int, float)) else 0\n        default_intent_order = -1 if isinstance(order_next_available, bool) and order_next_available else 0\n        intent_param_exclude = ['data', 'inplace']\n        intent_type_additions = []\n        super().__init__(property_manager=property_manager, default_save_intent=default_save_intent,\n                         intent_param_exclude=intent_param_exclude, default_intent_level=default_intent_level,\n                         default_intent_order=default_intent_order, default_replace_intent=default_replace_intent,\n                         intent_type_additions=intent_type_additions)\n\nin order to define the run pattern for the component task ``run_intent_pipeline(...)`` is an abstracted method\nthat defines the run pipeline of the intent.\n\nAs an example of a run_pipeline that iteratively updates a canonical with each intent\n\n.. code-block:: python\n\n    def run_intent_pipeline(self, canonical, intent_levels: [int, str, list]=None, **kwargs):\n        # test if there is any intent to run\n        if self._pm.has_intent():\n            # get the list of levels to run\n            if isinstance(intent_levels, (int, str, list)):\n                intent_levels = Commons.list_formatter(intent_levels)\n            else:\n                intent_levels = sorted(self._pm.get_intent().keys())\n            for level in intent_levels:\n                level_key = self._pm.join(self._pm.KEY.intent_key, level)\n                for order in sorted(self._pm.get(level_key, {})):\n                    for method, params in self._pm.get(self._pm.join(level_key, order), {}).items():\n                        if method in self.__dir__():\n                            # add method kwargs to the params\n                            if isinstance(kwargs, dict):\n                                params.update(kwargs)\n                            # add excluded parameters to the params\n                            params.update({'inplace': False, 'save_intent': False})\n                            canonical = eval(f\"self.{method}(canonical, **{params})\", globals(), locals())\n        return canonical\n\nThe code signature for an intent method would have the following construct\n\n.. code-block:: python\n\n    def <method>(self, <params>..., save_intent: bool=None, intent_level: [int, str]=None, intent_order: int=None,\n                 replace_intent: bool=None, remove_duplicates: bool=None):\n        # resolve intent persist options\n        self._set_intend_signature(self._intent_builder(method=inspect.currentframe().f_code.co_name, params=locals()),\n                                   intent_level=intent_level, intent_order=intent_order, replace_intent=replace_intent,\n                                   remove_duplicates=remove_duplicates, save_intent=save_intent)\n        # intend code block on the canonical\n        ...\n\n\nReference\n=========\n\n\nPython version\n--------------\n\nPython 3.6 or less is not supported. Although Python 3.7 is supported, it is recommended to\ninstall ``aistac-foundation`` against the latest Python 3.8.x or greater whenever possible.\n\nGitHub Project\n--------------\naistac-foundation: `<https://github.com/project-hadron/aistac-foundation>`_.\n\nChange log\n----------\n\nSee `CHANGELOG <https://github.com/project-hadron/aistac-foundation/blob/master/CHANGELOG.rst>`_.\n\n\nLicence\n-------\n\nMIT License: `<https://opensource.org/license/mit/>`_.\n\n\nAuthors\n-------\n\n`Gigas64`_  (`@gigas64`_) created aistac-foundation.\n\n\n.. _pip: https://pip.pypa.io/en/stable/installing/\n.. _Github API: http://developer.github.com/v3/issues/comments/#create-a-comment\n.. _Gigas64: http://opengrass.io\n.. _@gigas64: https://twitter.com/gigas64\n\n",
    "bugtrack_url": null,
    "license": "BSD",
    "summary": "Augmented Intent Single Task Adaptive Components",
    "version": "2.17.5",
    "project_urls": {
        "Homepage": "http://github.com/gigas64/aistac-foundation"
    },
    "split_keywords": [
        "foundation",
        "sdk",
        "machine",
        "learning",
        "ai",
        "component",
        "intent",
        "data",
        "science"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "92e4c9769b3200f5de8eff7d5700a30d1768325362fe8dd204ce03040f5a3e0c",
                "md5": "e4be43e3b737e9ca1ac798a623e951c5",
                "sha256": "47662a677bb98805d51ce0371a988a30299f2bb2633ddb8895c61a3045e7b278"
            },
            "downloads": -1,
            "filename": "aistac_foundation-2.17.5-py38-none-any.whl",
            "has_sig": false,
            "md5_digest": "e4be43e3b737e9ca1ac798a623e951c5",
            "packagetype": "bdist_wheel",
            "python_version": "py38",
            "requires_python": ">=3.7",
            "size": 80187,
            "upload_time": "2023-06-08T13:32:57",
            "upload_time_iso_8601": "2023-06-08T13:32:57.797016Z",
            "url": "https://files.pythonhosted.org/packages/92/e4/c9769b3200f5de8eff7d5700a30d1768325362fe8dd204ce03040f5a3e0c/aistac_foundation-2.17.5-py38-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6eb172ec347758c416537cabca1e2424725971fa41ff03b1ec1a9167c5b5cf02",
                "md5": "02a5b2cf8756114c090ddb6a3af87c49",
                "sha256": "c31f843eb235121aabbdc6b4866bbb05faa23c55e637956863043b2941a56e82"
            },
            "downloads": -1,
            "filename": "aistac-foundation-2.17.5.tar.gz",
            "has_sig": false,
            "md5_digest": "02a5b2cf8756114c090ddb6a3af87c49",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 73208,
            "upload_time": "2023-06-08T13:32:59",
            "upload_time_iso_8601": "2023-06-08T13:32:59.660573Z",
            "url": "https://files.pythonhosted.org/packages/6e/b1/72ec347758c416537cabca1e2424725971fa41ff03b1ec1a9167c5b5cf02/aistac-foundation-2.17.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-08 13:32:59",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "gigas64",
    "github_project": "aistac-foundation",
    "github_not_found": true,
    "lcname": "aistac-foundation"
}
        
Elapsed time: 0.07479s