afwf_example 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. afwf_example-0.1.1/AUTHORS.rst +15 -0
  2. afwf_example-0.1.1/LICENSE.txt +21 -0
  3. afwf_example-0.1.1/PKG-INFO +103 -0
  4. afwf_example-0.1.1/README.rst +50 -0
  5. afwf_example-0.1.1/afwf_example/__init__.py +1 -0
  6. afwf_example-0.1.1/afwf_example/cache.py +11 -0
  7. afwf_example-0.1.1/afwf_example/cli.py +21 -0
  8. afwf_example-0.1.1/afwf_example/handlers/__init__.py +2 -0
  9. afwf_example-0.1.1/afwf_example/handlers/error.py +22 -0
  10. afwf_example-0.1.1/afwf_example/handlers/memorize_cache.py +43 -0
  11. afwf_example-0.1.1/afwf_example/handlers/open_file.py +49 -0
  12. afwf_example-0.1.1/afwf_example/handlers/open_url.py +48 -0
  13. afwf_example-0.1.1/afwf_example/handlers/open_url_new.py +51 -0
  14. afwf_example-0.1.1/afwf_example/handlers/read_file.py +44 -0
  15. afwf_example-0.1.1/afwf_example/handlers/set_settings.py +103 -0
  16. afwf_example-0.1.1/afwf_example/handlers/view_settings.py +33 -0
  17. afwf_example-0.1.1/afwf_example/handlers/write_file.py +91 -0
  18. afwf_example-0.1.1/afwf_example/paths.py +35 -0
  19. afwf_example-0.1.1/afwf_example/settings.py +12 -0
  20. afwf_example-0.1.1/afwf_example/vendor/__init__.py +2 -0
  21. afwf_example-0.1.1/afwf_example/vendor/pytest_cov_helper.py +125 -0
  22. afwf_example-0.1.1/afwf_example/workflow.py +26 -0
  23. afwf_example-0.1.1/afwf_example.egg-info/PKG-INFO +103 -0
  24. afwf_example-0.1.1/afwf_example.egg-info/SOURCES.txt +37 -0
  25. afwf_example-0.1.1/afwf_example.egg-info/dependency_links.txt +1 -0
  26. afwf_example-0.1.1/afwf_example.egg-info/entry_points.txt +2 -0
  27. afwf_example-0.1.1/afwf_example.egg-info/requires.txt +28 -0
  28. afwf_example-0.1.1/afwf_example.egg-info/top_level.txt +1 -0
  29. afwf_example-0.1.1/pyproject.toml +128 -0
  30. afwf_example-0.1.1/setup.cfg +4 -0
  31. afwf_example-0.1.1/tests/test_handler_error.py +15 -0
  32. afwf_example-0.1.1/tests/test_handler_memorize_cache.py +15 -0
  33. afwf_example-0.1.1/tests/test_handler_open_file.py +14 -0
  34. afwf_example-0.1.1/tests/test_handler_open_url.py +14 -0
  35. afwf_example-0.1.1/tests/test_handler_read_file.py +15 -0
  36. afwf_example-0.1.1/tests/test_handler_view_settings.py +35 -0
  37. afwf_example-0.1.1/tests/test_handler_write_file.py +17 -0
  38. afwf_example-0.1.1/tests/test_import.py +14 -0
  39. afwf_example-0.1.1/tests/test_workflow.py +24 -0
