Last active
August 30, 2024 08:46
-
-
Save SpotlightKid/eca9b00239104e8c599b86635f62ab73 to your computer and use it in GitHub Desktop.
Making a POST request with url or form-encoded params with MicroPython
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ micropython uget.py key1=value1 key2=value2 key2=value3 | |
{'url': 'http://httpbin.org/get?key2=value3&key1=value1', 'headers': {'Host': 'httpbin.org', 'Connection': 'close'}, 'args': {'key2': 'value3', 'key1': 'value1'}, 'origin': 'XXX.XXX.XXX.XXX'} | |
$ micropython upost.py foo=bar spamm=42 | |
{'files': {}, 'headers': {'Host': 'httpbin.org', 'Content-Length': '16', 'Content-Type': 'application/x-www-form-urlencoded', 'Connection': 'close'}, 'args': {}, 'form': {'spamm': '42', 'foo': 'bar'}, 'origin': 'XXX.XXX.XXX.XXX', 'data': '', 'json': None, 'url': 'http://httpbin.org/post'} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import urequests | |
def get(url, params=None, **kw): | |
if params: | |
from urlencode import urlencode | |
url = url.rstrip('?') + '?' + urlencode(params, doseq=True) | |
return urequests.get(url, **kw) | |
if __name__ == '__main__': | |
import sys | |
url = 'http://httpbin.org/get' | |
params = [tuple(arg.split('=')) for arg in sys.argv[1:]] | |
print(get('http://httpbin.org/get', params).json()) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import urequests | |
def post(url, data=None, json=None, headers=None): | |
if isinstance(data, dict): | |
from urlencode import urlencode | |
data = urlencode(data) | |
headers = {} if headers is None else headers | |
headers['Content-Type'] = 'application/x-www-form-urlencoded' | |
return urequests.post(url, data=data, json=json, headers=headers) | |
if __name__ == '__main__': | |
import sys | |
url = 'http://httpbin.org/post' | |
data = dict((arg.split('=') for arg in sys.argv[1:])) | |
print(post(url, data=data).json()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# | |
# Extracted from: https://github.com/micropython/micropython-lib/blob/master/urllib.parse/urllib/parse.py | |
# | |
import collections | |
# XXX: Consider replacing with functools.lru_cache | |
_safe_quoters = {} | |
_ALWAYS_SAFE = frozenset(b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' | |
b'abcdefghijklmnopqrstuvwxyz' | |
b'0123456789' | |
b'_.-') | |
_ALWAYS_SAFE_BYTES = bytes(_ALWAYS_SAFE) | |
class Quoter(collections.defaultdict): | |
"""A mapping from bytes (in range(0,256)) to strings. | |
String values are percent-encoded byte values, unless the key < 128, and | |
in the "safe" set (either the specified safe set, or default set). | |
""" | |
# Keeps a cache internally, using defaultdict, for efficiency (lookups | |
# of cached keys don't call Python code at all). | |
def __init__(self, safe): | |
"""safe: bytes object.""" | |
self.safe = _ALWAYS_SAFE.union(safe) | |
def __repr__(self): | |
# Without this, will just display as a defaultdict | |
return "<Quoter %r>" % dict(self) | |
def __missing__(self, b): | |
# Handle a cache miss. Store quoted string in cache and return. | |
res = chr(b) if b in self.safe else '%{:02X}'.format(b) | |
self[b] = res | |
return res | |
def clear_cache(): | |
"""Clear the quoters cache.""" | |
_safe_quoters.clear() | |
def quote(string, safe='/', encoding=None, errors=None): | |
"""quote('abc def') -> 'abc%20def' | |
Each part of a URL, e.g. the path info, the query, etc., has a | |
different set of reserved characters that must be quoted. | |
RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax lists | |
the following reserved characters. | |
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | | |
"$" | "," | |
Each of these characters is reserved in some component of a URL, | |
but not necessarily in all of them. | |
By default, the quote function is intended for quoting the path | |
section of a URL. Thus, it will not encode '/'. This character | |
is reserved, but in typical usage the quote function is being | |
called on a path where the existing slash characters are used as | |
reserved characters. | |
string and safe may be either str or bytes objects. encoding must | |
not be specified if string is a str. | |
The optional encoding and errors parameters specify how to deal with | |
non-ASCII characters, as accepted by the str.encode method. | |
By default, encoding='utf-8' (characters are encoded with UTF-8), and | |
errors='strict' (unsupported characters raise a UnicodeEncodeError). | |
""" | |
if isinstance(string, str): | |
if not string: | |
return string | |
if encoding is None: | |
encoding = 'utf-8' | |
if errors is None: | |
errors = 'strict' | |
string = string.encode(encoding, errors) | |
else: | |
if encoding is not None: | |
raise TypeError("quote() doesn't support 'encoding' for bytes") | |
if errors is not None: | |
raise TypeError("quote() doesn't support 'errors' for bytes") | |
return quote_from_bytes(string, safe) | |
def quote_plus(string, safe='', encoding=None, errors=None): | |
"""Like quote(), but also replace ' ' with '+', as required for quoting | |
HTML form values. Plus signs in the original string are escaped unless | |
they are included in safe. It also does not have safe default to '/'. | |
""" | |
# Check if ' ' in string, where string may either be a str or bytes. If | |
# there are no spaces, the regular quote will produce the right answer. | |
if ((isinstance(string, str) and ' ' not in string) or | |
(isinstance(string, bytes) and b' ' not in string)): | |
return quote(string, safe, encoding, errors) | |
if isinstance(safe, str): | |
space = ' ' | |
else: | |
space = b' ' | |
string = quote(string, safe + space, encoding, errors) | |
return string.replace(' ', '+') | |
def quote_from_bytes(bs, safe='/'): | |
"""Like quote(), but accepts a bytes object rather than a str, and does | |
not perform string-to-bytes encoding. It always returns an ASCII string. | |
quote_from_bytes(b'abc def\x3f') -> 'abc%20def%3f' | |
""" | |
if not isinstance(bs, (bytes, bytearray)): | |
raise TypeError("quote_from_bytes() expected bytes") | |
if not bs: | |
return '' | |
if isinstance(safe, str): | |
# Normalize 'safe' by converting to bytes and removing non-ASCII chars | |
safe = safe.encode('ascii', 'ignore') | |
else: | |
safe = bytes([c for c in safe if c < 128]) | |
if not bs.rstrip(_ALWAYS_SAFE_BYTES + safe): | |
return bs.decode() | |
try: | |
quoter = _safe_quoters[safe] | |
except KeyError: | |
_safe_quoters[safe] = quoter = Quoter(safe).__getitem__ | |
return ''.join([quoter(char) for char in bs]) | |
def urlencode(query, doseq=False, safe='', encoding=None, errors=None): | |
"""Encode a dict or sequence of two-element tuples into a URL query string. | |
If any values in the query arg are sequences and doseq is true, each | |
sequence element is converted to a separate parameter. | |
If the query arg is a sequence of two-element tuples, the order of the | |
parameters in the output will match the order of parameters in the | |
input. | |
The components of a query arg may each be either a string or a bytes type. | |
When a component is a string, the safe, encoding and error parameters are | |
sent to the quote_plus function for encoding. | |
""" | |
if hasattr(query, "items"): | |
query = query.items() | |
else: | |
# It's a bother at times that strings and string-like objects are | |
# sequences. | |
try: | |
# non-sequence items should not work with len() | |
# non-empty strings will fail this | |
if len(query) and not isinstance(query[0], tuple): | |
raise TypeError | |
# Zero-length sequences of all types will get here and succeed, | |
# but that's a minor nit. Since the original implementation | |
# allowed empty dicts that type of behavior probably should be | |
# preserved for consistency | |
except TypeError: | |
# ty, va, tb = sys.exc_info() | |
raise TypeError("not a valid non-string sequence " | |
"or mapping object") # .with_traceback(tb) | |
l = [] | |
if not doseq: | |
for k, v in query: | |
if isinstance(k, bytes): | |
k = quote_plus(k, safe) | |
else: | |
k = quote_plus(str(k), safe, encoding, errors) | |
if isinstance(v, bytes): | |
v = quote_plus(v, safe) | |
else: | |
v = quote_plus(str(v), safe, encoding, errors) | |
l.append(k + '=' + v) | |
else: | |
for k, v in query: | |
if isinstance(k, bytes): | |
k = quote_plus(k, safe) | |
else: | |
k = quote_plus(str(k), safe, encoding, errors) | |
if isinstance(v, bytes): | |
v = quote_plus(v, safe) | |
l.append(k + '=' + v) | |
elif isinstance(v, str): | |
v = quote_plus(v, safe, encoding, errors) | |
l.append(k + '=' + v) | |
else: | |
try: | |
# Is this a sufficient test for sequence-ness? | |
_ = len(v) # noqa | |
except TypeError: | |
# not a sequence | |
v = quote_plus(str(v), safe, encoding, errors) | |
l.append(k + '=' + v) | |
else: | |
# loop over the sequence | |
for elt in v: | |
if isinstance(elt, bytes): | |
elt = quote_plus(elt, safe) | |
else: | |
elt = quote_plus(str(elt), safe, encoding, errors) | |
l.append(k + '=' + elt) | |
return '&'.join(l) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment