asgi-cli 0.4.2__tar.gz → 0.4.4__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 (31) hide show
  1. asgi_cli-0.4.4/PKG-INFO +149 -0
  2. asgi_cli-0.4.4/pyproject.toml +55 -0
  3. asgi_cli-0.4.4/src/asgi_cli/__init__.py +1 -0
  4. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli/main.py +2 -2
  5. asgi_cli-0.4.4/src/asgi_cli/tests/__init__.py +0 -0
  6. asgi_cli-0.4.4/src/asgi_cli/tests/test_formatter.py +28 -0
  7. asgi_cli-0.4.4/src/asgi_cli/tests/test_loader.py +8 -0
  8. asgi_cli-0.4.4/src/asgi_cli/tests/test_main.py +35 -0
  9. asgi_cli-0.4.4/src/asgi_cli/tests/test_parser.py +24 -0
  10. asgi_cli-0.4.4/src/asgi_cli.egg-info/PKG-INFO +149 -0
  11. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli.egg-info/SOURCES.txt +7 -2
  12. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli.egg-info/entry_points.txt +0 -1
  13. asgi-cli-0.4.2/PKG-INFO +0 -148
  14. asgi-cli-0.4.2/setup.py +0 -54
  15. asgi-cli-0.4.2/src/asgi_cli/__init__.py +0 -1
  16. asgi-cli-0.4.2/src/asgi_cli.egg-info/PKG-INFO +0 -148
  17. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/LICENSE +0 -0
  18. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/MANIFEST.in +0 -0
  19. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/README.md +0 -0
  20. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/setup.cfg +0 -0
  21. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli/builder.py +0 -0
  22. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli/executor.py +0 -0
  23. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli/formatter.py +0 -0
  24. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli/loader.py +0 -0
  25. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli/parser.py +0 -0
  26. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli/py.typed +0 -0
  27. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli/timing.py +0 -0
  28. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli/typing.py +0 -0
  29. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli.egg-info/dependency_links.txt +0 -0
  30. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli.egg-info/top_level.txt +0 -0
  31. {asgi-cli-0.4.2 → asgi_cli-0.4.4}/src/asgi_cli.egg-info/zip-safe +0 -0
