# mycgi - A Python3 Replacement for the Deprecated `cgi` Module
Other than using different class names (`mycgi.Form` instead of `cgi.FieldStorage` and `mycgi.Field` instead of `cgi.FieldStorage`) this module should be quite backward-compatible with the `mycgi` module. Additionally, JSON-encoded PUT and POST requests are supported.
Note that this module depends on the `python-multipart` package for handling POST and PUT requests that are not JSON-encoded.
## Some Usage Examples
```
# Instead of:
#from cgi import FieldStorage
# Use:
from mycgi import Form
form = Form()
# name is a text input field:
name = form.getvalue('name') # this will be a list if the form has multiple 'name' fields
# or: name = form.getfirst('name')
# or: names = form.getlist('name')
# spreadsheet is a file input field:
fileitem = form['spreadsheet']
# The name of the uploaded file:
filename = fileitem.filename
# Get the file contents as bytes 3 different ways:
contents = fileitem.file.read()
contents = fileitem.value
contents = form.getvalue('spreadsheet')
```
## Documentation
The initializer for the `mycgi.Form` class is:
```
def __init__(self, environ=os.environ, fp=None, keep_blank_values=False):
"""
Initialize a Form instance.
Arguments (all are optional):
environ: environment dictionary
default: os.environ
fp: stream containing encoded POST and PUT data
default: None (in which case sys.stdin.buffer will be used for
POST and PUT requests)
keep_blank_values: flag indicating whether blank values in
percent-encoded forms should be treated as blank
strings.
default: False
"""
```
A `mycgi.Form` instance is a specialized dictionary whose keys are the field names and whose values are either a `mycgi.Field`
instance or a list of these instances. A `mycgi.Field` instance has the following attributes:
1. `name`: The form field name.
2. `filename`: If this field is for a file, then the file's filename, else None.
3. `value`: The form field value (or a file's contents as bytes).
4. `file`: If this field is for a file, then a stream that can be read to get the uploaded file's value, else None.
The `mycgi.Form` class supports the `getvalue`, `getlist` and `getfirst` methods that behave identically to the like-named methods of the deprecated `cgi.FieldStorage` class and which make it unnecessary to access the `mycgi.Field` instances, although doing so can be useful for processing file uploads.
### JSON-encoded PUT and POST requests
Also supported are POST and PUT requests where the data is a JSON-encoded dictionary.
### WSGI Application Usage
To use `mycgi.Form` with a WSGI application:
```
from mycgi import Form
def wsgiApp(environ, start_response):
form = Form(environ=environ, fp=environ['wsgi.input'])
...
```
## Tests To Demonstrate `mycgi` Usage
```
from mycgi import Form
import io
# Test a GET request:
form = Form(environ={'QUERY_STRING': 'x=1&x=2&y=3'})
assert repr(form) == "{'x': [Field('x', None, '1'), Field('x', None, '2')], 'y': Field('y', None, '3')}"
assert form.getvalue('x') == ['1', '2']
assert form.getlist('x') == ['1', '2']
assert form.getfirst('x') == '1'
assert [field.filename for field in form['x']] == [None, None]
assert [field.value for field in form['x']] == ['1', '2']
assert form.getvalue('y') == '3'
assert form.getlist('y') == ['3']
assert form.getfirst('y') == '3'
assert form['y'].name == 'y'
assert form['y'].filename is None
assert form['y'].value == '3'
# Test a multipart POST request:
# We have here a text input field named 'act' whose value is 'abc' and two
# file input fields named 'the_file' where a file has been selected for only the
# first occurence:
fp = io.BytesIO(b'------WebKitFormBoundarytQ0DkMXsDqxwxBlp\r\nContent-Disposition: form-data; name="act"\r\n\r\nTest\r\n------WebKitFormBoundarytQ0DkMXsDqxwxBlp\r\nContent-Disposition: form-data; name="the_file"; filename="test.txt"\r\nContent-Type: text/plain\r\n\r\nabc\r\n------WebKitFormBoundarytQ0DkMXsDqxwxBlp\r\nContent-Disposition: form-data; name="the_file"; filename=""\r\nContent-Type: application/octet-stream\r\n\r\n\r\n------WebKitFormBoundarytQ0DkMXsDqxwxBlp--\r\n')
environ = {
'CONTENT_LENGTH': '431',
'CONTENT_TYPE': 'multipart/form-data; boundary=----WebKitFormBoundarytQ0DkMXsDqxwxBlp',
}
form = Form(environ=environ, fp=fp)
assert form['act'].name == 'act'
assert form['act'].filename is None
assert form['act'].value == 'Test'
assert form['the_file'][0].name == 'the_file'
assert form['the_file'][0].filename == 'test.txt'
assert form['the_file'][0].value == b'abc'
assert form['the_file'][1].name == 'the_file'
assert form['the_file'][1].filename == ''
assert form['the_file'][1].value == b''
assert form.getvalue('the_file') == [b'abc', b'']
# Test a JSON-encoded POST request:
fp = io.BytesIO(b'{"x": [1,2], "y": 3}')
environ = {
'CONTENT_LENGTH': '20',
'CONTENT_TYPE': 'application/json',
}
form = Form(environ=environ, fp=fp)
assert form.getvalue('x') == [1, 2]
assert form.getlist('x') == [1, 2]
assert form.getfirst('x') == 1
assert [field.filename for field in form['x']] == [None, None]
assert [field.value for field in form['x']] == [1, 2]
assert [field.file for field in form['x']] == [None, None]
assert form.getvalue('y') == 3
assert form.getlist('y') == [3]
assert form.getfirst('y') == 3
assert form['y'].name == 'y'
assert form['y'].filename is None
assert form['y'].value == 3
assert form['y'].file is None
```
Raw data
{
"_id": null,
"home_page": "",
"name": "mycgi",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": "",
"keywords": "cgi,replacement",
"author": "",
"author_email": "Ronald Aaronson <ronaldaaronson@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/a5/d4/b1dc565230f63d2a3a53111ce702a8c5f7cee8a95dda06693041937b5210/mycgi-0.0.4.post0.tar.gz",
"platform": null,
"description": "# mycgi - A Python3 Replacement for the Deprecated `cgi` Module\r\n\r\nOther than using different class names (`mycgi.Form` instead of `cgi.FieldStorage` and `mycgi.Field` instead of `cgi.FieldStorage`) this module should be quite backward-compatible with the `mycgi` module. Additionally, JSON-encoded PUT and POST requests are supported.\r\n\r\nNote that this module depends on the `python-multipart` package for handling POST and PUT requests that are not JSON-encoded.\r\n\r\n## Some Usage Examples\r\n\r\n```\r\n# Instead of:\r\n#from cgi import FieldStorage\r\n# Use:\r\nfrom mycgi import Form\r\n\r\nform = Form()\r\n\r\n# name is a text input field:\r\nname = form.getvalue('name') # this will be a list if the form has multiple 'name' fields\r\n# or: name = form.getfirst('name')\r\n# or: names = form.getlist('name')\r\n\r\n# spreadsheet is a file input field:\r\nfileitem = form['spreadsheet']\r\n# The name of the uploaded file:\r\nfilename = fileitem.filename\r\n# Get the file contents as bytes 3 different ways:\r\ncontents = fileitem.file.read()\r\ncontents = fileitem.value\r\ncontents = form.getvalue('spreadsheet')\r\n```\r\n\r\n## Documentation\r\n\r\nThe initializer for the `mycgi.Form` class is:\r\n\r\n```\r\n def __init__(self, environ=os.environ, fp=None, keep_blank_values=False):\r\n \"\"\"\r\n Initialize a Form instance.\r\n\r\n Arguments (all are optional):\r\n\r\n environ: environment dictionary\r\n default: os.environ\r\n\r\n fp: stream containing encoded POST and PUT data\r\n default: None (in which case sys.stdin.buffer will be used for\r\n POST and PUT requests)\r\n\r\n keep_blank_values: flag indicating whether blank values in\r\n percent-encoded forms should be treated as blank\r\n strings.\r\n default: False\r\n \"\"\"\r\n\r\n```\r\n\r\nA `mycgi.Form` instance is a specialized dictionary whose keys are the field names and whose values are either a `mycgi.Field`\r\ninstance or a list of these instances. A `mycgi.Field` instance has the following attributes:\r\n\r\n1. `name`: The form field name.\r\n2. `filename`: If this field is for a file, then the file's filename, else None.\r\n3. `value`: The form field value (or a file's contents as bytes).\r\n4. `file`: If this field is for a file, then a stream that can be read to get the uploaded file's value, else None.\r\n\r\nThe `mycgi.Form` class supports the `getvalue`, `getlist` and `getfirst` methods that behave identically to the like-named methods of the deprecated `cgi.FieldStorage` class and which make it unnecessary to access the `mycgi.Field` instances, although doing so can be useful for processing file uploads.\r\n\r\n### JSON-encoded PUT and POST requests\r\n\r\nAlso supported are POST and PUT requests where the data is a JSON-encoded dictionary.\r\n\r\n### WSGI Application Usage\r\n\r\nTo use `mycgi.Form` with a WSGI application:\r\n\r\n```\r\nfrom mycgi import Form\r\n\r\ndef wsgiApp(environ, start_response):\r\n form = Form(environ=environ, fp=environ['wsgi.input'])\r\n ...\r\n```\r\n\r\n## Tests To Demonstrate `mycgi` Usage\r\n\r\n```\r\nfrom mycgi import Form\r\nimport io\r\n\r\n# Test a GET request:\r\nform = Form(environ={'QUERY_STRING': 'x=1&x=2&y=3'})\r\nassert repr(form) == \"{'x': [Field('x', None, '1'), Field('x', None, '2')], 'y': Field('y', None, '3')}\"\r\n\r\nassert form.getvalue('x') == ['1', '2']\r\nassert form.getlist('x') == ['1', '2']\r\nassert form.getfirst('x') == '1'\r\nassert [field.filename for field in form['x']] == [None, None]\r\nassert [field.value for field in form['x']] == ['1', '2']\r\n\r\nassert form.getvalue('y') == '3'\r\nassert form.getlist('y') == ['3']\r\nassert form.getfirst('y') == '3'\r\nassert form['y'].name == 'y'\r\nassert form['y'].filename is None\r\nassert form['y'].value == '3'\r\n\r\n# Test a multipart POST request:\r\n# We have here a text input field named 'act' whose value is 'abc' and two\r\n# file input fields named 'the_file' where a file has been selected for only the\r\n# first occurence:\r\nfp = io.BytesIO(b'------WebKitFormBoundarytQ0DkMXsDqxwxBlp\\r\\nContent-Disposition: form-data; name=\"act\"\\r\\n\\r\\nTest\\r\\n------WebKitFormBoundarytQ0DkMXsDqxwxBlp\\r\\nContent-Disposition: form-data; name=\"the_file\"; filename=\"test.txt\"\\r\\nContent-Type: text/plain\\r\\n\\r\\nabc\\r\\n------WebKitFormBoundarytQ0DkMXsDqxwxBlp\\r\\nContent-Disposition: form-data; name=\"the_file\"; filename=\"\"\\r\\nContent-Type: application/octet-stream\\r\\n\\r\\n\\r\\n------WebKitFormBoundarytQ0DkMXsDqxwxBlp--\\r\\n')\r\nenviron = {\r\n 'CONTENT_LENGTH': '431',\r\n 'CONTENT_TYPE': 'multipart/form-data; boundary=----WebKitFormBoundarytQ0DkMXsDqxwxBlp',\r\n }\r\nform = Form(environ=environ, fp=fp)\r\n\r\nassert form['act'].name == 'act'\r\nassert form['act'].filename is None\r\nassert form['act'].value == 'Test'\r\n\r\nassert form['the_file'][0].name == 'the_file'\r\nassert form['the_file'][0].filename == 'test.txt'\r\nassert form['the_file'][0].value == b'abc'\r\n\r\nassert form['the_file'][1].name == 'the_file'\r\nassert form['the_file'][1].filename == ''\r\nassert form['the_file'][1].value == b''\r\n\r\nassert form.getvalue('the_file') == [b'abc', b'']\r\n\r\n# Test a JSON-encoded POST request:\r\nfp = io.BytesIO(b'{\"x\": [1,2], \"y\": 3}')\r\nenviron = {\r\n 'CONTENT_LENGTH': '20',\r\n 'CONTENT_TYPE': 'application/json',\r\n }\r\nform = Form(environ=environ, fp=fp)\r\n\r\nassert form.getvalue('x') == [1, 2]\r\nassert form.getlist('x') == [1, 2]\r\nassert form.getfirst('x') == 1\r\nassert [field.filename for field in form['x']] == [None, None]\r\nassert [field.value for field in form['x']] == [1, 2]\r\nassert [field.file for field in form['x']] == [None, None]\r\n\r\nassert form.getvalue('y') == 3\r\nassert form.getlist('y') == [3]\r\nassert form.getfirst('y') == 3\r\nassert form['y'].name == 'y'\r\nassert form['y'].filename is None\r\nassert form['y'].value == 3\r\nassert form['y'].file is None\r\n```\r\n",
"bugtrack_url": null,
"license": "Copyright 2023, Ronald Aaronson Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.",
"summary": "A Python3 replacement for the deprecated cgi module",
"version": "0.0.4.post0",
"project_urls": {
"Changelog": "https://github.com/ronaaronson/mycgi/tags",
"Homepage": "https://github.com/ronaaronson/mycgi",
"Source": "https://github.com/ronaaronson/mycgi"
},
"split_keywords": [
"cgi",
"replacement"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "1473d98d88d623d8a4b250d5b1f20c42757ffbfb62a356f18aa4e9a6bbbe1452",
"md5": "bd9105e0485f46e81e47225a1850286b",
"sha256": "d80a0376961f42fa4a8a921ad79bc06af2da35aa6736cb477dd646ab95788e01"
},
"downloads": -1,
"filename": "mycgi-0.0.4.post0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "bd9105e0485f46e81e47225a1850286b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 6435,
"upload_time": "2023-09-15T17:43:22",
"upload_time_iso_8601": "2023-09-15T17:43:22.210855Z",
"url": "https://files.pythonhosted.org/packages/14/73/d98d88d623d8a4b250d5b1f20c42757ffbfb62a356f18aa4e9a6bbbe1452/mycgi-0.0.4.post0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "a5d4b1dc565230f63d2a3a53111ce702a8c5f7cee8a95dda06693041937b5210",
"md5": "2b6b247f71914ee165d61f58f0228084",
"sha256": "45f49b5beb599d1fa815245e4608588b0d61b29716eabaa256ede7b1bb57696a"
},
"downloads": -1,
"filename": "mycgi-0.0.4.post0.tar.gz",
"has_sig": false,
"md5_digest": "2b6b247f71914ee165d61f58f0228084",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 5330,
"upload_time": "2023-09-15T17:43:23",
"upload_time_iso_8601": "2023-09-15T17:43:23.654121Z",
"url": "https://files.pythonhosted.org/packages/a5/d4/b1dc565230f63d2a3a53111ce702a8c5f7cee8a95dda06693041937b5210/mycgi-0.0.4.post0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-09-15 17:43:23",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ronaaronson",
"github_project": "mycgi",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "mycgi"
}