Skip to content

Commit 54a949d

Browse files
authored
Merge pull request #27 from Flow-Launcher/update_py_docs
update Python plugin documentation
2 parents 432b163 + 73d459e commit 54a949d

File tree

8 files changed

+179
-13
lines changed

8 files changed

+179
-13
lines changed

_sidebar.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
- Dotnet Plugins
77
- [**Development Guide**](/develop-dotnet-plugins.md)
88
- [**API Reference**](API-Reference/)
9-
- JSONRPC Plugins
9+
- Python Plugins
10+
- [**Before you start**](/py-develop-plugins.md)
11+
- [**Set up your project**](/py-setup-project.md)
12+
- [**Write the code**](/py-write-code.md)
13+
- [**Add your plugin to Flow**](/py-release-project.md)
14+
- [**Plugin references**](/py-plugin-references.md)
15+
- JSONRPC
1016
- [**JSON RPC Introduction**](/json-rpc.md)
11-
- [**Develop Python Plugins**](/develop-py-plugins.md)
1217
- [**Porting Plugins**](/port-plugins.md)
13-
1418
- [**How To Create a Theme**](/how-to-create-a-theme.md)
15-

develop-py-plugins.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

port-plugins.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
### Notes
44

55
- When porting, please keep the author's commit history
6-
- Flow Launcher targets .Net Core 3.1, so plugins should also be upgraded to keep the continuity of future developments
6+
- Flow Launcher targets .Net 5, so plugins should also be upgraded to keep the continuity of future developments
77
- All dll libraries used by the plugin should be outputted and included in the final build, to do this, set the attribute CopyLocalLockFileAssemblies in your project file to true
88

