Skip to main content

Simple and easy to use framework

Project description

FlexiStack Framework

PyPI - Version PyPI - Python Version GitHub License PyPI - Wheel

FlexiStack is a sophisticated Python framework designed to streamline the development of modular applications. It allows developers to efficiently manage the complexity associated with building applications by segmenting functionality into distinct, reusable components. FlexiStack provides a structured approach to developing software, offering significant benefits:

  • Modularity: Promotes clean separation of concerns, enabling developers to organize code into manageable pieces.
  • Reusability: Components such as actions and plugins can be reused across different projects, reducing development time.
  • Extensibility: New functionalities can be easily added through plugins without altering the core application logic.
  • Simplicity: Simplifies argument parsing and command-line interface creation, making it easier to build and maintain complex applications.

Core Components of FlexiStack

FlexiStack's architecture is built around three main components: middleware, actions, and plugins. Each serves a unique purpose within the framework, contributing to its flexibility and power.

Installation

You can install FlexiStack using pip:

pip install flexistack

How to use

Although FlexiStack can support various project structures, a recommended one is as follows:

/project_directory 
│ 
├── __main__.py 
├── /core 
│ └── ... 
├── /actions 
│ └── ... 
└── /plugins 
└── ...

Main Flexistack application

A minimum setup in the __main__.py file to utilize FlexiStack:

import os
import flexistack

if __name__ == "__main__":
   
    # Create an instance of the Flexistack framework
    fstack = flexistack.Flexistack()

    # Load actions and plugins
    fstack.load(":core/", ":actions/",":plugins/")

    # Parse arguments
    _, unknown_args = fstack.parse_arguments()

    # Execute actions/plugins based on given args
    fstack.run()
    
    pass

Flexistack Middleware

Middleware in FlexiStack serves as an intermediate layer that can process data or handle requests both before and after they reach the core action logic. Middleware can be employed for various purposes, such as logging, authentication, data preprocessing, or any other cross-cutting concern that should be applied consistently across different parts of your application.

FlexiStack utilizes the concept of middleware to provide a flexible way to insert these cross-cutting concerns without cluttering the business logic of actions and plugins. Middleware classes are automatically recognized and utilized by FlexiStack based on their structure and configuration.

Implementing Middleware

To implement middleware in FlexiStack, you have to define a Python class with the appropriate flexi decorator flexi_middleware. The class name is used automatically as a callable property within flexistack.middleware, making it readily available throughout your application.

The key elements of a middleware class are:

  • class <name>: The name of the class is used by the framework to access the functionalities of the middleware.
  • @flexi_middleware (decorator): describes the type of this class (middleware) and contains a short description of it.
  • init (method): Your init code (it is called automatically by the framework (once)).

Example: Terminal Middleware

from flexistack import *

@flexi_middleware(description="Simple colorful terminal")
class Terminal:

    def init(self):
        # Optional: Initialization code here
        pass

    # Example method for middleware
    def print(self, message):
        print(message)

Using Middleware

Once defined, middleware can be used throughout your application simply by accessing it through the flexistack.middleware property. For example, to use the Terminal middleware in an action to print a message, you would do the following:

self.flexistack.middleware.terminal.print("This is a message from an action using Terminal middleware.")

This approach to middleware allows FlexiStack applications to maintain clean separation of concerns and promotes the reuse of common functionalities across different parts of the application. By defining middleware like the Terminal example, developers can encapsulate specific behaviors (such as custom logging, output formatting, etc.) in a way that's easily accessible and reusable without coupling these behaviors to the core logic of actions or plugins.

Flexistack Actions

Actions are central to FlexiStack's design, representing the tasks that your application can perform. They are defined as Python scripts and are categorized into two main types based on how they are invoked from the command line:

  • Positional Actions: These are converted into positional arguments. The framework dynamically constructs the command-line interface based on the action scripts' names and their directory structure. For instance, an action placed directly under the actions directory becomes a first-level positional argument, while an action inside a subdirectory (like generate/random-number.py) becomes a nested positional argument (generate random-number).
  • Optional Actions: These are used as optional arguments, typically providing utility functionalities such as displaying the version of the application.

Implementing Actions

To implement an action, create a Python script in the /actions directory or a subdirectory for nesting. The script should define a class with the aforementioned key elements.

The structure and behavior of actions are defined by several key elements:

  • File Name: Determines the argument name used to invoke the action from the command line.
  • flexi_action (decorator): Contains metadata about the action, including its type and description.
  • set_optional_arguments (method): Defines additional CLI arguments that the action accepts.
  • init (method): Performs initial setup based on the provided command-line arguments.
  • run (method): Contains the main logic to be executed when the action is invoked.

