Last active
May 7, 2018 05:22
-
-
Save Lewiscowles1986/380425897b456a3f0d5b to your computer and use it in GitHub Desktop.
Python Dict / Multi-Dict to allow semantic structural nesting of formdata
This file contains hidden or 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
# FormData / Flat-to-Structured Dictionary Accessories For Python | |
# Copyright (C) 2015 Lewis Cowles | |
# | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
def _build_struct(components, struct): | |
# Loop over all but last component calling setdefault to set and return | |
# the value of the added element as struct (does what recursion achieved) | |
# using only two lines. | |
for comp in components: | |
struct = struct.setdefault(comp or len(struct), {}) | |
# return address of last object created or retrieved | |
return struct | |
def _parse_to_dict_val(key, value, struct): | |
components = [ | |
node.replace(']', '') for node in key.split('[') | |
] | |
struct = _build_struct(components[:-1], struct) | |
struct[components[-1] or len(struct)] = value | |
return struct | |
def parse_to_dict_vals(assignments): | |
dictout = {} | |
if isinstance(assignments, dict): | |
assignments = assignments.items() | |
for key, value in assignments: | |
_parse_to_dict_val(key, value, dictout) | |
return dictout | |
if __name__ == "__main__": | |
import unittest | |
import json | |
def getRoninStarlord(): | |
return parse_to_dict_vals([ | |
("name[]", "starlord"), | |
("name[accusor]", "ronin") | |
]) | |
def getGoodies(): | |
return parse_to_dict_vals([ | |
("goodies[starlord][age]", "29"), | |
("goodies[starlord][planet]", "Earth"), | |
("goodies[Yondu][species]", "Centaurian"), | |
("goodies[Yondu][abilities][]", "Magic Arrow"), | |
("goodies[Yondu][abilities][]", "Not Eating starlord") | |
]) | |
def miniJSON(v): | |
return json.dumps(v, sort_keys=True, separators=(',', ':')) | |
class InternalTest(unittest.TestCase): | |
def testStarlordName(self): | |
self.assertEqual( | |
getRoninStarlord()['name'][0], | |
'starlord') | |
def testAccusorName(self): | |
self.assertEqual( | |
getRoninStarlord()['name']['accusor'], | |
'ronin') | |
def testGoodiesStarlordAge(self): | |
self.assertEqual( | |
getGoodies()['goodies']['starlord']['age'], | |
'29') | |
def testSimpleRootOnly(self): | |
self.assertEqual( | |
miniJSON(parse_to_dict_vals({"name": "bob"})), | |
'{"name":"bob"}') | |
def testYonduInGoodiesHasAbilities(self): | |
self.assertTrue( | |
'abilities' in getGoodies()['goodies']['Yondu']) | |
def testYonduInGoodiesHasTwoAbilities(self): | |
self.assertTrue( | |
len(getGoodies()['goodies']['Yondu']['abilities']), | |
2) | |
def testCanParseDeepDoubleAuto(self): | |
self.assertEqual( | |
miniJSON( | |
parse_to_dict_vals( | |
{"root[subnode][attribute][][]": "value"}) | |
), | |
'{"root":{"subnode":{"attribute":{"0":{"0":"value"}}}}}') | |
def testCanParseDeepAutoWithNamedNode(self): | |
self.assertEqual( | |
miniJSON( | |
parse_to_dict_vals( | |
{"root[subnode][attribute][][me]": "value"}) | |
), | |
'{"root":{"subnode":{"attribute":{"0":{"me":"value"}}}}}') | |
unittest.main() |
I've put it on my todo ๐ ๐
Updated to PEP8 (it's probably junk code anyway)
Added doctests
Switched out dict
for list
of tuple
, although kept dict
as input support so that duplicate names are not destroyed.
Should probably be converted to multi-dict, right now seems to have parity with PHP HTTP form-data handling
wget {gist-raw-url}
pep8 FDAcc.py
python3 FDAcc.py
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You should really follow PEP8.