99
### Steps
@@ -12,7 +12,7 @@
1212
2. Use try convert tool from https://github.com/dotnet/try-convert
1313
3. Try-convert -w path-to-folder-or-solution-or-project
1414
4. May need to fix on the project file, a good template to follow is the [Explorer plugin](https://github.com/Flow-Launcher/Flow.Launcher/blob/dev/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj) project:
15-
- fix <TargetFramework> to netcoreapp3.1
15+
- fix <TargetFramework> to net5.0-windows
1616
- set the output location as 'Output\Release\<name of the project>'
1717
- add `<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>` and `<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>` to the csproj file
1818
- bump version to 2.0.0 and fix up any missing attributes if neccessary

py-develop-plugins.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
### About Flow's Python plugins
2+
3+
Python plugins use the [JSON-RPC](https://flow-launcher.github.io/docs/#/json-rpc) protocol to communicate with Flow via JSON structured calls.
4+
5+
When building a Python plugins there are several things to be mindful of:
6+
7+
* The most important thing is we do not expect users to have to manually install the dependencies in requirements.txt because we aim to provide a seamless experience for them. This can be achieved by adding the following three things to your project:
8+
1. Add a GitHub workflow- use a GitHub workflow that will install all your plugin's depedencies including the Python flowlauncher module to a folder called Lib inside your plugin.
9+
2. Publish all as a zip- zip up your project including a lib directory that contains the modules and publish it to GitHub Releases page.
10+
3. Point your module imports to the lib directory- reference all the modules to that directory where they are first imported.
11+
12+
* The user can use their own system installed Python with Flow Launcher. But in most circumstances the user will most likely be using Flow Launcher's own embedded Python executable. [Embedded Python](https://docs.python.org/3/using/windows.html#the-embeddable-package) is isolated from the users system and does not prepend the scripts run directory to the system `PATH`.<sup>[ref](https://bugs.python.org/issue28245)</sup> If you need to import external files please follow the example below.
13+
14+
### Simple Example
15+
Have a look at this simple example plugin [here](https://github.com/Flow-Launcher/plugin-samples/tree/master/HelloWorldPython), notice it has a folder called '.github/workflows' and a file called 'Publish Release.yml'. This is the workflow file that GitHub Workflow uses to run the CICD for the project. Moving out of that folder you can go into the [main.py](https://github.com/Flow-Launcher/plugin-samples/blob/master/HelloWorldPython/plugin.json) file, this is the entry file for your plugin. Notice it has this code block:
16+
```python
17+
import sys,os
18+
parent_folder_path = os.path.abspath(os.path.dirname(__file__))
19+
sys.path.append(parent_folder_path)
20+
sys.path.append(os.path.join(parent_folder_path, 'lib'))
21+
sys.path.append(os.path.join(parent_folder_path, 'plugin'))
22+
```

py-plugin-references.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
### Good references to follow
2+
3+
Here are some plugins which could help you build out your own or serve as a reference point:
4+
- IsPrime https://github.com/lvonkacsoh/Flow.Launcher.Plugin.IsPrime
5+
- RollDice https://github.com/lvonkacsoh/Flow.Launcher.RollDice
6+
- FancyEmoji https://github.com/Ma-ve/Flow.Launcher.Plugin.FancyEmoji
7+
- Steam Search https://github.com/Garulf/Steam-Search
8+
- Currency Converter https://github.com/deefrawley/Flow.Launcher.Plugin.Currency

py-release-project.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
### Release your plugin to Flow's Plugin Store
2+
When you are ready to release your plugin for people to enjoy, simply head over to Flow's [plugin repo](https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest) and follow the instructions there in the readme.

py-setup-project.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
### 1. Add GitHub workflow
2+
The workflow [file](https://github.com/Flow-Launcher/plugin-samples/blob/master/HelloWorldPython/.github/workflows/Publish%20Release.yml) will help build and deploy your project, it does the following things:
3+
1. `workflow_dispatch:` gives you the option to manually run your workflow from the Actions section of your project
4+
2. On pushes to main, it will kick off the workflow but ignore the push if it's only changes made to the workflow file.
5+
```yml
6+
push:
7+
branches: [ main ]
8+
paths-ignore:
9+
- .github/workflows/*
10+
```
11+
3. It specifies the python version that will be used for building your project:
12+
```yml
13+
env:
14+
python_ver: 3.8
15+
```
16+
4. The project's release version is obtained from your plugin.json automatically by the ci, so when built it will be appended to the zip file later:
17+
```yml
18+
- name: get version
19+
id: version
20+
uses: notiz-dev/github-action-json-property@release
21+
with:
22+
path: 'plugin.json'
23+
prop_path: 'Version'
24+
```
25+
5. The 'Install dependencies' section is where you will do most of your CI work. Notice it installs the requirements.txt and outputs it with the `-t` parameter to the `./lib` folder. This tells pip to dump all the installed modules to the local lib folder which you will zip up along with your project using the `zip -r <NAME-OF-YOUR-PLUGIN>.zip . -x '*.git*'`, where you replace this `<NAME-OF-YOUR-PLUGIN>` with the name of your plugin.
26+
27+
You can also add additional steps here to unpack/install any additional depedencies your plugin requires, for example compiling additional translation files like [this](https://github.com/deefrawley/Flow.Launcher.Plugin.Currency/blob/23770ee929af059b1b1b7f9b5f3327b692ac9587/.github/workflows/Publish%20Release.yml#L34)
28+
```yml
29+
- name: Install dependencies
30+
run: |
31+
python -m pip install --upgrade pip
32+
pip install -r ./requirements.txt -t ./lib
33+
zip -r <NAME-OF-YOUR-PLUGIN>.zip . -x '*.git*'
34+
```
35+
36+
### 2. Publish as zip
37+
The final step to the workflow file is this publish section, which will publish the zip file you generated, upload to GitHub Releases page and tag with the version generated from the previous step from your plugin.json file. Remmember again to replace `<NAME-OF-YOUR-PLUGIN>` with the name of your plugin.
38+
```yml
39+
- name: Publish
40+
if: success() && github.ref == 'refs/heads/main'
41+
uses: softprops/action-gh-release@v1
42+
with:
43+
files: '<NAME-OF-YOUR-PLUGIN>.zip'
44+
tag_name: "v${{steps.version.outputs.prop}}"
45+
env:
46+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47+
```
48+
49+
Feel free to also have a read of this [blog post](https://blog.ipswitch.com/how-to-build-your-first-github-actions-workflow) which does a simple explaination of how to use GitHub Actions Workflow.
50+
51+
### 3. Use lib directory
52+
Once the lib folder is included in your zip release, it can then be used without needing the user to manually pip install. You just have to tell during runtime to find those modules in your local lib folder. Do this by using this exact copy of the following block of code:
53+
```python
54+
import sys,os
55+
parent_folder_path = os.path.abspath(os.path.dirname(__file__))
56+
sys.path.append(parent_folder_path)
57+
sys.path.append(os.path.join(parent_folder_path, 'lib'))
58+
sys.path.append(os.path.join(parent_folder_path, 'plugin'))
59+
60+
```
61+
Add the above code into your init file at the top, usually this is the [main.py](https://github.com/Flow-Launcher/plugin-samples/blob/master/HelloWorldPython/main.py) file. This block of code appends the path of your lib and plugin directories on the user's machine to `sys.path`. `sys.path` is a built-in variable within the sys module, which contains a list of directories that the Python interpreter will search in for the required module. Effectively we are telling the interpreter if the required modules in your plugin are not found among its built-in modules then look through the list of directories defined by sys.path, which should have all the modules installed by your GitHub workflow in the 'lib' folder.

py-write-code.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
### 1. Start with a branch
2+
Since we have created a CI for your plugin in the [previous step](https://flow-launcher.github.io/docs/#/py-setup-project), which includes creating a release when you push/merge to the 'main' branch, it is then neccessary to create another git branch separate to your 'main' branch so you can continue to work on your plugin with git commits and pushes without creating a new release each time.
3+
4+
It is a good practice that you create a branch for each of the new feature/fixes you are releasing for your plugin, if you are not sure how to do so then follow this [video tutorial](https://www.gitkraken.com/learn/git/problems/create-git-branch). Once you have fully finished developing your plugin with your new branch, then you can merge it into the 'main' branch, which will consequently create a new release for your plugin with a version from your `plugin.json`.
5+
6+
### 2. main.py
7+
your main.py should look something like below:
8+
```
9+
import sys,os
10+
parent_folder_path = os.path.abspath(os.path.dirname(__file__))
11+
sys.path.append(parent_folder_path)
12+
sys.path.append(os.path.join(parent_folder_path, 'lib'))
13+
sys.path.append(os.path.join(parent_folder_path, 'plugin'))
14+
15+
from flowlauncher import FlowLauncher
16+
17+
18+
class HelloWorld(FlowLauncher):
19+
20+
def query(self, query):
21+
return [
22+
{
23+
"Title": "Hello World, this is where title goes. {}".format(('Your query is: ' + query , query)[query == '']),
24+
"SubTitle": "This is where your subtitle goes",
25+
"IcoPath": "Images/app.png",
26+
"JsonRPCAction": {
27+
"method": "do_something_for_query",
28+
"parameters": [param1, param2]
29+
}
30+
"ContextData": "ctxData",
31+
}
32+
]
33+
34+
def context_menu(self, data):
35+
return [
36+
{
37+
"Title": "Context menu entry",
38+
"SubTitle": "Data: {}".format(data),
39+
"IcoPath": "Images/app.ico",
40+
}
41+
]
42+
43+
def do_something_for_query(self, param1, param2):
44+
pass
45+
46+
if __name__ == "__main__":
47+
HelloWorld()
48+
49+
```
50+
51+
<br/>
52+
53+
### 3. Query entry point
54+
**def query(self, query):**
55+
56+
This is the main entry to your plugin and the return block will be a list of the results that your plugin returns, which could be a single or many results.
57+
58+
### 4. Assigning an action to your results
59+
**JsonRPCAction**
60+
61+
This is where you specify the method that will be executed when the user selects on the result.
62+
In this example, if the user selects the result, the `do_something_for_query` method will be called with the two parameters, it is then up to you to define what you want the method to do.
63+
64+
### 5. Create an additional context menu
65+
**def context_menu(self, data):**
66+
67+
This method creates a context menu for your results, where the user can carry out additional tasks when the go to the context menue via pressing `Shift + Enter`. A context menu could be helpful if you want some tasks specific to your returned results, for example the Explorer plugin would return a list of file results, and when going to the context menu of one of the result users can select to copy the file.
68+
69+
To attach a method to your context menu result, do the same as for normal results where you define a JsonRPCAction item with the method and parameters you want to call and pass through.
70+
71+
### 6. Your plugin.json
72+
73+
You will also need to if not yet already, create a plugin.json file that will instruct Flow on how to load your plugin.
74+
75+
This file should be placed in the top level folder.
76+
77+
To revisit what to include in your plugin.json, visit [here](https://flow-launcher.github.io/docs/#/plugin.json)

0 commit comments

Comments
 (0)