Mokha is a Python script that can be configured; via JSON, to automate workflows.
The basic idea of Mokha is as follows:
- You have a task that needs automating - maybe a tedious task or something you need to do a bunch of times.
- You write a Python script/method that does that job.
- You write a little bit of JSON configuration to setup the script.
- You add your python script to the dependencies folder.
- You run mokha.py however you want - keyboard binding, command line alias, whatever floats ya boat.
Aside from writing your scripts, you don't have to code anything to make it work with Mokha. (unless you class JSON as a coding language then I don't know how to help you.)
All the configuration in Mokha is done via JSON files. There are two main categories of configurations:
config.json
: This is the first file loaded by Mokha on startup. The entire purpose of this file is configure the directories of the remaining three configuration files. The default location for all three files are the root directory of the application.
dependencies.json
: A JSON file that outlines of what files, folders, and python scripts your code requires.accounts.json
: A JSON file that outlines high-level structures that outlines different groups of methods you might have, for example: I have three profiles for Home use, Independent work use, and for my main job.methods.json
: JSON File that outlines the structure of all methods being run by Mokha.
The reason for splitting the types of configuration is simple. Base Config
encapsulates anything fundamental to the operation of Mokha itself while User Config
refers to the operation of your scripts.
-
Clone this repo and run
pip install click
andpip install pyperclip
. If that doesn't work trypip3
instead -
Run Mokha.py. It will automatically generate the config.json file with the default values, however, it will not generate those files/folders for you.
-
Create
accounts.json
,methods.json
anddependencies.json
files and adependencies
folder wherever you want. If you deviate from the default values inconfig.json
please update them there.
NOTE: Please put the absolute path for any files or directories outside of the root directory. -
Add an account to the
accounts.json
file as follows:accounts.json
contains an array of json objects for which each object is an account that can contain methods.[ { "--id": "1", "title": "Personal", "functions": [ { "title": "Google Calendar", "methodID": "open-a-website", "arguments": { "URL": "https://calendar.google.com/calendar/b/0/r/month" } }, { "title": "GitHub Profile", "methodID": "open-a-website", "arguments": { "URL": "https://github.com/ChildishhAlbino" } }, { "title": "Personal Blog", "methodID": "open-a-website", "arguments": { "URL": "https://childishhalbino.github.io/" } } ] } ]
An account has the following fields:
-
--id
: A unique identifier for this profile. -
title
: A title for the profile. This gets printed to the console. -
functions
: An array of function objects that detail the method being called and the arguments being passed for this option. -
function
: A function object looks like this:{ "title": "Google Calendar", "methodID": "open-a-website", "arguments": { "URL": "https://calendar.google.com/calendar/b/0/r/month" } },
A function object has the following fields:
title
: This is the name of the function.methodID
: This is a reference to the ID of the method this function calls.arguments
: A JSON object that has keys that equal the parameters names outline in this method's configuration. The value of said key is the argument that will be passed to the method call.
-
-
Now that we have an account to add methods to, let's make one!
Before we can add anything to Mokha, we need to write some code first - let's make a small function that just opens any URL we throw at it in the web browser.
We can achieve this with the following Python code. Let's save it as
utilities.py
in ourdependencies
folder.def openURL(URL="https://www.google.com.au"): webbrowser.open(URL)
To implement this is in Mokha - We'd use the below JSON.
{ "--id": "open-a-website", "name": "openURL", "dependency": "utilities", "schema": { "numParams": 1, "parameterNames": ["URL"] }
A method has the following fields:
--id
: Some unique ID for this specific method definition. Helps keep things modular.name
: This the name of the method in Python you are defining in the Mokha configuration file. This IS case sensitive.dependency
: This is the name of Python module you are importing to run this. You always need only 1 dependency - this will be elaborated in a section below.schema
: This is an object that verifies that a shortcut that calls this method is passing the correct arguments.numParams
: This outlines the number of parameters this method expects. This will be made optional in the future.parameterNames
: An array of string that outline the expected arguments.
-
There's one last step we need to do. We have to tell Mokha to attempt to load our
utilities
dependency on startup.To add a dependency to Mokha, you just have to modify your
dependencies.json
file. By default, it should look like this:{ "python": [], "file-system": [], "remote": [] }
As you can see, there are two fields for different types of dependencies.
python
: Dependencies on Python modules or.py
files.file-system
: Dependencies on any files your Python modules may use to achieve their goals.
NOTE: All file paths stored here can be either absolute or relative to thedependencies
path.remote
: Remote dependencies are files on your PC that may not be best suited stored in your dependencies folder for whatever reason. By putting the absolute path of this file here, Mokha will check said path and copy over the file if it doesn't exist or if the remote version does not match the current version byte-for-byte.
For the purposes of our utilities.py
module, we just have to modify the python
dependencies as follows:
{
"python": ["utilities"],
"file-system": [],
"remote": []
}
-
That's it! You can run Mokha.py and it should (fingers crossed) work. You should get some console output like this:
Attempting to import dependencies from: E:/Documents/Dropbox/Mokha/dependencies --------------------- Filesystem dependencies loaded successfully. Loaded module: Utilities --------------------- Welcome to Mokha V1.0-a. This is a tool designed to enable configuration of shortcuts to python code. 1: Personal Select an option:
Upon selecting a language, you should see this:
Attempting to import dependencies from: E:/Documents/Dropbox/Mokha/dependencies --------------------- Filesystem dependencies loaded successfully. Loaded module: Utilities --------------------- Welcome to Mokha V1.0-a. This is a tool designed to enable configuration of shortcuts to python code. 1: Personal Select an option: 1 1: Google Calendar 2: GitHub Profile 3: Personal Blog Select an option:
Upon selecting whichever option you want; you should see the respective webpage you set for that option open inside your web browser.
The basic flow of the application is as follows:
-
Mokha starts and it attempts to read in
config.py
.- If it doesn't exist, it's creates it with the default values in place.
- Exits the application so the user can configure the rest.
-
Mokha adds whatever path the user set as your
dependencies-path
variable tosys.path
. Allows the user to import modules from outside the root folder ofmokha.py
-
The application then tries to load the user's filesystem dependencies, followed by your python dependencies.
- If Mokha successfully imports their dependencies, it will load in the remainder of their
user-config
files. - Else it will throw an exception and explain why.
- If Mokha successfully imports their dependencies, it will load in the remainder of their
-
Mokha then prompts the user for input on which account they want to access.
-
Mokha takes the input and finds the
account
that matches it, it then finds all thefunctions
associated with it. -
The application will prompt the user for input for which function they want to run and then finds it from their config.
-
Mokha gets the attribute that matches the selected method's
name
field inside it'sdependency
module. -
Mokha constructs a dictionary with keys that equal the parameters outlined in the method's
schema
object and maps them to the selected functionsarguments
object. -
Mokha changes the current directory to the
dependencies-path
value. This is to ensure that a user's scripts function as they would if they were run in isolation. -
This dictionary is then passed as the argument to the Python function call and thanks to keyword-arguments; as long as the dictionary does not have any keys that aren't a parameter on the method (in code), the function should be called without any issues.
(Hopefully that made sense 😂)
Working in Software; both professionally and independently, I just couldn't find a tool that automated the menial, and repetitive tasks I encountered every day, and was flexible in the way I wanted.
So I built Mokha. Mokha works the way YOU want it to. It's cross platform (well, it's as cross platform as the scripts you make it run.) and it's designed to be flexible about how you integrate it into your workflow.
I personally have it bound to a keyboard shortcut on my work MacBook and Windows PC and it works a treat. I expect that other people will use it in a variety of ways so I've left it standalone to allow for you to integrate it the way you want.
So far, there's one small convenience I've added to Mokha that is completely optional for you to implement. If a script you want to run requires text from the clipboard, you can set a parameter to clipboardContext
as follows:
def memeify(clipboardContext=None):
string = clipboardContext if(clipboardContext != None) else pyperclip.paste()
string2 = ""
for c in string:
string2 = string2 + c + " "
pyperclip.copy(string2.strip())
and the configuration in JSON is as such:
{
"title": "Memeify the clipboard text.",
"methodID": "memeify-the-text",
"arguments": {
"clipboardContext": {}
}
}
{
"--id": "memeify-the-text",
"name": "memeify",
"dependency": "memetext",
"schema": {
"numParams": 1,
"parameterNames": ["clipboardContext"]
}
}
Mokha will then pass the value of the clipboard (via pyperclip.paste()
) into the value of clipboardContext
during Step 8 of the application's flow.