@@ -0,0 +1,15 @@
1
+ .. _about_author:
2
+
3
+ About the Author
4
+ ------------------------------------------------------------------------------
5
+ ::
6
+
7
+ (\ (\
8
+ ( -.-)o
9
+ o_(")(")
10
+
11
+ **Sanhe Hu** is a seasoned software engineer with a deep passion for Python development since 2010. As an author and maintainer of `150+ open-source Python projects <https://pypi.org/user/machugwu/>`_, with over `15 million monthly downloads <https://github.com/MacHu-GWU>`_, I bring a wealth of experience to the table. As a Senior Solution Architect and Subject Matter Expert in AI, Data, Amazon Web Services, Cloud Engineering, DevOps, I thrive on helping clients with platform design, enterprise architecture, and strategic roadmaps.
12
+
13
+ Talk is cheap, show me the code:
14
+
15
+ - My Github: https://github.com/MacHu-GWU
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sanhe Hu <husanhe@email.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.4
2
+ Name: afwf_example
3
+ Version: 0.1.1
4
+ Summary: A sample Alfred Workflow Python project.
5
+ Author-email: Sanhe Hu <husanhe@email.com>
6
+ Maintainer-email: Sanhe Hu <husanhe@email.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/MacHu-GWU/afwf_example-project
9
+ Project-URL: Documentation, https://afwf-example.readthedocs.io/en/latest/
10
+ Project-URL: Repository, https://github.com/MacHu-GWU/afwf_example-project
11
+ Project-URL: Issues, https://github.com/MacHu-GWU/afwf_example-project/issues
12
+ Project-URL: Changelog, https://github.com/MacHu-GWU/afwf_example-project/blob/main/release-history.rst
13
+ Project-URL: Download, https://pypi.org/pypi/afwf-example#files
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Natural Language :: English
17
+ Classifier: Operating System :: Microsoft :: Windows
18
+ Classifier: Operating System :: MacOS
19
+ Classifier: Operating System :: Unix
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
26
+ Requires-Python: <4.0,>=3.10
27
+ Description-Content-Type: text/x-rst
28
+ License-File: LICENSE.txt
29
+ License-File: AUTHORS.rst
30
+ Requires-Dist: afwf<2.0.0,>=1.0.1
31
+ Requires-Dist: fire<1.0.0,>=0.7.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: rich<14.0.0,>=13.8.1; extra == "dev"
34
+ Provides-Extra: test
35
+ Requires-Dist: pytest<9.0.0,>=8.2.2; extra == "test"
36
+ Requires-Dist: pytest-cov<7.0.0,>=6.0.0; extra == "test"
37
+ Provides-Extra: doc
38
+ Requires-Dist: Sphinx<8.0.0,>=7.4.7; extra == "doc"
39
+ Requires-Dist: sphinx-copybutton<1.0.0,>=0.5.2; extra == "doc"
40
+ Requires-Dist: sphinx-design<1.0.0,>=0.6.1; extra == "doc"
41
+ Requires-Dist: sphinx-jinja<3.0.0,>=2.0.2; extra == "doc"
42
+ Requires-Dist: furo==2024.8.6; extra == "doc"
43
+ Requires-Dist: pygments<3.0.0,>=2.18.0; extra == "doc"
44
+ Requires-Dist: ipython<8.19.0,>=8.18.1; extra == "doc"
45
+ Requires-Dist: nbsphinx<1.0.0,>=0.8.12; extra == "doc"
46
+ Requires-Dist: rstobj==2.0.0; extra == "doc"
47
+ Requires-Dist: docfly==3.0.3; extra == "doc"
48
+ Provides-Extra: mise
49
+ Requires-Dist: PyGithub<3.0.0,>=2.8.0; extra == "mise"
50
+ Requires-Dist: httpx<1.0.0,>=0.28.0; extra == "mise"
51
+ Requires-Dist: tomli<3.0.0,>=2.0.0; python_version < "3.11" and extra == "mise"
52
+ Dynamic: license-file
53
+
54
+
55
+ .. image:: https://readthedocs.org/projects/afwf-example/badge/?version=latest
56
+ :target: https://afwf-example.readthedocs.io/en/latest/
57
+ :alt: Documentation Status
58
+
59
+ .. image:: https://github.com/MacHu-GWU/afwf_example-project/actions/workflows/main.yml/badge.svg
60
+ :target: https://github.com/MacHu-GWU/afwf_example-project/actions?query=workflow:CI
61
+
62
+ .. image:: https://codecov.io/gh/MacHu-GWU/afwf_example-project/branch/main/graph/badge.svg
63
+ :target: https://codecov.io/gh/MacHu-GWU/afwf_example-project
64
+
65
+ .. image:: https://img.shields.io/pypi/v/afwf-example.svg
66
+ :target: https://pypi.python.org/pypi/afwf-example
67
+
68
+ .. image:: https://img.shields.io/pypi/l/afwf-example.svg
69
+ :target: https://pypi.python.org/pypi/afwf-example
70
+
71
+ .. image:: https://img.shields.io/pypi/pyversions/afwf-example.svg
72
+ :target: https://pypi.python.org/pypi/afwf-example
73
+
74
+ .. image:: https://img.shields.io/badge/✍️_Release_History!--None.svg?style=social&logo=github
75
+ :target: https://github.com/MacHu-GWU/afwf_example-project/blob/main/release-history.rst
76
+
77
+ .. image:: https://img.shields.io/badge/⭐_Star_me_on_GitHub!--None.svg?style=social&logo=github
78
+ :target: https://github.com/MacHu-GWU/afwf_example-project
79
+
80
+ ------
81
+
82
+ .. image:: https://img.shields.io/badge/Link-API-blue.svg
83
+ :target: https://afwf-example.readthedocs.io/en/latest/py-modindex.html
84
+
85
+ .. image:: https://img.shields.io/badge/Link-GitHub-blue.svg
86
+ :target: https://github.com/MacHu-GWU/afwf_example-project
87
+
88
+ .. image:: https://img.shields.io/badge/Link-Submit_Issue-blue.svg
89
+ :target: https://github.com/MacHu-GWU/afwf_example-project/issues
90
+
91
+ .. image:: https://img.shields.io/badge/Link-Request_Feature-blue.svg
92
+ :target: https://github.com/MacHu-GWU/afwf_example-project/issues
93
+
94
+ .. image:: https://img.shields.io/badge/Link-Download-blue.svg
95
+ :target: https://pypi.org/pypi/afwf-example#files
96
+
97
+
98
+ Welcome to ``afwf_example`` Documentation
99
+ ==============================================================================
100
+ .. image:: https://afwf-example.readthedocs.io/en/latest/_static/afwf_example-logo.png
101
+ :target: https://afwf-example.readthedocs.io/en/latest/
102
+
103
+ This project demonstrates best practices for building Alfred Workflows using the `afwf <https://github.com/MacHu-GWU/afwf-project>`_ framework. You can use it as a reference to learn how ``afwf`` works. A `cookiecutter-afwf <https://github.com/MacHu-GWU/cookiecutter-afwf>`_ project template is also available — simply provide a project name and it will generate a ready-to-use Git repository with all the automation scripts and example code you need.
@@ -0,0 +1,50 @@
1
+
2
+ .. image:: https://readthedocs.org/projects/afwf-example/badge/?version=latest
3
+ :target: https://afwf-example.readthedocs.io/en/latest/
4
+ :alt: Documentation Status
5
+
6
+ .. image:: https://github.com/MacHu-GWU/afwf_example-project/actions/workflows/main.yml/badge.svg
7
+ :target: https://github.com/MacHu-GWU/afwf_example-project/actions?query=workflow:CI
8
+
9
+ .. image:: https://codecov.io/gh/MacHu-GWU/afwf_example-project/branch/main/graph/badge.svg
10
+ :target: https://codecov.io/gh/MacHu-GWU/afwf_example-project
11
+
12
+ .. image:: https://img.shields.io/pypi/v/afwf-example.svg
13
+ :target: https://pypi.python.org/pypi/afwf-example
14
+
15
+ .. image:: https://img.shields.io/pypi/l/afwf-example.svg
16
+ :target: https://pypi.python.org/pypi/afwf-example
17
+
18
+ .. image:: https://img.shields.io/pypi/pyversions/afwf-example.svg
19
+ :target: https://pypi.python.org/pypi/afwf-example
20
+
21
+ .. image:: https://img.shields.io/badge/✍️_Release_History!--None.svg?style=social&logo=github
22
+ :target: https://github.com/MacHu-GWU/afwf_example-project/blob/main/release-history.rst
23
+
24
+ .. image:: https://img.shields.io/badge/⭐_Star_me_on_GitHub!--None.svg?style=social&logo=github
25
+ :target: https://github.com/MacHu-GWU/afwf_example-project
26
+
27
+ ------
28
+
29
+ .. image:: https://img.shields.io/badge/Link-API-blue.svg
30
+ :target: https://afwf-example.readthedocs.io/en/latest/py-modindex.html
31
+
32
+ .. image:: https://img.shields.io/badge/Link-GitHub-blue.svg
33
+ :target: https://github.com/MacHu-GWU/afwf_example-project
34
+
35
+ .. image:: https://img.shields.io/badge/Link-Submit_Issue-blue.svg
36
+ :target: https://github.com/MacHu-GWU/afwf_example-project/issues
37
+
38
+ .. image:: https://img.shields.io/badge/Link-Request_Feature-blue.svg
39
+ :target: https://github.com/MacHu-GWU/afwf_example-project/issues
40
+
41
+ .. image:: https://img.shields.io/badge/Link-Download-blue.svg
42
+ :target: https://pypi.org/pypi/afwf-example#files
43
+
44
+
45
+ Welcome to ``afwf_example`` Documentation
46
+ ==============================================================================
47
+ .. image:: https://afwf-example.readthedocs.io/en/latest/_static/afwf_example-logo.png
48
+ :target: https://afwf-example.readthedocs.io/en/latest/
49
+
50
+ This project demonstrates best practices for building Alfred Workflows using the `afwf <https://github.com/MacHu-GWU/afwf-project>`_ framework. You can use it as a reference to learn how ``afwf`` works. A `cookiecutter-afwf <https://github.com/MacHu-GWU/cookiecutter-afwf>`_ project template is also available — simply provide a project name and it will generate a ready-to-use Git repository with all the automation scripts and example code you need.
@@ -0,0 +1 @@
1
+ # -*- coding: utf-8 -*-
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ Disk cache for Alfred Workflow.
5
+ """
6
+
7
+ from diskcache import Cache
8
+
9
+ from .paths import dir_cache
10
+
11
+ cache = Cache(dir_cache.abspath)
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import json
4
+
5
+
6
+ class Command:
7
+ def open_url_new(self, query: str = ""):
8
+ from afwf_example.handlers.open_url_new import handler
9
+
10
+ sf = handler.handler(query)
11
+ print(json.dumps(sf.to_script_filter(), indent=4))
12
+
13
+
14
+ def main():
15
+ import fire
16
+
17
+ fire.Fire(Command)
18
+
19
+
20
+ if __name__ == "__main__":
21
+ main()
@@ -0,0 +1,2 @@
1
+ # -*- coding: utf-8 -*-
2
+
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ This handler will always raise an error. It is used for testing purpose.
5
+ """
6
+
7
+ import typing as T
8
+ import attrs
9
+ import afwf.api as afwf
10
+
11
+
12
+ @attrs.define
13
+ class Handler(afwf.Handler):
14
+ def main(self) -> afwf.ScriptFilter:
15
+ afwf.log_debug_info("before raising the error")
16
+ raise Exception("raise this error intentionally")
17
+
18
+ def parse_query(self, query: str) -> T.Dict[str, T.Any]:
19
+ return {}
20
+
21
+
22
+ handler = Handler(id="error")
@@ -0,0 +1,43 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ [CN]
5
+
6
+ 该 Script Filter 的功能是根据 key 随机生成一个 1 ~ 1000 之间的 value. 这个 value 的值
7
+ 将会被缓存 5 秒. 5 秒内查询同一个 key 的结果将会是一样的. 该例子用来展示如何使用 time to live
8
+ 缓存.
9
+
10
+ 在 Alfred Workflow 的 Canvas 界面中 Script Filter 的设置如下:
11
+
12
+ - Keyword: afwf-example-memorize-cache, Argument Required
13
+ - Language: /bin/bash
14
+ - Script: python main.py 'memorize_cache {query}'
15
+ """
16
+
17
+ import random
18
+
19
+ import attrs
20
+ import afwf.api as afwf
21
+
22
+ from ..cache import cache
23
+
24
+
25
+ @attrs.define
26
+ class Handler(afwf.Handler):
27
+ @cache.memoize(tag="memorize_cache", expire=5)
28
+ def main(self, key: str) -> afwf.ScriptFilter:
29
+ sf = afwf.ScriptFilter()
30
+ value = random.randint(1, 1000)
31
+ item = afwf.Item(
32
+ title=f"value is {value}",
33
+ )
34
+ sf.items.append(item)
35
+ return sf
36
+
37
+ def parse_query(self, query: str):
38
+ return dict(
39
+ key=query,
40
+ )
41
+
42
+
43
+ handler = Handler(id="memorize_cache")
@@ -0,0 +1,49 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ [CN]
5
+
6
+ 该 Script Filter 的功能是展示当前这个 handlers 文件夹下的所有 Python 文件供用户选择,
7
+ 用户可以用上下选择文件, 也可以输入字符来过滤文件. 选中后按回车就会用默认应用打开对应的文件.
8
+
9
+ 我们准备用 Alfred filters results 功能帮我们过滤文件, 所以我们无需在 main() 中接收参数,
10
+ 免去了自己实现过滤文件的功能. 那么我们在实现 ``parse_query()`` 函数的时候直接返回空字典即可.
11
+
12
+ 在 Alfred Workflow 的 Canvas 界面中 Script Filter 的设置如下:
13
+
14
+ - Keyword: afwf-example-open-file, Argument Optional
15
+ - Language: /bin/bash
16
+ - Script: python main.py 'open_file {query}'
17
+ - Alfred filters results: checked
18
+ - 连接一个 Utilities - Conditional 的控件, 条件是 ``{var:open_file}`` is equal to ``y``.
19
+ - 连接一个 Actions - Open File 的控件, File 的参数是 ``{var:open_file_path}``.
20
+ """
21
+
22
+ import attrs
23
+ from pathlib_mate import Path
24
+ import afwf.api as afwf
25
+
26
+
27
+ @attrs.define
28
+ class Handler(afwf.Handler):
29
+ def main(self) -> afwf.ScriptFilter:
30
+ sf = afwf.ScriptFilter()
31
+ dir_here = Path.dir_here(__file__)
32
+ for p in dir_here.iterdir():
33
+ if p.ext.lower() == ".py":
34
+ item = afwf.Item(
35
+ title=p.basename,
36
+ subtitle=f"Open {p.abspath}",
37
+ autocomplete=p.basename,
38
+ match=p.basename,
39
+ arg=p.abspath,
40
+ )
41
+ item.open_file(path=p.abspath)
42
+ sf.items.append(item)
43
+ return sf
44
+
45
+ def parse_query(self, query: str):
46
+ return {}
47
+
48
+
49
+ handler = Handler(id="open_file")
@@ -0,0 +1,48 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ [CN]
5
+
6
+ 该 Script Filter 的功能是展示一些预先定义好的网站的名字和 URL. 然后选中后按回车就会在浏览器
7
+ 内打开对应网站.
8
+
9
+ 这个 Script Filter 没有输入参数. 所以 ``main()`` 函数也没有参数. 那么我们在实现
10
+ ``parse_query()`` 函数的时候直接返回空字典即可.
11
+
12
+ 在 Alfred Workflow 的 Canvas 界面中 Script Filter 的设置如下:
13
+
14
+ - Keyword: afwf-example-open-url, No Argument
15
+ - Language: /bin/bash
16
+ - Script: python main.py 'open_url {query}', 这里我们没有勾选 Alfred filters results. 因为我们不需要 Alfred 帮我们过滤结果.
17
+ - 连接一个 Utilities - Conditional 的控件, 条件是 ``{var:open_url}`` is equal to ``y``.
18
+ - 连接一个 Actions - Open Url 的控件, URL 的参数是 ``{var:open_url_arg}``.
19
+ """
20
+
21
+ import attrs
22
+ import afwf.api as afwf
23
+
24
+
25
+ @attrs.define
26
+ class Handler(afwf.Handler):
27
+ def main(self) -> afwf.ScriptFilter:
28
+ sf = afwf.ScriptFilter()
29
+ for title, url in [
30
+ ("Alfred App", "https://www.alfredapp.com/"),
31
+ ("Python", "https://www.python.org/"),
32
+ ("GitHub", "https://github.com/"),
33
+ ]:
34
+ item = afwf.Item(
35
+ title=title,
36
+ subtitle=f"open {url}",
37
+ autocomplete=title,
38
+ arg=url,
39
+ )
40
+ item.open_url(url=url)
41
+ sf.items.append(item)
42
+ return sf
43
+
44
+ def parse_query(self, query: str):
45
+ return {}
46
+
47
+
48
+ handler = Handler(id="open_url")
@@ -0,0 +1,51 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ [CN]
5
+
6
+ 该 Script Filter 的功能是展示一些预先定义好的网站的名字和 URL. 然后选中后按回车就会在浏览器
7
+ 内打开对应网站.
8
+
9
+ 这个 Script Filter 没有输入参数. 所以 ``main()`` 函数也没有参数. 那么我们在实现
10
+ ``parse_query()`` 函数的时候直接返回空字典即可, ``encode_query()`` 也直接返回空字符串.
11
+
12
+ 在 Alfred Workflow 的 Canvas 界面中 Script Filter 的设置如下:
13
+
14
+ - Keyword: afwf-example-open-url, No Argument
15
+ - Language: /bin/bash
16
+ - Script: python main.py 'open_url {query}', 这里我们没有勾选 Alfred filters results. 因为我们不需要 Alfred 帮我们过滤结果.
17
+ - 连接一个 Utilities - Conditional 的控件, 条件是 ``{var:open_url}`` is equal to ``y``.
18
+ - 连接一个 Actions - Open Url 的控件, URL 的参数是 ``{var:open_url_arg}``.
19
+ """
20
+
21
+ from afwf.handler import Handler
22
+ from afwf.script_filter import ScriptFilter
23
+ from afwf.item import Item
24
+
25
+
26
+ class OpenUrlHandler(Handler):
27
+ def parse_query(self, query: str) -> dict:
28
+ return {}
29
+
30
+ def encode_query(self, **kwargs) -> str:
31
+ return ""
32
+
33
+ def main(self) -> ScriptFilter:
34
+ sf = ScriptFilter()
35
+ for title, url in [
36
+ ("Alfred App", "https://www.alfredapp.com/"),
37
+ ("Python", "https://www.python.org/"),
38
+ ("GitHub", "https://github.com/"),
39
+ ]:
40
+ item = Item(
41
+ title=title,
42
+ subtitle=f"open {url}",
43
+ autocomplete=title,
44
+ arg=url,
45
+ )
46
+ item.open_url(url=url)
47
+ sf.items.append(item)
48
+ return sf
49
+
50
+
51
+ handler = OpenUrlHandler(id="open_url")
@@ -0,0 +1,44 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ [CN]
5
+
6
+ 该 Script Filter 的功能是展示 file.txt 文件中的内容. 仅仅是和 ``write_file.py`` 模块
7
+ 配合使用, 永远验证.
8
+ """
9
+
10
+ import attrs
11
+ import afwf.api as afwf
12
+
13
+ from ..paths import dir_project_home
14
+
15
+ path_file = dir_project_home / "file.txt"
16
+ path_file.parent.mkdir(parents=True, exist_ok=True)
17
+ if path_file.exists() is False:
18
+ path_file.write_text("hello world")
19
+
20
+
21
+ @attrs.define
22
+ class Handler(afwf.Handler):
23
+ def main(self) -> afwf.ScriptFilter:
24
+ sf = afwf.ScriptFilter()
25
+ if path_file.exists():
26
+ content = path_file.read_text()
27
+ item = afwf.Item(
28
+ title=f"content of {path_file} is",
29
+ subtitle=content,
30
+ )
31
+ else:
32
+ item = afwf.Item(
33
+ title=f"{path_file} does not exist!",
34
+ )
35
+ item.set_icon(afwf.IconFileEnum.error)
36
+
37
+ sf.items.append(item)
38
+ return sf
39
+
40
+ def parse_query(self, query: str):
41
+ return {}
42
+
43
+
44
+ handler = Handler(id="read_file")
@@ -0,0 +1,103 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ [CN]
5
+
6
+ 该 Script Filter 的功能是让用户对用作 settings 的 sqlite 写入. 可以和 ``view_settings.py``
7
+ 模块配合使用查看效果.
8
+ """
9
+
10
+ import typing as T
11
+ import sys
12
+
13
+ import attrs
14
+ import afwf.api as afwf
15
+
16
+ from ..settings import settings, SettingsKeyEnum
17
+
18
+
19
+ @attrs.define
20
+ class SetSettingValueHandler(afwf.Handler):
21
+ def main(self, key: str, value: str) -> afwf.ScriptFilter:
22
+ sf = afwf.ScriptFilter()
23
+ settings[key] = value
24
+ return sf
25
+
26
+ def parse_query(self, query: str):
27
+ key, value = query.split(" ", 1)
28
+ return dict(
29
+ key=key,
30
+ value=value,
31
+ )
32
+
33
+ def encode_query(self, key: str, value: str) -> str:
34
+ return f"{key} {value}"
35
+
36
+
37
+ set_setting_value_handler = SetSettingValueHandler(id="set_setting_value")
38
+
39
+
40
+ @attrs.define
41
+ class Handler(afwf.Handler):
42
+ def main(
43
+ self,
44
+ key: T.Optional[str] = None,
45
+ value: T.Optional[str] = None,
46
+ ) -> afwf.ScriptFilter:
47
+ sf = afwf.ScriptFilter()
48
+
49
+ if key is None:
50
+ for settings_key in SettingsKeyEnum:
51
+ item = afwf.FuzzyItem(
52
+ title=settings_key.value,
53
+ subtitle=f"set {settings_key.value} to ...",
54
+ autocomplete=settings_key.value + " ",
55
+ ).set_fuzzy_match_name(settings_key.value)
56
+ sf.items.append(item)
57
+ elif value is None:
58
+ items = list()
59
+ for settings_key in SettingsKeyEnum:
60
+ item = afwf.FuzzyItem(
61
+ title=settings_key.value,
62
+ subtitle=f"set {settings_key.value} to ...",
63
+ autocomplete=settings_key.value + " ",
64
+ ).set_fuzzy_match_name(settings_key.value)
65
+ items.append(item)
66
+ matcher = afwf.FuzzyItemMatcher.from_items(items)
67
+ sf.items.extend(matcher.match(key, threshold=0))
68
+ else:
69
+ if key in SettingsKeyEnum.__members__:
70
+ item = afwf.Item(
71
+ title=f"Set settings.{key} = {value!r}",
72
+ )
73
+ item.send_notification(
74
+ title=f"Set settings.{key} = {value!r}",
75
+ )
76
+ cmd = set_setting_value_handler.encode_run_script_command(
77
+ bin_python=sys.executable,
78
+ key=key,
79
+ value=value,
80
+ )
81
+ item.run_script(cmd)
82
+ sf.items.append(item)
83
+ else:
84
+ item = afwf.Item(
85
+ title=f"{key!r} is not a valid settings key",
86
+ )
87
+ item.set_icon(afwf.IconFileEnum.error)
88
+ sf.items.append(item)
89
+ return sf
90
+
91
+ def parse_query(self, query: str):
92
+ q = afwf.Query.from_str(query)
93
+ if q.n_trimmed_parts == 0:
94
+ return dict(key=None, value=None)
95
+ elif q.n_trimmed_parts == 1:
96
+ return dict(key=q.trimmed_parts[0], value=None)
97
+ elif q.n_trimmed_parts == 2:
98
+ return dict(key=q.trimmed_parts[0], value=q.trimmed_parts[1])
99
+ else:
100
+ raise NotImplementedError
101
+
102
+
103
+ handler = Handler(id="set_settings")
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ [CN]
5
+
6
+ 该 Script Filter 的功能是让用户对用作 settings 的 sqlite 进行读取. 可以和 ``set_settings.py``
7
+ 模块配合使用查看效果.
8
+ """
9
+
10
+ import attrs
11
+ import afwf.api as afwf
12
+
13
+ from ..settings import path_settings_sqlite, settings, SettingsKeyEnum
14
+
15
+
16
+ @attrs.define
17
+ class Handler(afwf.Handler):
18
+ def main(self) -> afwf.ScriptFilter:
19
+ sf = afwf.ScriptFilter()
20
+ for settings_key in SettingsKeyEnum:
21
+ value = settings.get(settings_key.value)
22
+ item = afwf.Item(
23
+ title=f"settings.{settings_key} = {value!r}",
24
+ subtitle=f"settings are stored at {path_settings_sqlite}",
25
+ )
26
+ sf.items.append(item)
27
+ return sf
28
+
29
+ def parse_query(self, query: str):
30
+ return {}
31
+
32
+
33
+ handler = Handler(id="view_settings")