{ "info": { "author": "Malthe Borch", "author_email": "repoze-dev@lists.repoze.org", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: Zope Public License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP" ], "description": "The ``repoze.formapi`` provides a form library which integrates with\nHTML forms instead of abstracting them away.\n\nIt provides a small framework to take you through the entire process\nof rendering a form, provide default values, validate and execute form\nactions.\n\nForm fields are defined using Python base types which map out nested\ndata structures with end points that are either integers, strings,\nfloats or tuples of these. It's up to the application to bridge these\nwith more complex objects.\n\n\nIntroduction\n============\n\nThis library helps you parse, validate and deserialize form input as\nwell as execute form actions.\n\nThe starting point is to define the data structure that describes your\ndata. For instance, an action string and a list of numbers (typical\nfor a form that allows a user to select some items and apply an\naction):\n\n>>> fields = {\n... 'action': unicode,\n... 'items': [int]\n... }\n\nLet's apply the following input sequence:\n\n>>> params = [\n... ('action', 'submit'),\n... ('items', 1),\n... ('items', 2),\n... ('security-token', '...')\n... ]\n\nNote that ``'security-token'`` is an example of a parameter that is\nprovided, but not defined in the fields. That's not an error.\n\nNow, to parse the parameters above into the data structure defined by\nour fields definition, we use the ``parse`` function (note that in the\nrest of this text, we assume that symbols have been imported).\n\n>>> from repoze.formapi import parse\n>>> data, errors = parse(params, fields)\n\nIn the logic that handles this call, you'll typically want to test if\nthe ``errors`` value is true (meaning there was an error) or false\n(meaning there was no error).\n\n>>> bool(errors)\nFalse\n\nLet's take a look at the data:\n\n>>> data\n{'action': u'submit', 'items': [1, 2]}\n\n\nTypes\n=====\n\nIn the previous example, we used Python's built-in data types: ``int``\nand ``unicode``.\n\nHowever, you can use any callable as the data type. Note that if the\ncallable raises a ``KeyError``, then it's simply ignored.\n\nLet's try an example:\n\n>>> data, errors = parse((('foo', 'bar'), ('baz', 'boo'), ('baz', 'qux')), {\n... 'foo': str.upper,\n... 'baz': {'boo': 'yes'}.__getitem__,\n... })\n\nWhat can we expect in ``data``?\n\nThe ``'foo'`` parameter will be uppercased, the first ``'baz'``\nresolves to ``'yes'``, while the other raises a ``KeyError`` and is\nignored.\n\n>>> data\n{'foo': 'BAR', 'baz': 'yes'}\n\nIt's useful to remember that if you want a parameter to be ignored,\nsimply raise a ``KeyError``.\n\n\nForms\n=====\n\nThe library provides an abstraction for handling forms.\n\nTo create a form you subclass the ``Form`` class and define the form\nfield definitions in the ``fields`` attribute.\n\n>>> class TapeForm(Form):\n... \"\"\"Casette tape form.\"\"\"\n...\n... fields = {\n... 'artist': unicode,\n... 'title': unicode,\n... 'asin': str,\n... 'year': int,\n... 'playtime': float\n... }\n\nIf there are no start or *default* values, the form can be\ninstantiated with no arguments:\n\n>>> form = TapeForm()\n\nThe form data is available from the ``data`` attribute. Since we\ndidn't pass in a request, there's no data available.\n\n>>> form.data['artist'] is None\nTrue\n\nThat's not very interesting. Let's pass an input parameter.\n\n>>> params = (('title', u'Motorcity Detroit USA Live'),)\n>>> form = TapeForm(params=params)\n\nThis will set the ``'title'`` field.\n\nThe input is a valid unicode string and there are no validation\nerrors.\n\n>>> form.validate()\nTrue\n\nLet's confirm that the data is available.\n\n>>> form.data['title']\nu'Motorcity Detroit USA Live'\n\nThe library also support passing in a ``request`` argument, if this is\nan object that has a ``params`` attribute.\n\n>>> request = Request(params=params)\n\nThe ``Request`` class from `WebOb `_\n(a popular package that provides an object-oriented interface to the\nHTTP protocol) is compatible.\n\n>>> form = TapeForm(request=request)\n\nWe'll often want to initialize the form with default values. To this\neffect we pass in a dictionary object.\n\n>>> data = {\n... 'artist': u'Bachman-Turner Overdrive',\n... 'title': u'Four Wheel Drive',\n... 'asin': 'B000001FL8',\n... 'year': 1975,\n... 'playtime': 33.53\n... }\n>>> form = TapeForm(data)\n\nThe values are available in the form data object.\n\n>>> form.data['title']\nu'Four Wheel Drive'\n\nHowever, if we pass in the request from the former example, we'll see\nthat values from the request are used before the passed dictionary\nobject is queried.\n\n>>> form = TapeForm(data, request=request)\n>>> form.data['title']\nu'Motorcity Detroit USA Live'\n\nThe provided ``data`` dictionary is unchanged at this point:\n\n>>> data['title']\nu'Four Wheel Drive'\n\nWe need to invoke the ``save`` method to commit the changes to the\nprovided dictionary.\n\n>>> form.data.save()\n>>> data['title']\nu'Motorcity Detroit USA Live'\n\n\nAdditional validation\n---------------------\n\nIt is possible to create validation methods for more complex\nneeds. These extra validators can be hooked up using the `validator`\ndecorator.\n\n>>> class CDForm(Form):\n... fields = {\n... 'artist': unicode,\n... 'title': unicode,\n... 'asin': str,\n... 'year': int,\n... 'genre': str,\n... 'playtime': float}\n...\n... @validator\n... def check_genre(self):\n... if self.data['genre'] != 'rock':\n... yield 'Genre is invalid'\n\nA validator can look at all the data that is available. This makes it\neasy to create validators that need to check multiple fields.\n\n>>> form = CDForm()\n>>> form.validate()\nFalse\n\nThe errors attribute contains our error message.\n\n>>> form.errors[0]\n'Genre is invalid'\n\nErrors can also be assigned to a specific field. To do this a\nvalidator can register itself for a specific field.\n\n>>> class CDForm(Form):\n...\n... fields = {\n... 'artist': unicode,\n... 'title': unicode,\n... 'asin': str,\n... 'year': int,\n... 'genre': str,\n... 'playtime': float}\n...\n... @validator('genre')\n... def check_genre(self):\n... if self.data['genre'] != 'rock':\n... yield 'Genre is invalid'\n\nWhen this form is validated it will have the error available for the\nspecific field.\n\n>>> form = CDForm()\n>>> form.validate()\nFalse\n>>> 'genre' in form.errors\nTrue\n>>> form.errors['genre'][0]\n'Genre is invalid'\n\nForm context\n------------\n\nWe can set the context of a form to some object.\n\n>>> class Tape:\n... title = u'Motorcity Detroit USA Live'\n... asin = 'B000001FL8'\n... year = 1975\n\n>>> tape = Tape()\n\nThe form data will draw defaults from the context.\n\n>>> form = TapeForm(context=tape)\n>>> form.data['title']\nu'Motorcity Detroit USA Live'\n\nRequest parameters take priority over the context. In the following\nexample, we submit the form with trivial input.\n\n>>> request = Request(params=(('asin', u''), ('year', u'')))\n>>> form = TapeForm(context=tape, request=request)\n\nThis form input is valid; although ``year`` is an integer field, the\ntrivial input is valid and will be assigned a value of ``None``.\n\n>>> form.validate()\nTrue\n\nThe ``asin`` input is coerced to a string (from unicode).\n\n>>> form.data['asin']\n''\n\nThe ``year`` input is trivial. It's not a required field, so the value\nis ``None`` (treated as a non-input).\n\n>>> form.data['year'] is None\nTrue\n\nRequired fields\n---------------\n\nWe use the ``required`` method to mark fields required.\n\nLet's continue the example from above. If we make the fields required,\nthe input no longer validates.\n\n>>> TapeForm.fields['year'] = required(int, u\"Required field\" )\n>>> TapeForm.fields['asin'] = required(str)\n\nThe form input is no longer valid.\n\n>>> form = TapeForm(context=tape, request=request)\n>>> form.validate()\nFalse\n>>> form.data['year'] is None\nTrue\n\nThe error message is available as well:\n\n>>> form.errors['year'][0]\n'Required field'\n\nNow let's try a valid input:\n\n>>> request = Request(params=(('asin', u'B000001FL8'), ('year', u'1978')))\n>>> form = TapeForm(context=tape, request=request)\n\nWe can expect both required fields to be\nconverted and correctly typed.\n\n>>> form.validate()\nTrue\n\n>>> form.data['asin']\n'B000001FL8'\n\n>>> form.data['year']\n1978\n\nForm submission\n---------------\n\nIf a form prefix has not been set, the request is applied by\ndefault. However, most applications will want to set a form prefix and\nrequire explicit form submission.\n\nA form submits a \"default action\" if the prefix is submitted as a\nparameter.\n\n>>> request = Request(params=(\n... ('tape_form', ''),\n... ('title', u'Motorcity Detroit USA Live')))\n>>> form = TapeForm(request=request, prefix='tape_form')\n>>> form.data['title']\nu'Motorcity Detroit USA Live'\n\nAs expected, if we submit a form with a different prefix, the request\nis not applied.\n\n>>> form = TapeForm(request=request, prefix='other_form')\n>>> form.data['title'] is None\nTrue\n\nWe can also define form actions on the form class itself.\n\n>>> class TapeAddForm(TapeForm):\n... \"\"\"An add-form for a casette tape.\"\"\"\n...\n... @action\n... def handle_add(self, data):\n... print \"add\"\n...\n... @action(\"add_and_edit\")\n... def handle_add_and_edit(self, data):\n... print \"add_and_edit\"\n\nThe first action is a \"default action\"; if we submit the request we\nset up before, this action will be read to be submitted.\n\n>>> form = TapeAddForm(request=request, prefix='tape_form')\n>>> form.actions\n[,\n ]\n\nThe submitted action is available in the ``action`` parameter.\n\n>>> form.action\n\n\nTo call the form handler of the submitted action, we invoke the form's\ncall method.\n\n>>> form()\nadd\n\nTo call the named form action, there must be a parameter in the\nrequest which is a concatenation of the prefix and the form action\nname. Accepted separation characters are '.' (dot), '_' (underscore)\nand '-' (dash).\n\n>>> request = Request(params=(\n... ('tape_form-add_and_edit', ''),\n... ('title', u'Motorcity Detroit USA Live'),))\n>>> form = TapeAddForm(request=request, prefix='tape_form')\n>>> form.actions\n[,\n ]\n>>> form()\nadd_and_edit\n\nData proxies\n------------\n\nWe can bind a context object to a data object by using a proxy\nobject. This technique can be used to create edit or add-forms.\n\nTo illustrate this, let's define a content object. We'll hardcode\ndefault values for simplicity.\n\n>>> class Tape(object):\n... artist = u'Bachman-Turner Overdrive'\n... title = u'Four Wheel Drive'\n... asin = 'B000001FL8'\n... year = 1975\n... playtime = 33.53\n\nWe can now create a data proxy for an instance of this class.\n\n>>> tape = Tape()\n>>> proxy = Proxy(tape)\n\nWith no further intervention, this data object acts as a proxy to read\nand write attributes on the content object.\n\n>>> proxy.title\nu'Four Wheel Drive'\n>>> proxy.title = u'Motorcity Detroit USA Live'\n>>> tape.title\nu'Motorcity Detroit USA Live'\n\nIf we want to have more control over this process, we can subclass and\ndefine descriptors.\n\nThe following example defines custom behavior for the ``title``\nattribute; the value is uppercased.\n\n>>> class TapeProxy(Proxy):\n... def get_title(self):\n... return self.title\n...\n... def set_title(self, value):\n... self.title = value.upper()\n...\n... title = property(get_title, set_title)\n>>> proxy = TapeProxy(tape)\n\nIf we read and write to the ``title`` attribute of this proxy object,\nthe custom getter and setter functions are used.\n\n>>> proxy.title = u'Motorcity Detroit USA Live'\n\nAs would be expected from a proxy, changes are actually made to the\nunderlying content object.\n\n>>> tape.title\nu'MOTORCITY DETROIT USA LIVE'\n\nSaving form data\n----------------\n\nWhen instantiating a form, you can pass in a proxy object instead of\n``data``. This binds the data object to the proxy, but it also allows\nus to save the form data on the proxied object.\n\n>>> form = TapeForm(proxy, request=request)\n>>> form.data['title'] = u'Four Wheel Drive'\n\nAssignment behaves logically.\n\n>>> form.data['title']\nu'Four Wheel Drive'\n\nHowever, if we invoke the ``save`` action, changes take effect on the\nproxied object.\n\n>>> form.data.save()\n>>> tape.title\nu'FOUR WHEEL DRIVE'\n\nChangelog\n=========\n\n0.6.1 (2012-12-10)\n------------------\n\n- Added support for the field definition callable to raise a\n ``KeyError`` exception such that the input is ignored.\n\n0.6 (2012-12-10)\n----------------\n\n- The ``marshalling`` module has been renamed to ``parser``.\n\n- Fixed issue where an integer would cause an error even when not\n required.\n\n0.5.4 (2012-12-04)\n------------------\n\n- Added ``keys`` method to marshaller such that the object can be used\n as a mapping.\n\n0.5.3 (2012-11-23)\n------------------\n\n- Fixed an issue where a fields definition with a single entry would\n get incorrectly marshalled when the corresponding data had multiple\n entries.\n\n0.5.2 (2012-11-19)\n------------------\n\n- Fixed an issue with `required` where the marshaller would not\n correctly convert a value to the provided value type.\n\n\n0.5.1 (2012-11-16)\n------------------\n\n- Type-checking has been removed from the marshalling code::\n\n if not error and not isinstance(value, data_type):\n error = True\n\n This change was required to support \"schema types\" such as::\n\n import re\n\n match_email = re.compile(\n r\"^(\\w&.%#$&'\\*+-/=?^_`{}|~]+!)*[\\w&.%#$&'\"\n r\"\\*+-/=?^_`{}|~]+@(([0-9a-z]([0-9a-z-]*[0-9a-z])\"\n r\"?\\.)+[a-z]{2,6}|([0-9]{1,3}\\.){3}[0-9]{1,3})$\",\n re.IGNORECASE).match\n\n class email(unicode):\n def __new__(cls, string):\n if match_email(string):\n return string\n\n raise ValueError(u\"Not a valid e-mail address.\")\n\n\n0.5.0 (2010-05-28)\n------------------\n\n- Fixed ``Errors`` class to use the more obtuse ``__getattr__``\n override; this fixes an issue where an attribute lookup of\n ``__class__`` would fail. [malthe]\n\n- Added ``required`` decorator for field types; when we wrap a type\n with this decorator, inputs that do not validate (even the trivial\n input of the empty string) are given the input value as-is. Compare\n this to an optional field (the default setting) where the empty\n string will be interpreted as a non-input (unless it's a string type\n or another type which will accept the empty string). [malthe]\n\n- Add __contains__/has_key support to the Error class. [wichert]\n\n0.4.2 (2009-09-14)\n------------------\n\n- Added ``any`` builtin fallback. [malthe]\n\n0.4.1 (2009-07-31)\n------------------\n\n- Added defaultdict emulation class. [malthe]\n\n0.4 (2009-07-29)\n----------------\n\n- The selected action, if any, is available in the ``action``\n attribute of a form instance. [malthe]\n\n- Even if form input does not validate, the input is available as-is\n in the ``data`` dictionary. [malthe, rnix]\n\n- Request parameters can now be provided directly as the ``params``\n keyword argument. [malthe]\n\n- Added ``get`` method to errors dictionary. [malthe]\n\n- Errors can now be compared with each other to see if they are the\n same. This makes it easier to test without doctest.\n\n- Made the truth test for the errors object check just for messages in\n itself or it's sub errors. This avoids having the errors object\n saying it is true after accessing a key for which no error exists\n (thus creating a new errors object). [jvloothuis]\n\n- Changed the base class of errors from unicode to object. This makes\n it behave like one would expect when printing etc. [jvloothuis]\n\n0.3.2 (2009-03-09)\n------------------\n\n- Shedding unused dependency on 'zope.interface' [jvloothuis]\n\n0.3.1 (2008-10-27)\n------------------\n\n- Make it possible to set `prefix` as class attribute. [malthe]\n\n- Fixed issue where action parameters would not get set. [malthe]\n\n0.3 (2008-10-27)\n----------------\n\n- Marshalled data is no longer applied when no parameters are\n available from the request. [malthe]\n\n- Made the `errors`-object subclass unicode instead of defaultdict and\n implemented custom string representation function which concatenates\n error messages. [malthe]\n\n0.2 (2008-10-19)\n----------------\n\n- Created/improved the abilities for custom validation. [jvloothuis]\n\n- Added form action support. [malthe]\n\n- Reworked marshalling code to handle dynamic dictionary\n keys. [malthe]\n\n- Implemented form data object which facilities the form processing\n flow from applying the request to committing changes to a context\n object. [malthe]\n\n- Integrated the converter into the ``form`` module. [seletz]\n\n- Added ``ValidationErrors`` object, which evaluates to True if validation\n errors occured. [seletz]\n\n- Added ``unicode`` converter. [seletz]\n\n- Added ``converter`` module to support converting and validating request\n parameters sent by a form. [seletz]\n\n- Added logic to allow registering and acquiring template API\n components from templates. [malthe]\n\n- Changed the Skin Template View to be a class, and added a minimal\n interface ISkinTemplate to access the template path [seletz]\n\n- Fixed a bug where we did not tear down the tests correctly [seletz]\n\n- Fixed bug where the INewRequest event handler would call\n templates when checking for their existence [seletz]\n\n0.1 (2008-09-25)\n----------------\n\n- Initial release [malthe]\n\n- Added support to dynamically register templates if they\n are added to a registered template directory [seletz]", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "UNKNOWN", "keywords": "forms html validation marshalling", "license": "BSD-derived (http://www.repoze.org/LICENSE.txt)", "maintainer": null, "maintainer_email": null, "name": "repoze.formapi", "package_url": "https://pypi.org/project/repoze.formapi/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/repoze.formapi/", "project_urls": { "Download": "UNKNOWN", "Homepage": "UNKNOWN" }, "release_url": "https://pypi.org/project/repoze.formapi/0.6.1/", "requires_dist": null, "requires_python": null, "summary": "Minimalistic form library.", "version": "0.6.1" }, "last_serial": 798817, "releases": { "0.2": [ { "comment_text": "", "digests": { "md5": "3c8db3ec8aef5febacaca5e68e06f0ed", "sha256": "9dfa4d42435b306aac739140cc8742c4ad9f5c1e15ca1281dfb597a2b76ebc72" }, "downloads": -1, "filename": "repoze.formapi-0.2.tar.gz", "has_sig": false, "md5_digest": "3c8db3ec8aef5febacaca5e68e06f0ed", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14529, "upload_time": "2008-10-19T16:32:36", "url": "https://files.pythonhosted.org/packages/86/b1/df70fda270af8585a6b968d83688c06667d01677bcd0178780291316f0ef/repoze.formapi-0.2.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "ef6610491a186ebc9261b1b1479c8106", "sha256": "d4ee2109cb8b45f4f27df788578585c42717267844bd51710ad5869994cb41ee" }, "downloads": -1, "filename": "repoze.formapi-0.3.tar.gz", "has_sig": false, "md5_digest": "ef6610491a186ebc9261b1b1479c8106", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16570, "upload_time": "2008-10-29T09:11:19", "url": "https://files.pythonhosted.org/packages/88/34/ec994135b1a8e73aee794e8d10c911e414a564efe1c76359970151ee7b04/repoze.formapi-0.3.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "2ecb82bef5d06b1e14fa926da1f438b9", "sha256": "93a6103e1389276d35bdd678bf836c24ceafceac2e10cace838bf72f32bc028f" }, "downloads": -1, "filename": "repoze.formapi-0.3.1.tar.gz", "has_sig": false, "md5_digest": "2ecb82bef5d06b1e14fa926da1f438b9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16638, "upload_time": "2008-12-05T15:20:52", "url": "https://files.pythonhosted.org/packages/b7/f8/ce30d14861ef2897f9d3ed8f5ca92536b743970da9215ff5039fc806839c/repoze.formapi-0.3.1.tar.gz" } ], "0.3.2": [ { "comment_text": "", "digests": { "md5": "79693e6a2fdd698d3eae0a03813b7209", "sha256": "4ebcec37faeb7a234c247e0d707183e39d0587372b62c677a4185d8c21e19e2c" }, "downloads": -1, "filename": "repoze.formapi-0.3.2.tar.gz", "has_sig": false, "md5_digest": "79693e6a2fdd698d3eae0a03813b7209", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16647, "upload_time": "2009-03-09T08:00:37", "url": "https://files.pythonhosted.org/packages/03/f1/eb796be317c126b4390b6daa940793e0bbe7846e55627390213f0e6c04c8/repoze.formapi-0.3.2.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "054597fb588ef1c600e231486c7b0c6a", "sha256": "2c5d7c291ba7849094ca32a318b278cb640d28a9bf73cfae70a489e8c8509f69" }, "downloads": -1, "filename": "repoze.formapi-0.4.tar.gz", "has_sig": false, "md5_digest": "054597fb588ef1c600e231486c7b0c6a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28235, "upload_time": "2009-07-29T10:04:54", "url": "https://files.pythonhosted.org/packages/1b/e1/9b0afa16349114296514d35eafb8a486ce798f777b1ccb59a983d7daf3a7/repoze.formapi-0.4.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "054bb20779434b265319093a06f19a70", "sha256": "75dbb7be75f598af698405b149d343206c71f3779da864790fa72772aac853ae" }, "downloads": -1, "filename": "repoze.formapi-0.4.1.tar.gz", "has_sig": false, "md5_digest": "054bb20779434b265319093a06f19a70", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28583, "upload_time": "2009-07-31T13:59:14", "url": "https://files.pythonhosted.org/packages/19/2e/7a58d1925bb9f48d9a9e12bdace3a7aa6cf10a5df8755eaf90e56cc94a50/repoze.formapi-0.4.1.tar.gz" } ], "0.4.2": [ { "comment_text": "", "digests": { "md5": "4ecb22a44f6ea593a6ad756f9e428cec", "sha256": "f8df8bf0638057c776264e6c432dc0f4e8541408c29bb05130d6945c7dfd3bda" }, "downloads": -1, "filename": "repoze.formapi-0.4.2.tar.gz", "has_sig": false, "md5_digest": "4ecb22a44f6ea593a6ad756f9e428cec", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28659, "upload_time": "2009-09-14T14:08:07", "url": "https://files.pythonhosted.org/packages/8d/64/3ed3e4c3ec67d4e4916f8acf72bfabdee2769fa131470b509482db45068f/repoze.formapi-0.4.2.tar.gz" } ], "0.5.0": [ { "comment_text": "", "digests": { "md5": "64066d4becf8dfe3b2df207bfea2f398", "sha256": "9c9e3aa1e1173432f2fc709482e346064eba89c69fea8241db20327a964ee055" }, "downloads": -1, "filename": "repoze.formapi-0.5.0.tar.gz", "has_sig": false, "md5_digest": "64066d4becf8dfe3b2df207bfea2f398", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30439, "upload_time": "2010-05-28T05:49:16", "url": "https://files.pythonhosted.org/packages/85/9a/42d1de6793f2eba6545ba0a797784aee24cf4861bd2c25b5a832673b6281/repoze.formapi-0.5.0.tar.gz" } ], "0.5.1": [ { "comment_text": "", "digests": { "md5": "26118951a29d0b3f802d591f45804b1c", "sha256": "c2db6b51b8506f9300dd0035dbcb1de93ad508cdec2c91643653614d332900b2" }, "downloads": -1, "filename": "repoze.formapi-0.5.1.tar.gz", "has_sig": false, "md5_digest": "26118951a29d0b3f802d591f45804b1c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 34444, "upload_time": "2012-11-16T14:28:37", "url": "https://files.pythonhosted.org/packages/9d/4d/228661ed39ec361036e01d9de747410c5e14ec82b7cabc117d3b514eb455/repoze.formapi-0.5.1.tar.gz" } ], "0.5.2": [ { "comment_text": "", "digests": { "md5": "15028e812c13e5efb233bbea84c9fd03", "sha256": "3324486e6d7a85c4cd9b60d7deae1b49bfd3473a78e66f737a011ff031cacca7" }, "downloads": -1, "filename": "repoze.formapi-0.5.2.tar.gz", "has_sig": false, "md5_digest": "15028e812c13e5efb233bbea84c9fd03", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 34540, "upload_time": "2012-11-19T10:52:15", "url": "https://files.pythonhosted.org/packages/d7/b2/748401961fb1941d14c8c9c97854a42d2f8b87e85e547cfa00a29a3d957d/repoze.formapi-0.5.2.tar.gz" } ], "0.5.3": [ { "comment_text": "", "digests": { "md5": "5680bab5aff1c941724dcd1f92848602", "sha256": "f914ba9c26f56d116f263bab09bb7f6f727337df42d96d4d8c58f1ff956c05fd" }, "downloads": -1, "filename": "repoze.formapi-0.5.3.tar.gz", "has_sig": false, "md5_digest": "5680bab5aff1c941724dcd1f92848602", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35293, "upload_time": "2012-11-23T13:59:02", "url": "https://files.pythonhosted.org/packages/f8/a9/411c635631a158a8dfb26fc3c1730332febbb8e60d9b11ebfd5a37ee48a0/repoze.formapi-0.5.3.tar.gz" } ], "0.5.4": [ { "comment_text": "", "digests": { "md5": "f606b80ebf15b8b3df3cc5a50b1ccbfd", "sha256": "a98bae35dbb3233499bbc6b1455c13b3fa899ca426d9297bfa4af9fc145eb731" }, "downloads": -1, "filename": "repoze.formapi-0.5.4.tar.gz", "has_sig": false, "md5_digest": "f606b80ebf15b8b3df3cc5a50b1ccbfd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35572, "upload_time": "2012-12-04T14:17:08", "url": "https://files.pythonhosted.org/packages/c1/c2/e8889565eb7a15ff908385ae6169a5443c1bf3a6dc5ebca3cb0a2da6a649/repoze.formapi-0.5.4.tar.gz" } ], "0.6": [ { "comment_text": "", "digests": { "md5": "aaf64513f676b9d97f073df11a920c01", "sha256": "25bdc1847570aa586b175b1fd324e09a3b145f1a1e5b37572c6a0d2646d67c4c" }, "downloads": -1, "filename": "repoze.formapi-0.6.tar.gz", "has_sig": false, "md5_digest": "aaf64513f676b9d97f073df11a920c01", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36281, "upload_time": "2012-12-10T10:38:35", "url": "https://files.pythonhosted.org/packages/1f/94/28d4c30240420bdf48660a06a9eec7c27258eb754cf1454f533a8bbb3f64/repoze.formapi-0.6.tar.gz" } ], "0.6-dev": [], "0.6.1": [ { "comment_text": "", "digests": { "md5": "d3ebbf7448c8244882e0f2cf6db88fe0", "sha256": "c58230977ffc879640f6c2ae61d942b66356d92dbf9c07ace6e2a7e24f8a2cc7" }, "downloads": -1, "filename": "repoze.formapi-0.6.1.tar.gz", "has_sig": false, "md5_digest": "d3ebbf7448c8244882e0f2cf6db88fe0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 37266, "upload_time": "2012-12-10T14:28:13", "url": "https://files.pythonhosted.org/packages/c7/4c/afe685c01925b5b60cf016373238403a69d310af89e90f34296f907fb37e/repoze.formapi-0.6.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "d3ebbf7448c8244882e0f2cf6db88fe0", "sha256": "c58230977ffc879640f6c2ae61d942b66356d92dbf9c07ace6e2a7e24f8a2cc7" }, "downloads": -1, "filename": "repoze.formapi-0.6.1.tar.gz", "has_sig": false, "md5_digest": "d3ebbf7448c8244882e0f2cf6db88fe0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 37266, "upload_time": "2012-12-10T14:28:13", "url": "https://files.pythonhosted.org/packages/c7/4c/afe685c01925b5b60cf016373238403a69d310af89e90f34296f907fb37e/repoze.formapi-0.6.1.tar.gz" } ] }