@@ -0,0 +1,149 @@
1
+ Metadata-Version: 2.4
2
+ Name: asgi-cli
3
+ Version: 0.4.4
4
+ Summary: Call ASGI Python application from command line, just like CURL
5
+ Author-email: Andriy Kornatskyy <andriy.kornatskyy@live.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/akornatskyy/asgi-cli
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Environment :: Console
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Natural Language :: English
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: Implementation :: CPython
22
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
23
+ Classifier: Topic :: Internet :: WWW/HTTP
24
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
25
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Requires-Python: >=3.10
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Dynamic: license-file
31
+
32
+ # ASGI CLI
33
+
34
+ ![tests](https://github.com/akornatskyy/asgi-cli/workflows/tests/badge.svg)
35
+ [![Coverage Status](https://coveralls.io/repos/github/akornatskyy/asgi-cli/badge.svg?branch=master)](https://coveralls.io/github/akornatskyy/asgi-cli?branch=master)
36
+ [![pypi version](https://badge.fury.io/py/asgi-cli.svg)](https://badge.fury.io/py/asgi-cli)
37
+
38
+ Call [ASGI](https://asgi.readthedocs.io/en/latest/index.html)
39
+ Python application from command line, just like CURL.
40
+
41
+ If you’re using this tool, **★Star** this repository to show your interest, please!
42
+
43
+ ## Install
44
+
45
+ ```sh
46
+ pip install -U asgi-cli
47
+ ```
48
+
49
+ ## Usage
50
+
51
+ ```sh
52
+ asgi-cli --help
53
+ ```
54
+
55
+ ```text
56
+ usage: asgi-cli [-h] [-V] [-X COMMAND] [-H HEADER] [-d DATA | -F MULTIPART]
57
+ [-I] [-b] [-p] [-n NUMBER] [-v]
58
+ app [url]
59
+
60
+ positional arguments:
61
+ app an application module
62
+ url a uniform resource locator or path (default /)
63
+
64
+ optional arguments:
65
+ -h, --help show this help message and exit
66
+ -V, --version show program's version number and exit
67
+ -X COMMAND, --request COMMAND
68
+ specify request command to use, e.g. POST (default
69
+ GET)
70
+ -H HEADER, --header HEADER
71
+ pass custom header line, e.g. -H='Accept:
72
+ application/json'
73
+ -d DATA, --data DATA request body data, e.g. '{"msg":"hello"}', 'msg=hello'
74
+ -F MULTIPART, --form MULTIPART
75
+ specify HTTP multipart POST data, e.g. name=value or
76
+ name=@file
77
+ -I, --head show status and headers only
78
+ -b, --benchmark issue a number of requests through repeated iterations
79
+ (reports throughtput and average call time)
80
+ -p, --profile prints out a report of top 10 functions ordered by
81
+ internal time, saves to 'stats.cprof' file
82
+ -n NUMBER a number of requests to issue (default 100K)
83
+ -v, --verbose make the operation more talkative
84
+ ```
85
+
86
+ ## Examples
87
+
88
+ _example.py_:
89
+
90
+ ```python
91
+ START = {
92
+ "type": "http.response.start",
93
+ "status": 200,
94
+ "headers": [
95
+ (b"content-length", b"13"),
96
+ (b"content-type", b"text/html; charset=utf-8"),
97
+ ],
98
+ }
99
+
100
+ BODY1 = {"type": "http.response.body", "body": b"Hello"}
101
+ BODY2 = {"type": "http.response.body", "body": b", world!"}
102
+
103
+
104
+ async def app(scope, receive, send) -> None:
105
+ await send(START)
106
+ await send(BODY1)
107
+ await send(BODY2)
108
+ ```
109
+
110
+ Then run the examples:
111
+
112
+ `asgi-cli example:app` prints response body:
113
+
114
+ ```text
115
+ Hello, world!
116
+ ```
117
+
118
+ `asgi-cli -v example:app` pretty prints scope and sent messages:
119
+
120
+ ```text
121
+ {'scope': {'asgi': {'spec_version': '2.1', 'version': '3.0'},
122
+ 'client': ('127.0.0.1', 49327),
123
+ 'headers': [(b'accept', b'*/*'),
124
+ (b'user-agent', b'asgi-cli/0.0.1'),
125
+ (b'host', b'127.0.0.1:8000')],
126
+ 'http_version': '1.1',
127
+ 'method': 'GET',
128
+ 'path': '/',
129
+ 'query_string': b'',
130
+ 'raw_path': b'/',
131
+ 'root_path': '',
132
+ 'scheme': 'http',
133
+ 'server': ('127.0.0.1', 8000),
134
+ 'type': 'http'}}
135
+ {'message': {'headers': [(b'content-length', b'13'),
136
+ (b'content-type', b'text/html; charset=utf-8')],
137
+ 'status': 200,
138
+ 'type': 'http.response.start'}}
139
+ {'message': {'body': b'Hello', 'type': 'http.response.body'}}
140
+ {'message': {'body': b', world!', 'type': 'http.response.body'}}
141
+ ```
142
+
143
+ `asgi-cli -b example:app` shows execution stats (runs in 3 iterations, for each iteration displays requests per second and an average call time):
144
+
145
+ ```text
146
+ #1 => 477.74K, 2.09μs
147
+ #2 => 438.12K, 2.28μs
148
+ #3 => 446.90K, 2.24μs
149
+ ```
@@ -0,0 +1,55 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "asgi-cli"
7
+ dynamic = ["version"]
8
+ description = "Call ASGI Python application from command line, just like CURL"
9
+ readme = {file = "README.md", content-type = "text/markdown"}
10
+ requires-python = ">=3.10"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "Andriy Kornatskyy", email = "andriy.kornatskyy@live.com"}
14
+ ]
15
+ keywords = []
16
+ classifiers = [
17
+ "Development Status :: 5 - Production/Stable",
18
+ "Environment :: Console",
19
+ "Environment :: Web Environment",
20
+ "Intended Audience :: Developers",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Natural Language :: English",
23
+ "Operating System :: OS Independent",
24
+ "Programming Language :: Python",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Programming Language :: Python :: 3.13",
29
+ "Programming Language :: Python :: 3.14",
30
+ "Programming Language :: Python :: Implementation :: CPython",
31
+ "Programming Language :: Python :: Implementation :: PyPy",
32
+ "Topic :: Internet :: WWW/HTTP",
33
+ "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
34
+ "Topic :: Software Development :: Libraries :: Application Frameworks",
35
+ "Topic :: Software Development :: Libraries :: Python Modules",
36
+ ]
37
+ dependencies = []
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/akornatskyy/asgi-cli"
41
+
42
+ [project.scripts]
43
+ asgi-cli = "asgi_cli.main:main"
44
+
45
+ [tool.setuptools]
46
+ zip-safe = true
47
+
48
+ [tool.setuptools.dynamic]
49
+ version = {attr = "asgi_cli.__version__"}
50
+
51
+ [tool.setuptools.packages.find]
52
+ where = ["src"]
53
+
54
+ [tool.setuptools.package-data]
55
+ asgi_cli = ["py.typed"]
@@ -0,0 +1 @@
1
+ __version__ = "0.4.4"
@@ -1,8 +1,8 @@
1
1
  import asyncio
2
2
  import os
3
3
  import sys
4
- import typing
5
4
  import traceback
5
+ import typing
6
6
 
7
7
  from asgi_cli import builder, formatter, loader, parser
8
8
  from asgi_cli.executor import Executor
@@ -42,7 +42,7 @@ def main(args: typing.Optional[typing.List[str]] = None) -> int:
42
42
  if args is None: # pragma: nocover
43
43
  args = sys.argv[1:]
44
44
  sys.path.extend([os.path.abspath(".")])
45
- return asyncio.get_event_loop().run_until_complete(go(args))
45
+ return asyncio.run(go(args))
46
46
 
47
47
 
48
48
  if __name__ == "__main__": # pragma: nocover
File without changes
@@ -0,0 +1,28 @@
1
+ import unittest
2
+
3
+ from asgi_cli.formatter import format_number
4
+
5
+
6
+ class FormatterTestCase(unittest.TestCase):
7
+ def test_format_number(self) -> None:
8
+ for number, expected in [
9
+ (12345678901, "12,345.68M"),
10
+ (1234567890, "1,234.57M"),
11
+ (123456789.1, "123.46M"),
12
+ (12345678.9, "12.35M"),
13
+ (1234567.89, "1.23M"),
14
+ (123456.789, "123.46K"),
15
+ (12345.6789, "12.35K"),
16
+ (1234.56789, "1.23K"),
17
+ (123.456789, "123.46"),
18
+ (12.3456789, "12.35"),
19
+ (1.23456789, "1.23"),
20
+ (0.12345678, "123.46m"),
21
+ (0.01234567, "12.35m"),
22
+ (0.00123456, "1.23m"),
23
+ (0.00012345, "123.45u"),
24
+ (0.00001234, "12.34u"),
25
+ (0.00000123, "1.23u"),
26
+ (-1234.56789, "-1,234.57"),
27
+ ]:
28
+ self.assertEqual(format_number(number), expected)
@@ -0,0 +1,8 @@
1
+ import unittest
2
+
3
+ from asgi_cli.loader import from_string
4
+
5
+
6
+ class LoaderTestCase(unittest.TestCase):
7
+ def test_from_string(self) -> None:
8
+ self.assertRaises(ValueError, lambda: from_string("unknown"))
@@ -0,0 +1,35 @@
1
+ import unittest
2
+
3
+ from asgi_cli.main import main
4
+
5
+
6
+ class MainTestCase(unittest.TestCase):
7
+ def test_main(self) -> None:
8
+ main(["unknown:app"])
9
+ main(["example:app"])
10
+ main(["-v", "example:app"])
11
+ main(["-d", "", "example:app"])
12
+ main(["-d", "{}", "example:app"])
13
+ main(["example:app", "/receiver"])
14
+ main(["-F", "x=123", "example:app", "/receiver"])
15
+ main(["-F", "fn=@README.md", "example:app", "/receiver"])
16
+ main(["-X", "POST", "-v", "example:app"])
17
+ main(["-X", "POST", "-d", "msg=hello", "example:app"])
18
+ main(["-I", "example:app"])
19
+ main(["-b", "-n", "1K", "example:app"])
20
+ main(["-p", "-n", "1K", "example:app"])
21
+ main(["-H", "Accept: application/json", "example:app"])
22
+ main(["-v", "example:app", "http://example.com/uk/welcome"])
23
+ main(
24
+ [
25
+ "-v",
26
+ "-X",
27
+ "PATCH",
28
+ "-H",
29
+ "Content-Type: application/json",
30
+ "-d",
31
+ "[]",
32
+ "example:app",
33
+ "welcome",
34
+ ]
35
+ )
@@ -0,0 +1,24 @@
1
+ import unittest
2
+
3
+ from asgi_cli.parser import parse_number
4
+
5
+
6
+ class ParserTestCase(unittest.TestCase):
7
+ def test_parse_number(self) -> None:
8
+ for s, expected in [
9
+ ("12345", 12345),
10
+ ("12345678901", 12345678901),
11
+ ("1K", 1e3),
12
+ ("25K", 25e3),
13
+ ("1M", 1e6),
14
+ ("10M", 1e7),
15
+ ]:
16
+ self.assertEqual(parse_number(s), expected)
17
+
18
+ for s in [
19
+ "1KK",
20
+ "1G",
21
+ "K",
22
+ "M",
23
+ ]:
24
+ self.assertRaises(ValueError, lambda s: parse_number(s), s)
@@ -0,0 +1,149 @@
1
+ Metadata-Version: 2.4
2
+ Name: asgi-cli
3
+ Version: 0.4.4
4
+ Summary: Call ASGI Python application from command line, just like CURL
5
+ Author-email: Andriy Kornatskyy <andriy.kornatskyy@live.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/akornatskyy/asgi-cli
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Environment :: Console
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Natural Language :: English
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: Implementation :: CPython
22
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
23
+ Classifier: Topic :: Internet :: WWW/HTTP
24
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
25
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Requires-Python: >=3.10
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Dynamic: license-file
31
+
32
+ # ASGI CLI
33
+
34
+ ![tests](https://github.com/akornatskyy/asgi-cli/workflows/tests/badge.svg)
35
+ [![Coverage Status](https://coveralls.io/repos/github/akornatskyy/asgi-cli/badge.svg?branch=master)](https://coveralls.io/github/akornatskyy/asgi-cli?branch=master)
36
+ [![pypi version](https://badge.fury.io/py/asgi-cli.svg)](https://badge.fury.io/py/asgi-cli)
37
+
38
+ Call [ASGI](https://asgi.readthedocs.io/en/latest/index.html)
39
+ Python application from command line, just like CURL.
40
+
41
+ If you’re using this tool, **★Star** this repository to show your interest, please!
42
+
43
+ ## Install
44
+
45
+ ```sh
46
+ pip install -U asgi-cli
47
+ ```
48
+
49
+ ## Usage
50
+
51
+ ```sh
52
+ asgi-cli --help
53
+ ```
54
+
55
+ ```text
56
+ usage: asgi-cli [-h] [-V] [-X COMMAND] [-H HEADER] [-d DATA | -F MULTIPART]
57
+ [-I] [-b] [-p] [-n NUMBER] [-v]
58
+ app [url]
59
+
60
+ positional arguments:
61
+ app an application module
62
+ url a uniform resource locator or path (default /)
63
+
64
+ optional arguments:
65
+ -h, --help show this help message and exit
66
+ -V, --version show program's version number and exit
67
+ -X COMMAND, --request COMMAND
68
+ specify request command to use, e.g. POST (default
69
+ GET)
70
+ -H HEADER, --header HEADER
71
+ pass custom header line, e.g. -H='Accept:
72
+ application/json'
73
+ -d DATA, --data DATA request body data, e.g. '{"msg":"hello"}', 'msg=hello'
74
+ -F MULTIPART, --form MULTIPART
75
+ specify HTTP multipart POST data, e.g. name=value or
76
+ name=@file
77
+ -I, --head show status and headers only
78
+ -b, --benchmark issue a number of requests through repeated iterations
79
+ (reports throughtput and average call time)
80
+ -p, --profile prints out a report of top 10 functions ordered by
81
+ internal time, saves to 'stats.cprof' file
82
+ -n NUMBER a number of requests to issue (default 100K)
83
+ -v, --verbose make the operation more talkative
84
+ ```
85
+
86
+ ## Examples
87
+
88
+ _example.py_:
89
+
90
+ ```python
91
+ START = {
92
+ "type": "http.response.start",
93
+ "status": 200,
94
+ "headers": [
95
+ (b"content-length", b"13"),
96
+ (b"content-type", b"text/html; charset=utf-8"),
97
+ ],
98
+ }
99
+
100
+ BODY1 = {"type": "http.response.body", "body": b"Hello"}
101
+ BODY2 = {"type": "http.response.body", "body": b", world!"}
102
+
103
+
104
+ async def app(scope, receive, send) -> None:
105
+ await send(START)
106
+ await send(BODY1)
107
+ await send(BODY2)
108
+ ```
109
+
110
+ Then run the examples:
111
+
112
+ `asgi-cli example:app` prints response body:
113
+
114
+ ```text
115
+ Hello, world!
116
+ ```
117
+
118
+ `asgi-cli -v example:app` pretty prints scope and sent messages:
119
+
120
+ ```text
121
+ {'scope': {'asgi': {'spec_version': '2.1', 'version': '3.0'},
122
+ 'client': ('127.0.0.1', 49327),
123
+ 'headers': [(b'accept', b'*/*'),
124
+ (b'user-agent', b'asgi-cli/0.0.1'),
125
+ (b'host', b'127.0.0.1:8000')],
126
+ 'http_version': '1.1',
127
+ 'method': 'GET',
128
+ 'path': '/',
129
+ 'query_string': b'',
130
+ 'raw_path': b'/',
131
+ 'root_path': '',
132
+ 'scheme': 'http',
133
+ 'server': ('127.0.0.1', 8000),
134
+ 'type': 'http'}}
135
+ {'message': {'headers': [(b'content-length', b'13'),
136
+ (b'content-type', b'text/html; charset=utf-8')],
137
+ 'status': 200,
138
+ 'type': 'http.response.start'}}
139
+ {'message': {'body': b'Hello', 'type': 'http.response.body'}}
140
+ {'message': {'body': b', world!', 'type': 'http.response.body'}}
141
+ ```
142
+
143
+ `asgi-cli -b example:app` shows execution stats (runs in 3 iterations, for each iteration displays requests per second and an average call time):
144
+
145
+ ```text
146
+ #1 => 477.74K, 2.09μs
147
+ #2 => 438.12K, 2.28μs
148
+ #3 => 446.90K, 2.24μs
149
+ ```
@@ -1,7 +1,7 @@
1
1
  LICENSE
2
2
  MANIFEST.in
3
3
  README.md
4
- setup.py
4
+ pyproject.toml
5
5
  src/asgi_cli/__init__.py
6
6
  src/asgi_cli/builder.py
7
7
  src/asgi_cli/executor.py
@@ -17,4 +17,9 @@ src/asgi_cli.egg-info/SOURCES.txt
17
17
  src/asgi_cli.egg-info/dependency_links.txt
18
18
  src/asgi_cli.egg-info/entry_points.txt
19
19
  src/asgi_cli.egg-info/top_level.txt
20
- src/asgi_cli.egg-info/zip-safe
20
+ src/asgi_cli.egg-info/zip-safe
21
+ src/asgi_cli/tests/__init__.py
22
+ src/asgi_cli/tests/test_formatter.py
23
+ src/asgi_cli/tests/test_loader.py
24
+ src/asgi_cli/tests/test_main.py
25
+ src/asgi_cli/tests/test_parser.py
@@ -1,3 +1,2 @@
1
1
  [console_scripts]
2
2
  asgi-cli = asgi_cli.main:main
3
-
asgi-cli-0.4.2/PKG-INFO DELETED
@@ -1,148 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: asgi-cli
3
- Version: 0.4.2
4
- Summary: Call ASGI Python application from command line, just like CURL
5
- Home-page: https://github.com/akornatskyy/asgi-cli
6
- Author: Andriy Kornatskyy
7
- Author-email: andriy.kornatskyy@live.com
8
- License: MIT
9
- Description: # ASGI CLI
10
-
11
- ![tests](https://github.com/akornatskyy/asgi-cli/workflows/tests/badge.svg)
12
- [![Coverage Status](https://coveralls.io/repos/github/akornatskyy/asgi-cli/badge.svg?branch=master)](https://coveralls.io/github/akornatskyy/asgi-cli?branch=master)
13
- [![pypi version](https://badge.fury.io/py/asgi-cli.svg)](https://badge.fury.io/py/asgi-cli)
14
-
15
- Call [ASGI](https://asgi.readthedocs.io/en/latest/index.html)
16
- Python application from command line, just like CURL.
17
-
18
- If you’re using this tool, **★Star** this repository to show your interest, please!
19
-
20
- ## Install
21
-
22
- ```sh
23
- pip install -U asgi-cli
24
- ```
25
-
26
- ## Usage
27
-
28
- ```sh
29
- asgi-cli --help
30
- ```
31
-
32
- ```text
33
- usage: asgi-cli [-h] [-V] [-X COMMAND] [-H HEADER] [-d DATA | -F MULTIPART]
34
- [-I] [-b] [-p] [-n NUMBER] [-v]
35
- app [url]
36
-
37
- positional arguments:
38
- app an application module
39
- url a uniform resource locator or path (default /)
40
-
41
- optional arguments:
42
- -h, --help show this help message and exit
43
- -V, --version show program's version number and exit
44
- -X COMMAND, --request COMMAND
45
- specify request command to use, e.g. POST (default
46
- GET)
47
- -H HEADER, --header HEADER
48
- pass custom header line, e.g. -H='Accept:
49
- application/json'
50
- -d DATA, --data DATA request body data, e.g. '{"msg":"hello"}', 'msg=hello'
51
- -F MULTIPART, --form MULTIPART
52
- specify HTTP multipart POST data, e.g. name=value or
53
- name=@file
54
- -I, --head show status and headers only
55
- -b, --benchmark issue a number of requests through repeated iterations
56
- (reports throughtput and average call time)
57
- -p, --profile prints out a report of top 10 functions ordered by
58
- internal time, saves to 'stats.cprof' file
59
- -n NUMBER a number of requests to issue (default 100K)
60
- -v, --verbose make the operation more talkative
61
- ```
62
-
63
- ## Examples
64
-
65
- _example.py_:
66
-
67
- ```python
68
- START = {
69
- "type": "http.response.start",
70
- "status": 200,
71
- "headers": [
72
- (b"content-length", b"13"),
73
- (b"content-type", b"text/html; charset=utf-8"),
74
- ],
75
- }
76
-
77
- BODY1 = {"type": "http.response.body", "body": b"Hello"}
78
- BODY2 = {"type": "http.response.body", "body": b", world!"}
79
-
80
-
81
- async def app(scope, receive, send) -> None:
82
- await send(START)
83
- await send(BODY1)
84
- await send(BODY2)
85
- ```
86
-
87
- Then run the examples:
88
-
89
- `asgi-cli example:app` prints response body:
90
-
91
- ```text
92
- Hello, world!
93
- ```
94
-
95
- `asgi-cli -v example:app` pretty prints scope and sent messages:
96
-
97
- ```text
98
- {'scope': {'asgi': {'spec_version': '2.1', 'version': '3.0'},
99
- 'client': ('127.0.0.1', 49327),
100
- 'headers': [(b'accept', b'*/*'),
101
- (b'user-agent', b'asgi-cli/0.0.1'),
102
- (b'host', b'127.0.0.1:8000')],
103
- 'http_version': '1.1',
104
- 'method': 'GET',
105
- 'path': '/',
106
- 'query_string': b'',
107
- 'raw_path': b'/',
108
- 'root_path': '',
109
- 'scheme': 'http',
110
- 'server': ('127.0.0.1', 8000),
111
- 'type': 'http'}}
112
- {'message': {'headers': [(b'content-length', b'13'),
113
- (b'content-type', b'text/html; charset=utf-8')],
114
- 'status': 200,
115
- 'type': 'http.response.start'}}
116
- {'message': {'body': b'Hello', 'type': 'http.response.body'}}
117
- {'message': {'body': b', world!', 'type': 'http.response.body'}}
118
- ```
119
-
120
- `asgi-cli -b example:app` shows execution stats (runs in 3 iterations, for each iteration displays requests per second and an average call time):
121
-
122
- ```text
123
- #1 => 477.74K, 2.09μs
124
- #2 => 438.12K, 2.28μs
125
- #3 => 446.90K, 2.24μs
126
- ```
127
-
128
- Platform: any
129
- Classifier: Development Status :: 5 - Production/Stable
130
- Classifier: Environment :: Console
131
- Classifier: Environment :: Web Environment
132
- Classifier: Intended Audience :: Developers
133
- Classifier: License :: OSI Approved :: MIT License
134
- Classifier: Natural Language :: English
135
- Classifier: Operating System :: OS Independent
136
- Classifier: Programming Language :: Python
137
- Classifier: Programming Language :: Python :: 3.6
138
- Classifier: Programming Language :: Python :: 3.7
139
- Classifier: Programming Language :: Python :: 3.8
140
- Classifier: Programming Language :: Python :: 3.9
141
- Classifier: Programming Language :: Python :: Implementation :: CPython
142
- Classifier: Programming Language :: Python :: Implementation :: PyPy
143
- Classifier: Topic :: Internet :: WWW/HTTP
144
- Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
145
- Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
146
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
147
- Requires-Python: >=3.6
148
- Description-Content-Type: text/markdown
asgi-cli-0.4.2/setup.py DELETED
@@ -1,54 +0,0 @@
1
- import re
2
-
3
- from setuptools import setup
4
-
5
- README = open("README.md").read()
6
- VERSION = (
7
- re.search(
8
- r"__version__ = \"(.+)\"", open("src/asgi_cli/__init__.py").read()
9
- )
10
- .group(1)
11
- .strip()
12
- )
13
-
14
- setup(
15
- name="asgi-cli",
16
- version=VERSION,
17
- python_requires=">=3.6",
18
- description="Call ASGI Python application from command line,"
19
- " just like CURL",
20
- long_description=README,
21
- long_description_content_type="text/markdown",
22
- url="https://github.com/akornatskyy/asgi-cli",
23
- author="Andriy Kornatskyy",
24
- author_email="andriy.kornatskyy@live.com",
25
- license="MIT",
26
- classifiers=[
27
- "Development Status :: 5 - Production/Stable",
28
- "Environment :: Console",
29
- "Environment :: Web Environment",
30
- "Intended Audience :: Developers",
31
- "License :: OSI Approved :: MIT License",
32
- "Natural Language :: English",
33
- "Operating System :: OS Independent",
34
- "Programming Language :: Python",
35
- "Programming Language :: Python :: 3.6",
36
- "Programming Language :: Python :: 3.7",
37
- "Programming Language :: Python :: 3.8",
38
- "Programming Language :: Python :: 3.9",
39
- "Programming Language :: Python :: Implementation :: CPython",
40
- "Programming Language :: Python :: Implementation :: PyPy",
41
- "Topic :: Internet :: WWW/HTTP",
42
- "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
43
- "Topic :: Software Development :: Libraries :: Application Frameworks",
44
- "Topic :: Software Development :: Libraries :: Python Modules",
45
- ],
46
- keywords="",
47
- packages=["asgi_cli"],
48
- package_data={"asgi_cli": ["py.typed"]},
49
- package_dir={"": "src"},
50
- zip_safe=True,
51
- install_requires=[],
52
- entry_points={"console_scripts": ["asgi-cli=asgi_cli.main:main"]},
53
- platforms="any",
54
- )
@@ -1 +0,0 @@
1
- __version__ = "0.4.2"
@@ -1,148 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: asgi-cli
3
- Version: 0.4.2
4
- Summary: Call ASGI Python application from command line, just like CURL
5
- Home-page: https://github.com/akornatskyy/asgi-cli
6
- Author: Andriy Kornatskyy
7
- Author-email: andriy.kornatskyy@live.com
8
- License: MIT
9
- Description: # ASGI CLI
10
-
11
- ![tests](https://github.com/akornatskyy/asgi-cli/workflows/tests/badge.svg)
12
- [![Coverage Status](https://coveralls.io/repos/github/akornatskyy/asgi-cli/badge.svg?branch=master)](https://coveralls.io/github/akornatskyy/asgi-cli?branch=master)
13
- [![pypi version](https://badge.fury.io/py/asgi-cli.svg)](https://badge.fury.io/py/asgi-cli)
14
-
15
- Call [ASGI](https://asgi.readthedocs.io/en/latest/index.html)
16
- Python application from command line, just like CURL.
17
-
18
- If you’re using this tool, **★Star** this repository to show your interest, please!
19
-
20
- ## Install
21
-
22
- ```sh
23
- pip install -U asgi-cli
24
- ```
25
-
26
- ## Usage
27
-
28
- ```sh
29
- asgi-cli --help
30
- ```
31
-
32
- ```text
33
- usage: asgi-cli [-h] [-V] [-X COMMAND] [-H HEADER] [-d DATA | -F MULTIPART]
34
- [-I] [-b] [-p] [-n NUMBER] [-v]
35
- app [url]
36
-
37
- positional arguments:
38
- app an application module
39
- url a uniform resource locator or path (default /)
40
-
41
- optional arguments:
42
- -h, --help show this help message and exit
43
- -V, --version show program's version number and exit
44
- -X COMMAND, --request COMMAND
45
- specify request command to use, e.g. POST (default
46
- GET)
47
- -H HEADER, --header HEADER
48
- pass custom header line, e.g. -H='Accept:
49
- application/json'
50
- -d DATA, --data DATA request body data, e.g. '{"msg":"hello"}', 'msg=hello'
51
- -F MULTIPART, --form MULTIPART
52
- specify HTTP multipart POST data, e.g. name=value or
53
- name=@file
54
- -I, --head show status and headers only
55
- -b, --benchmark issue a number of requests through repeated iterations
56
- (reports throughtput and average call time)
57
- -p, --profile prints out a report of top 10 functions ordered by
58
- internal time, saves to 'stats.cprof' file
59
- -n NUMBER a number of requests to issue (default 100K)
60
- -v, --verbose make the operation more talkative
61
- ```
62
-
63
- ## Examples
64
-
65
- _example.py_:
66
-
67
- ```python
68
- START = {
69
- "type": "http.response.start",
70
- "status": 200,
71
- "headers": [
72
- (b"content-length", b"13"),
73
- (b"content-type", b"text/html; charset=utf-8"),
74
- ],
75
- }
76
-
77
- BODY1 = {"type": "http.response.body", "body": b"Hello"}
78
- BODY2 = {"type": "http.response.body", "body": b", world!"}
79
-
80
-
81
- async def app(scope, receive, send) -> None:
82
- await send(START)
83
- await send(BODY1)
84
- await send(BODY2)
85
- ```
86
-
87
- Then run the examples:
88
-
89
- `asgi-cli example:app` prints response body:
90
-
91
- ```text
92
- Hello, world!
93
- ```
94
-
95
- `asgi-cli -v example:app` pretty prints scope and sent messages:
96
-
97
- ```text
98
- {'scope': {'asgi': {'spec_version': '2.1', 'version': '3.0'},
99
- 'client': ('127.0.0.1', 49327),
100
- 'headers': [(b'accept', b'*/*'),
101
- (b'user-agent', b'asgi-cli/0.0.1'),
102
- (b'host', b'127.0.0.1:8000')],
103
- 'http_version': '1.1',
104
- 'method': 'GET',
105
- 'path': '/',
106
- 'query_string': b'',
107
- 'raw_path': b'/',
108
- 'root_path': '',
109
- 'scheme': 'http',
110
- 'server': ('127.0.0.1', 8000),
111
- 'type': 'http'}}
112
- {'message': {'headers': [(b'content-length', b'13'),
113
- (b'content-type', b'text/html; charset=utf-8')],
114
- 'status': 200,
115
- 'type': 'http.response.start'}}
116
- {'message': {'body': b'Hello', 'type': 'http.response.body'}}
117
- {'message': {'body': b', world!', 'type': 'http.response.body'}}
118
- ```
119
-
120
- `asgi-cli -b example:app` shows execution stats (runs in 3 iterations, for each iteration displays requests per second and an average call time):
121
-
122
- ```text
123
- #1 => 477.74K, 2.09μs
124
- #2 => 438.12K, 2.28μs
125
- #3 => 446.90K, 2.24μs
126
- ```
127
-
128
- Platform: any
129
- Classifier: Development Status :: 5 - Production/Stable
130
- Classifier: Environment :: Console
131
- Classifier: Environment :: Web Environment
132
- Classifier: Intended Audience :: Developers
133
- Classifier: License :: OSI Approved :: MIT License
134
- Classifier: Natural Language :: English
135
- Classifier: Operating System :: OS Independent
136
- Classifier: Programming Language :: Python
137
- Classifier: Programming Language :: Python :: 3.6
138
- Classifier: Programming Language :: Python :: 3.7
139
- Classifier: Programming Language :: Python :: 3.8
140
- Classifier: Programming Language :: Python :: 3.9
141
- Classifier: Programming Language :: Python :: Implementation :: CPython
142
- Classifier: Programming Language :: Python :: Implementation :: PyPy
143
- Classifier: Topic :: Internet :: WWW/HTTP
144
- Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
145
- Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
146
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
147
- Requires-Python: >=3.6
148
- Description-Content-Type: text/markdown
File without changes
File without changes
File without changes
File without changes
File without changes