Example: Positional Action

from flexistack import *

@flexi_action(None, 'Shuffle a given string')
class Action:

    def set_optional_arguments(self, parser, modules):
        parser.add_argument('--data', help="Input data to shuffle")

    def init(self, **kwargs):
        self.data = kwargs.get('data', None)
        return True

    def run(self, **kwargs):
        # Logic to shuffle the data
        pass

Example: Optional Action

from flexistack import *

@flexi_action('store_true', 'Shuffle a given string')
class Action:

    def init(self, **kwargs):
        return True

    def run(self, **kwargs):
        print("Application Version: 1.0.0")

Action Invocation and Structure

The framework auto-generates the command-line interface based on the action scripts' names and their placement within the directory structure. This structure allows for intuitive and organized access to the various functionalities of your application.

  • A script named shuffle.py directly under actions is invoked as python app.py shuffle.
  • A script named random-number.py inside a subdirectory generate is invoked as python app.py generate random-number.

The .flexistack File

For actions grouped under a directory (like generate), a .flexistack file within the directory provides additional metadata for the grouped actions, such as the order in which they appear and a short description. This file enhances the CLI's usability by organizing related actions under a common command namespace.

{
	"z-index": 105,
	"description": "Generate different data"
}

By carefully structuring actions and utilizing the .flexistack file for grouped actions, developers can create a rich, intuitive command-line interface for their applications using FlexiStack, enhancing both the development experience and the end user's interaction with the application.

Flexistack Plugins

Plugins in FlexiStack are reusable components that extend the functionality of actions. They can be invoked by actions to perform specific tasks, such as generating data, interacting with databases, or integrating with external services. A notable feature of FlexiStack's plugin system is its support for versioning, allowing multiple versions of a plugin to coexist. This ensures that improvements or changes can be made to plugins without breaking existing functionality that depends on earlier versions.

Key Elements of a Plugin

  • File Name: Determines the argument name used to invoke the action from the command line.
  • flexi_plugin (decorator): Contains metadata about the plugin, including its name, version and description. This information is crucial for the framework to manage and utilize the plugin correctly.
  • Multiple Versions: Plugins can have multiple versions, each residing in its own directory under the plugin's main directory. The version is specified in the flexi_plugin decorator
  • init (method-optional): Performs initial setup based on the provided command-line arguments.
  • run (method-optional): Contains the main logic to be executed when the action is invoked.

Plugin Versioning

FlexiStack supports multiple versions of plugins, allowing developers to introduce enhancements or fixes without breaking existing functionality. Plugin versioning follows a structured approach, where each version is identified by a version number (e.g., 0.1, 0.2, etc.). When loading plugins, FlexiStack automatically selects the latest version available.

Implementing a Plugin

To implement a plugin, create a directory under the plugins directory of your application, named after the plugin. Within this directory, create subdirectories for each version of the plugin, containing a Python script that defines the plugin's functionality.

Example: Dummy Data Generator Plugin (v0.2)

from flexistack import *

@flexi_plugin("dummy-generator", '0.2', "A plugin to generate dummy data for testing purposes")
class Plugin:

    def init(self,**kargs):
        print ("Dummy Data Generator Init")
        pass

    def random_string(self, length):
        # Example method to generate a random string
        return ''.join(random.choices(string.ascii_letters + string.digits, k=length))

Using a Plugin within an Action

Actions as well as other plugins can utilize plugins by accessing them through the flexistack.plugins property. The framework ensures that actions can easily call upon plugin functionality while respecting versioning requirements.

Example: Generating a Random String in an Action

from flexistack import *

@flexi_action(None, 'Generate a random string')
class Action:

    length = None

    def set_optional_arguments(self, parser, modules):
        parser.add_argument('-l', '--length', type=int, help="Length of the random string")

     def init(self,**kargs):
        try:
            args = kargs['pargs']
            if ('length' in args):
                self.length = int(args['length'])
                return True
        except:
            pass
        return False

  def run(self, **kwargs):
        # Accessing the latest version of the dummy-generator plugin
        dummy_generator = self.flexistack.plugins['dummy-generator']()
        random_string = dummy_generator.random_string(self.length)
        print(f"Generated Random String: {random_string}")

In this example, the action generates a random string by utilizing the dummy-generator plugin. It specifies the length of the string through an optional argument. The action calls the random_string method of the latest version of the dummy-generator plugin, demonstrating how FlexiStack facilitates the interaction between actions and plugins while leveraging plugin versioning to ensure compatibility and flexibility.

