Squiffy is the minimal library that helps you build your CLI application before your boss notices
Project description
squiffy - a light library for interactive CLI application
This is squiffy, a small, small - wonderfully small - library for developing and deploying locally interactive CLI applications.
It's intended for things that should be done quickly, with prime focuse on functionality and not on the infrastructure.
We aim to provide a bit of infrastructure for simple applications, that depend on user interaction which triggers custom actions.
Table of Contents
Installation
You can use pip to install squiffy into your environment.
pip install squiffy
Additionally we encourage usage of virtualenv to for development environments. we recommend to use pipenv for your development environment.
Install pipenv using pip:
pip install pipenv
If restricted or there are problems with pip, you can use:
python -m pip install pipenv
Navigate in the directory you wish to install squiffy into and develop the app and use pipenv install to install squiffy.
cd my_app
pipenv install squiffy
If you want to modify squiffy to suit your need, just clone the repo:
cd my_app
git init.
git clone https://github.com/Gygarte/squiffy.git
Create the environment and install de dependencies specified in the Pipfile using:
pipenv --python 3.12
pipenv install --dev
or:
python -m pipenv --python 3.12
python -m pipenv install --dev
Start using squiffy in your project.
Note: Refer to the pipenv documentation here: https://pypi.org/project/pipenv/
Usage
Squiffy uses four mandatory items to setup the CLI application:
- layout.json the blueprint of your application's layout.
- LayoutFactory the main class for app layout construction
- State the main class for configuring an internal state - which contains whatever informations is needed in the app
- Application the main class to be used
Creating a layout.json
An example equals to 1000 words :D (please be advise that I purposfully let some keywords that do nothing yet! Squiffy is still in alpha and I'm still a noob)
{
"submenu": [
{
"title": "Main_Menu",
"main":true,
"logo_path": null, // NOT IMPLEMENTED
"header_msg": "This is the header for the main menu",
"footer_msg": "Gabriel Artemie@2023",
"return_to_previous": false,
"return_to_main": false,
"quit": true,
"options": [
{
"option": "SwitchToSubmenu2",
"include_help": true, // NOT IMPLEMENTED
"help": "SwitchToSubmenu2 help", // NOT IMPLEMENTED
"switch":"Second_Menu",
"action": null // NOT IMPLEMENTED
},
{
"option": "Print_and_wait",
"include_help": true, // NOT IMPLEMENTED
"help": "Print_and_wait help", // NOT IMPLEMENTED
"switch":null,
"action": null // NOT IMPLEMENTED
},
{
"option": "Trigger_an_error",
"include_help": true, // NOT IMPLEMENTED
"help": "Trigger_an_error help", // NOT IMPLEMENTED
"switch":null,
"action": null // NOT IMPLEMENTED
}
],
"style":null // NOT IMPLEMENTED: to use a special style for each submenu
},
{
"title": "Second_Menu",
"main":false,
"logo_path": null, // NOT IMPLEMENTED
"header_msg": "This is another header message for submenu2",
"footer_msg": "Gabriel Artemie@2023",
"return_to_previous": true,
"return_to_main": true,
"quit": true,
"options": [
{
"option": "Accept_an_input",
"include_help": true, // NOT IMPLEMENTED
"help": "option1 help", // NOT IMPLEMENTED
"switch":null,
"action": null // NOT IMPLEMENTED
},
{
"option": "Print_the_state",
"include_help": true, // NOT IMPLEMENTED
"help": "option2 help", // NOT IMPLEMENTED
"switch":null,
"action": null // NOT IMPLEMENTED
}
],
"style":null // NOT IMPLEMENTED: to use a special style for each submenu
}
],
"error_handling":{
"name":"Error",
"include":true,
"log_path":null // NOT IMPLEMENTED
},
"style_sheet_path":null, //NOT IMPLEMENTED: a path to a separate style sheet
"default_style":{
"dimensions":{
"type":"auto",
"width":null,
"height":null
},
"padding":{
"top":1,
"right":2,
"bottom":1,
"left":2
},
"border":{
"type":"light" // You can chouse from "light", "thick" and "double" border style
}
}
}
The LayoutFactory
The layout is created by passing the path to the layout.json to the LayoutFactory constructor
from squiffy import LayoutFactory
layout = LayoutFactory('my_app/layout.json')
The style
The style sheet is still a simple approach for a kinda' retro style type. The inspiration for the style apperance was drawn from the console-menu project by @aergirhall (many many thanks to you for the ideas and I hope you do not dissaprove that I've used them)
From the above layout.json you can guess what styling options are available in this version.
Please see the Future Developments section bellow for details regarding the development of this feature.
Setting a State
A State keeps data that are used by the callback functions. You can add specific configuration in the State from the app initialization and from the callback functions.
The State is configured to be saved whenewer the app is quitting or an error is triggered. So, any configurations passed to the State should implement a saving mechanism.
Let's assume:
from dataclass import datacalss
@dataclass
class MyConfig:
# a bunch of attributes and configurations
def save(self) -> None:
# some saving logic
So the State will be defined as:
state = State({"config":MyConfig()})
Setting the application
This is as simple as passing the State and Layout to the Application constructor and hit run.
app = Application(layout=layout, state=state)
app.run()
Setting callback functions
In order to do some stuff with all this we need some end function. The end functions should use the State and return a signal like OK, Error, Abort
Let's see an example:
from squiffy import State
from squiffy.signals import OK, Error, Abort
def my_func(state:State) -> OK | Error | Abort:
# do some stuff and return something
In order to save the results of the computation in the State you just pass a dictionary with the name_of_the_data and the actual_data_object to the OK.payload().
If an error occured you can pass the following arguments to the Error: origin, log_message, traceback
from squiffy import State
from squiffy.signals import OK, Error, Abort
def my_func(state:State) -> OK | Error | Abort:
# all is good and the computation runned smoothly
resulted_state = {"name_of_the_data":actual_data_object}
return OK(pyload=resulted_state)
# an error occured
return Error()
# you are fancy and use try-except and traceback.format_exc
try:
# some shady stuff
except Exception:
return Error(origin="here",log_message="Some shady error occured!", traceback=format_exc())
Finally your function is passed to the app instance as follows
def main() -> None:
app = Application(layout=layout, state=state)
app.add(function=my_func, option="Option1", submenu="Submenu1") # tadaaaa
app.run()
if __name__ == "__main__":
main()
That is all! You can start building simple and beautifull stuff and show your work bestie the cool stuff you do because you do not have a real life :D. Cheers!
Examples
We enjoy having an example ready to be explored. just write the following and enjoy our small and not-so-creative example.
python -m squiffy.example.example
or if this fails, try to write the following in a .py file.
from squiffy import example
if __name__ == "__main__":
example.main()
Future Developments
- Include the rendering and display of the logo based on a logo_path.
- Include a keybinding for visualizing the help information for each option on the menu.
- Include special stylesheet for each submenu (not sure I will follow this path tho!)
- Include error logging into dedicated file.
- Separate the style sheet from the layout sheet.
- Refactoring: improvements of the architecture, code redability, commenting and more.
- Include keybindings for common options like: return_to_previous, return_to_main, quit and others.
- Write tests!
Contributing
We accept contributions, sugestions and any thought on how to improve squiffy or what edge cases should be treated (ofc and new features suggestions).
License
Please see the License section.
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
Built Distribution
File details
Details for the file squiffy-0.1.2.tar.gz
.
File metadata
- Download URL: squiffy-0.1.2.tar.gz
- Upload date:
- Size: 24.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6d548a31bd804da26a865e46ced8bb2f0307eefed2d41e5ae46dd8596fac8198 |
|
MD5 | 5bf9d42bc1da0d171beb3f1673f9e25a |
|
BLAKE2b-256 | 831d8b9f7e4c902bf226e7f6751d9a17d95f313ea2c0d391b8c826378c33f4b3 |
File details
Details for the file squiffy-0.1.2-py3-none-any.whl
.
File metadata
- Download URL: squiffy-0.1.2-py3-none-any.whl
- Upload date:
- Size: 29.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | d584480ce6638a8323ccd228f9ae73ddd163b3b79c84f30f4c9d931f5801603f |
|
MD5 | 9d87871b3b3a38ec6a239ef903cf3acb |
|
BLAKE2b-256 | 3c94da93fe650fd162deff845c89a0a3ba13078f6bab8f18508bb56fdb088f7f |