Helper Class

FlexiStack includes a @Helper@ class that provides a collection of commonly used helper functions. This class is accessible via the @flexistack.helper@ property.

Available Helper Methods

  • resolve_path(path): Resolves the given path, resolving any symbolic links if present.
  • shortcut_resolver(item): Resolves a shortcut item to its target path, considering the operating system.
  • get_total_cpu(): Returns the total number of CPU cores, including logical and physical cores.
  • generate_random_string(length): Generates a random string of specified length using ASCII letters and digits.
  • generate_random_number(length): Generates a random number string of specified length.
  • get_total_mem(): Returns the total virtual and swap memory in gigabytes.
  • filehash_md5(fname): Computes the MD5 hash of the specified file.
  • filehash_sha256(fname): Computes the SHA-256 hash of the specified file.
  • encrypt(key, plaintext): Encrypts the plaintext using AES algorithm with the provided key.
  • decrypt(key, ciphertextb64): Decrypts the base64 encoded ciphertext using AES algorithm with the provided key.
  • split_into_slices(A, slices): Splits the given list into slices as per the provided slices parameter.

You can access the helper methods within your actions or plugins as follows:

helper = self.flexistack.helper
random_string = helper.generate_random_string(10)
print(f"Random String: {random_string}")

Configuration Vault

FlexiStack integrates @ConfigVault@ to securely store and retrieve configuration data within your application. The @ConfigVault@ is accessible via the @flexistack.config_vault@ property.

Storing Configuration

Store a configuration dictionary securely under a specific key. Set @force=True@ if you want to overwrite an existing entry.

python data = {"database": "mydb", "user": "admin", "password": "secure_password"}
self.flexistack.config_vault.store("db_config", data, force=True) # Overwrites if "db_config" exists

Retrieving Configuration

Retrieve and decrypt stored data by its key.

python retrieved_data = self.flexistack.config_vault.retrieve("db_config") 
print(retrieved_data) # Output: {"database": "mydb", "user": "admin", "password": "secure_password"} 

Removing Configurations

To remove a specific configuration by its key, use the @remove@ method.

python self.flexistack.config_vault.remove("db_config") # Removes the configuration with key "db_config"

To remove all stored configurations, use the @remove_all@ method:

python self.flexistack.config_vault.remove_all() # Clears all configurations

Framework Arguments

You can pass framework related arguments by appending -- <argument> when you call your software.

Chrono Mode

The chrono mode when enabled, provides timing information about various operations, such as loading middleware, plugins, actions, and executing actions.

To enable chrono mode, use the --chrono command-line argument when running your application:

python __main__.py <application arguments> -- --chrono

Debug Mode

The debug mode that provides detailed debug information during execution.

To enable debug mode, use the --debug command-line argument when running your application:

python __main__.py <application arguments> -- --debug

Conclusion

FlexiStack simplifies the development of modular Python applications by handling argument parsing and supporting multiple versions of plugins. Its intuitive design allows for quick setup and seamless integration into various project structures.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flexistack-0.2.10.tar.gz (23.0 kB view details)

Uploaded Source

Built Distribution

flexistack-0.2.10-py3-none-any.whl (18.4 kB view details)

Uploaded Python 3

File details

Details for the file flexistack-0.2.10.tar.gz.

File metadata

  • Download URL: flexistack-0.2.10.tar.gz
  • Upload date:
  • Size: 23.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for flexistack-0.2.10.tar.gz
Algorithm Hash digest
SHA256 e1541bea9140c7714bdffbaba6870eedd0ec33ac6748fa1253a069a130780bf3
MD5 c2ee185d0913fe09e047f1aa10487c8b
BLAKE2b-256 01f8f20cdaa9e1a811315a2429d9be77d78014e3e53af741eb4b03f3b7102fbe

See more details on using hashes here.

File details

Details for the file flexistack-0.2.10-py3-none-any.whl.

File metadata

  • Download URL: flexistack-0.2.10-py3-none-any.whl
  • Upload date:
  • Size: 18.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for flexistack-0.2.10-py3-none-any.whl
Algorithm Hash digest
SHA256 761bbe521f0c4a75e37566f9ed96a746b8cd26943c29639565c996a07619a642
MD5 4671a3204ac80f563f9749cd19b07c2b
BLAKE2b-256 772c7319fc1de71a9605c55368bd12ecc314fa6e9a2d8f63c87ef0325bb83ae9

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page