Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

New name is Hopak

  • Loading branch information...
commit 4b4391d5a62dd9827cd6c2ae7b6fc355b8316867 1 parent ebc7401
Mikhail Kashkin authored
Showing with 57 additions and 1,980 deletions.
  1. +1 −1  .gitignore
  2. +23 −23 MANIFEST
  3. +1 −1  MANIFEST.in
  4. +15 −13 README.rst
  5. +7 −7 docs/README.ru.md
  6. +1 −1  examples/example.py
  7. +0 −1  formgear/__init__.py
  8. +0 −123 formgear/controllers.py
  9. +0 −17 formgear/ds/__init__.py
  10. +0 −37 formgear/ds/base.py
  11. +0 −43 formgear/ds/mongo.py
  12. +0 −29 formgear/exceptions.py
  13. +0 −333 formgear/fields.py
  14. +0 −3  formgear/forms.py
  15. +0 −17 formgear/loader.py
  16. +0 −488 formgear/models.py
  17. +0 −110 formgear/registry.py
  18. +0 −29 formgear/templates/form.html
  19. +0 −32 formgear/templates/form_old.html
  20. +0 −24 formgear/templates/widgets/base_widget.html
  21. +0 −37 formgear/templates/widgets/boolean.html
  22. +0 −35 formgear/templates/widgets/checkbox.html
  23. +0 −30 formgear/templates/widgets/email.html
  24. +0 −38 formgear/templates/widgets/markdown.html
  25. +0 −28 formgear/templates/widgets/password.html
  26. +0 −42 formgear/templates/widgets/pricerange.html
  27. +0 −39 formgear/templates/widgets/select.html
  28. +0 −29 formgear/templates/widgets/string.html
  29. +0 −25 formgear/templates/widgets/text.html
  30. +0 −32 formgear/templates/widgets/timerange.html
  31. +0 −97 formgear/utils.py
  32. +0 −207 formgear/widgets.py
  33. +5 −5 setup.py
  34. +2 −2 tests/__init__.py
  35. +2 −2 tests/models.py
2  .gitignore
View
@@ -1,7 +1,7 @@
*.py[co]
.DS_Store
.installed.cfg
-formgear.egg-info
+hopak.egg-info
bin
etc
.idea
46 MANIFEST
View
@@ -1,26 +1,26 @@
# file GENERATED by distutils, do NOT edit
README.rst
setup.py
-formgear/__init__.py
-formgear/controllers.py
-formgear/exceptions.py
-formgear/fields.py
-formgear/forms.py
-formgear/loader.py
-formgear/models.py
-formgear/registry.py
-formgear/utils.py
-formgear/widgets.py
-formgear/templates/form.html
-formgear/templates/form_old.html
-formgear/templates/widgets/base_widget.html
-formgear/templates/widgets/boolean.html
-formgear/templates/widgets/checkbox.html
-formgear/templates/widgets/email.html
-formgear/templates/widgets/markdown.html
-formgear/templates/widgets/password.html
-formgear/templates/widgets/pricerange.html
-formgear/templates/widgets/select.html
-formgear/templates/widgets/string.html
-formgear/templates/widgets/text.html
-formgear/templates/widgets/timerange.html
+hopak/__init__.py
+hopak/controllers.py
+hopak/exceptions.py
+hopak/fields.py
+hopak/forms.py
+hopak/loader.py
+hopak/models.py
+hopak/registry.py
+hopak/utils.py
+hopak/widgets.py
+hopak/templates/form.html
+hopak/templates/form_old.html
+hopak/templates/widgets/base_widget.html
+hopak/templates/widgets/boolean.html
+hopak/templates/widgets/checkbox.html
+hopak/templates/widgets/email.html
+hopak/templates/widgets/markdown.html
+hopak/templates/widgets/password.html
+hopak/templates/widgets/pricerange.html
+hopak/templates/widgets/select.html
+hopak/templates/widgets/string.html
+hopak/templates/widgets/text.html
+hopak/templates/widgets/timerange.html
2  MANIFEST.in
View
@@ -1,3 +1,3 @@
include *html
include *rst
-recursive-include formgear/templates *html
+recursive-include hopak/templates *html
28 README.rst
View
@@ -1,10 +1,12 @@
-Formgear
-#########
+Hopak
+######
-.. image:: https://secure.travis-ci.org/xen/formgear.png
- :target: https://travis-ci.org/xen/formgear
+Formely project name was ``formgear``.
-Main idea behind ``formgear`` allow iteratively create data models in easy
+.. image:: https://secure.travis-ci.org/xen/hopak.png
+ :target: https://travis-ci.org/xen/hopak
+
+Main idea behind ``hopak`` allow iteratively create data models in easy
readable form and use them as part of your websites. At this moment only
MongoDB is allowed.
@@ -19,10 +21,10 @@ But we are living in 21 century, have decoded DNA, pushing frontier into
space, digging into core of the atoms and listening dubstep! Why we must to
write all that crap? Why computers cann't just do all this stuff?
-So that is why we invent ``formgear``. Because we want computers to do that they
+So that is why we invent ``hopak``. Because we want computers to do that they
supposed to do.
-`formgear` is only part of this effort, but there are already some results. So,
+`hopak` is only part of this effort, but there are already some results. So,
example how to make simple model. We use `YAML` because it is very human
readable. Minimal file::
@@ -40,11 +42,11 @@ readable. Minimal file::
This file is enough to use it as model in your python code::
# models.py
- from formgear.models import Model
+ from hopak.models import Model
class User(Model):
__yaml__ = 'user.yaml'
-``formgear`` is only a library for bigger framework, if you decide to use the whole
+``hopak`` is only a library for bigger framework, if you decide to use the whole
stack then you will get site with admin section including list, edit, add,
search, delete sections for each models.
@@ -64,10 +66,10 @@ More
Links:
-* ``formgear`` page on PyPI: `http://pypi.python.org/pypi/formgear/
- <http://pypi.python.org/pypi/formgear/>`_
-* Github page: `https://github.com/xen/formgear
- <https://github.com/xen/formgear>`_
+* ``hopak`` page on PyPI: `http://pypi.python.org/pypi/hopak/
+ <http://pypi.python.org/pypi/hopak/>`_
+* Github page: `https://github.com/xen/hopak
+ <https://github.com/xen/hopak>`_
More documentation is approaching.
14 docs/README.ru.md
View
@@ -1,8 +1,8 @@
-# formgear
+# hopak
**Внимание, код не является полностью работающим, но является прототипом. Цель публикации документации — привлечь внимание**
-formgear — это активно развиваемый проект идея которого в том, чтобы максимально упростить работу по созданию сайтов.
+hopak — это активно развиваемый проект идея которого в том, чтобы максимально упростить работу по созданию сайтов.
Когда планирую сайт, то делаю его в несколько простых этапов. Перый - это подготовка чего-то типа "карты сайта". Обычно
назваю этот документ `sitemap.txt`. Пример такого документа:
@@ -32,7 +32,7 @@ formgear — это активно развиваемый проект идея
- Картинка
Как программисту кажется, что такого описания уже должно быть достаточно чтобы нажать какую-то магическую кнопку и
-получить работающий сайт. Для этого и создается **formgear**. Взять какой-то простой и предсказуемый синтаксис
+получить работающий сайт. Для этого и создается **hopak**. Взять какой-то простой и предсказуемый синтаксис
(никакого сраного XML) и сделать так чтобы после создания документов все магическим образом заработало.
На данный момент в проекте уже реализовано создание моделей в очень простом декларативном стиле, либо с помощью
@@ -84,7 +84,7 @@ fields:
В текущий момент реализован следующий путь:
```python
-from formgear.models import Model
+from hopak.models import Model
class NewsYAML(Model):
__yaml__ = 'news.yaml'
# тут код который вы хотите использовать дополнительно
@@ -92,8 +92,8 @@ class NewsYAML(Model):
# этот код эквивалентен приблизительно следующему python коду
-from formgear.fields import *
-from formgear.widgets import *
+from hopak.fields import *
+from hopak.widgets import *
class NewsPy(Model):
title = StringField(title="News Title", length=80, required=True)
@@ -127,5 +127,5 @@ TODO:
- пока нет url роутингов, но пример идеи можно посмотреть в `test/data/sample/sitemap.yaml`
- не понятно будет ли этот проект оформлен как библиотека которую можно будет использовать
в любых своих проектах или будет тесно связан с каким-то фреймворком
-- formgear дурацкое название, скорее всего будет придумано какое-то более эпичное
+- hopak дурацкое название, скорее всего будет придумано какое-то более эпичное
- нет вообще никаких тестов
2  examples/example.py
View
@@ -3,7 +3,7 @@
__author__ = 'xen'
-from formgear.models import Model #, ModelRegistry
+from hopak.models import Model #, ModelRegistry
class User(Model):
__yaml__ = 'doctype'
1  formgear/__init__.py
View
@@ -1 +0,0 @@
-# -*- coding: utf-8 -*-
123 formgear/controllers.py
View
@@ -1,123 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-
-""" Basic validators
-"""
-import re
-from formgear.exceptions import NotFoundValidatorException, InvalidValue
-from registry import Registry
-import inspect
-
-import sys
-
-PY3 = sys.version_info[0] == 3
-
-if PY3: # pragma: no cover
- string_types = str,
- text_type = str
-else:
- string_types = basestring,
- text_type = unicode
-
-class ValidatorRegistry(Registry):
- NotFound = NotFoundValidatorException
-
-class MetaValidator(type):
- """
- Class for all validators
- """
- def __new__(cls, name, bases, attrs):
- registername = attrs.pop('name', name.lower())
- newbornclass = super(MetaValidator, cls).__new__(cls, name, bases, attrs)
- ValidatorRegistry.register(newbornclass, registername)
- return newbornclass
-
-class BaseValidator(object):
- """ All vaidators should be child of this class to add themself to registry
- """
- __metaclass__ = MetaValidator
-
-
-class Required(BaseValidator):
- """ Validator which tests is value empty."""
- def __init__(self):
- pass
-
- def __call__(self, node, value):
- if not value:
- raise InvalidValue(node, "is required")
-
-class Regex(BaseValidator):
- def __init__(self, regex, msg=None):
- if isinstance(regex, string_types):
- self.match_object = re.compile(regex)
- else:
- self.match_object = regex
- if msg is None:
- self.msg = "String does not match expected pattern"
- else:
- self.msg = msg
-
- def __call__(self, node, value):
- if self.match_object.match(value) is None:
- raise InvalidValue(node, self.msg)
-
-class Email(Regex):
- """ Email address validator.
- """
- def __init__(self, msg=None):
- if msg is None:
- msg = _("Invalid email address")
- super(Email, self).__init__(regex='(?i)^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$', msg=msg)
-
-class Length(BaseValidator):
- """ Validator which succeeds if the value passed to it has a
- length between a minimum and maximum. The value is most often a
- string."""
- min_err = 'Shorter than minimum length %s'
- max_err = 'Longer than maximum length %s'
-
- def __init__(self, min=None, max=None):
- self.min = min
- self.max = max
-
- def __call__(self, node, value):
- if self.min is not None:
- if len(value) < self.min:
- raise InvalidValue(node, self.min_err % str(self.min))
-
- if self.max is not None:
- if len(value) > self.max:
- raise InvalidValue(node, self.max_err % str(self.max))
-
-class Max(BaseValidator):
- """ Validate if value not great than `value`
- """
-
- text_err = 'Current value - %d is great than max %d'
-
- def __init__(self, value=None):
- self.value = value
-
- def __call__(self, node, value):
- if self.value is not None:
- if self.value < value:
- raise InvalidValue(node, self.text_err % (self.value, value,))
-
-class Min(BaseValidator):
- """ Validate if value not less than `value`
- """
-
- text_err = 'Current value - %d is less than min %d'
-
- def __init__(self, value=None):
- self.value = value
-
- def __call__(self, node, value):
- if self.value is not None:
- if self.value > value:
- raise InvalidValue(node, self.text_err % (self.value, value,))
-
-
-def lookup(lvs={}):
- return [ValidatorRegistry.resolve(validator)(**lvs[validator]) for validator in lvs]
17 formgear/ds/__init__.py
View
@@ -1,17 +0,0 @@
-__all__ = ['ConnectionError', 'register_datasource',
- 'get_datasource', 'DEFAULT_DATASOURCE_NAME']
-
-DEFAULT_DATASOURCE_NAME = 'default'
-
-class ConnectionError(Exception):
- pass
-
-_datasources = {}
-
-def register_datasource(ds, alias=DEFAULT_DATASOURCE_NAME):
- global _datasources
- _datasources[alias] = ds
-
-def get_datasource(alias=DEFAULT_DATASOURCE_NAME):
- global _datasources
- return _datasources[alias]
37 formgear/ds/base.py
View
@@ -1,37 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-
-class BaseDS(object):
- """ Data source interface
- """
-
- def __init__(self, conn):
- self.conn = conn
-
- def save(self, id):
- raise NotImplemented
-
- def get(self, id):
- raise NotImplemented
-
- def delete(self, id):
- raise NotImplemented
-
- def save_multi(self, ids=[]):
- raise NotImplemented
-
- def get_multi(self, ids=[]):
- raise NotImplemented
-
- def delete_multi(self, ids=[]):
- raise NotImplemented
-
- def query(self):
- raise NotImplemented
-
- def count(self):
- raise NotImplemented
-
- def disconnect(self):
- raise NotImplemented
-
43 formgear/ds/mongo.py
View
@@ -1,43 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-from .base import BaseDS
-
-class MongoDS(BaseDS):
- """ Mongodb Data Source
- """
-
- def __init__(self, conn):
- self.conn = conn
-
- def save(self, id):
- _id = _id or data.get('_id')
- if not (_id is None):
- self.conn.db.update({"_id": _id}, data, upsert=True, safe=True)
- return _id
- else:
- return self.conn.db.insert(data)
-
- def get(self, id):
- return self.conn.db.find({"_id": _id})
-
- def delete(self, id):
- self.conn.db.remove({"_id": _id})
-
- def save_multi(self, ids=[]):
- pass
-
- def get_multi(self, ids=[]):
- pass
-
- def delete_multi(self, ids=[]):
- pass
-
- def find(self, col, **kw):
- return self.conn.db[col].find(kw)
-
- def count(self, **kw):
- return self.conn.db.count(kw)
-
- def disconnect(self):
- self.conn.disconnect()
-
29 formgear/exceptions.py
View
@@ -1,29 +0,0 @@
-"""
-List of exceptions that may be happen in our new modest framework.
-"""
-
-class NotFoundModelException(Exception):
- pass
-
-
-class ParsingExcpetion(Exception):
- pass
-
-
-class YamlAttributeNotFoundException(Exception):
- pass
-
-
-class YamlEntryNotFoundInListException(Exception):
- pass
-
-class NotFoundValidatorException(Exception):
- pass
-
-class InvalidValue(Exception):
- """
- Base form validation exception
-
- Based on https://github.com/Pylons/colander/blob/master/colander/__init__.py
-
- """
333 formgear/fields.py
View
@@ -1,333 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import datetime, re
-
-import controllers
-import widgets
-from registry import Registry
-from formgear.exceptions import InvalidValue
-
-class NotFoundFieldException(Exception):
- pass
-
-
-class FieldsRegistry(Registry):
- """ Registry needed to resolve fields from YAML file """
- fields = {}
- NotFound = NotFoundFieldException
-
-
-class MetaField(type):
- """
- Class for all widgets
- """
- def __new__(cls, name, bases, attrs):
- meta = attrs.pop('Meta', None)
- abstract = getattr(meta, 'abstract', False)
- registername = attrs.pop('name', name.lower())
- newbornclass = super(MetaField, cls).__new__(cls, name, bases, attrs)
-
- if not abstract:
- #print("Register widget:", registername)
- FieldsRegistry.register(newbornclass, registername)
-
- return newbornclass
-
-
-def init_partial(real):
- def init_partial(self, *a, **kw):
- self._partial = a, kw
- return real(self, *a, **kw)
-
- return init_partial
-
-
-class BaseField(object):
- """ BaseField is very similar to MongoEngine fields.
- """
-
- __metaclass__ = MetaField
- # Fields may have _types inserted into indexes by default
- _index_with_types = True
- _geo_index = False
- widget = widgets.StringWidget
-
- @init_partial
- def __init__(self, db_field=None, required=False, default=None,
- unique=False, unique_with=None, primary_key=False,
- validators=[], widget=None, **kw):
- """
- Params:
-
- * db_field - set explicit field name in database
- * required - quick alias for validator.Required
- * title - field name
- * default=None - default value
- * unique=False - mongodb unique field index
- * unique_with=None - mongodb unique_with field index
- * primary_key=False - mongodb field index for primary_key
- * validators=None - set of validators from controllers collection (or your own)
- * description=None - field help text description
- * widget - widget to represent field value
-
- """
- self.db_field = db_field if not primary_key else '_id'
-
- self.required = required or primary_key
- self.unique = bool(unique or unique_with)
- self.unique_with = unique_with
- self.default = default
-
- self.validators = controllers.lookup(validators)
- if controllers.Required in self.validators:
- self.required = True
- if required:
- self.required = True
- if controllers.Required not in self.validators:
- self.validators.append(controllers.Required)
-
- if widget:
- self.widget = widget
-
- self.__dict__.update(kw)
- self.value = None
-
- def validate(self):
- """Perform validation on a value.
- """
- ret = True
- self.errors = []
- for validator in self.validators:
- if isinstance(validator, type):
- validator = validator()
-
- try:
- validator(self, self.value)
- except InvalidValue, e:
- ret = False
- self.errors.append(e.args[1])
- return ret
-
- def reinstance(self):
- a, kw = self._partial
- return self.__class__(*a, **kw)
-
- def translate(self, msgid):
- """ Use the translator passed to the renderer of this field to
- translate the msgid into a term. If the renderer does not have a
- translator, this method will return the msgid."""
- translate = getattr(self.renderer, 'translate', None)
- if translate is not None:
- return translate(msgid)
- return msgid
-
- def __repr__(self):
- return '<%s.%s object at %d>' % (
- self.__module__,
- self.__class__.__name__,
- id(self)
- )
-
- def __unicode__(self):
- return unicode(self.value)
-
- __str__ = __unicode__
-
- def __call__(self, state="edit", **kwargs):
- return self.widget.render(self, state, **kwargs)
-
- def clear(self):
- self._value = None
-
- def set_value(self, val):
- self._value = val
-
- def get_value(self):
- val = self._value or self.default
-
- if val:
- short, _val = self.shortcut(val)
- if short:
- val = _val
-
- return val
-
- value = property(get_value, set_value)
-
- def shortcut(self, value):
- return False, None
-
- @property
- def to_mongo(self):
- if hasattr(self, '__mongo__'):
- val = self.__mongo__(self.value)
- else:
- val = self.value
-
- return val
-
-
-class StringField(BaseField):
- """ Simple string
- """
-
- alter_names = ('string',)
-
- def __init__(self, regex=None, max_length=None, min_length=None, **kwargs):
- self.regex = re.compile(regex) if regex else None
- self.max_length = max_length
- self.min_length = min_length
- super(StringField, self).__init__(**kwargs)
-
-
-class TextField(BaseField):
- """ Plain text field.
- XXX: Add text processors, may be including typography.
- """
- alter_names = ('text',)
- widget = widgets.TextWidget
-
- def __init__(self, max_length=None, min_length=None, **kwargs):
- self.max_length = max_length
- self.min_length = min_length
- super(TextField, self).__init__(**kwargs)
-
-
-class DateField(BaseField):
- alter_names = ('date', )
-
- format='%Y/%m/%d'
- # self.data = datetime.datetime.strptime(date_str, self.format).date()
- def __init__(self, **kwargs):
- """
- """
- pass
-
-
-class DateTimeField(BaseField):
-
- alter_names = ('datetime',)
- type = 'date'
-
- def shortcut(self, value):
- if value == 'now':
- return True, datetime.datetime.now()
- elif value == 'today':
- return True, datetime.datetime.today()
-
- return False, None
-
- def validate(self):
- if isinstance(self.value, datetime.datetime):
- return True
-
- from dateutil import parser
- try:
- self.value = parser.parse(self.value or '')
- except ValueError:
- return
-
- return True
-
-
-class TimeField(BaseField):
- alter_names = ('time', )
-
-
-class IntegerField(BaseField):
- alter_names = ('int', 'integer', )
-
-
-class BooleanField(BaseField):
- alter_names = ('bool', 'boolean', )
-
- def shortcut(self, value):
- return True, bool(value)
-
-class EmailField(BaseField):
- alter_names = ('email', )
-
- def validate(self):
- ret = '@' in self.value
- if not ret:
- self.errors = [
- u"Wrong email format",
- ]
- return ret
-
-
-class FloatField(BaseField):
- alter_names = ('float', )
-
-
-class URLField(BaseField):
- alter_names = ('url', 'link', )
-
- #XXX: Y NO ccTLD like xn--shitshitshit domains?
- URL_REGEX = re.compile(
- r'^https?://'
- r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|'
- r'localhost|'
- r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
- r'(?::\d+)?'
- r'(?:/?|[/?]\S+)$', re.IGNORECASE
- )
-
- def __init__(self, verify_exists=False):
- self.verify_exists = verify_exists
- super(URLField, self).__init__(**kwargs)
-
-
-class FileField(BaseField):
- alter_names = ('file', 'blob', )
-
-
-class ImageField(BaseField):
- alter_names = ('img', 'image', )
-
-
-class GeoPointField(BaseField):
- alter_names = ('geo', 'geopoint', )
-
-
-class TimerangeField(BaseField):
- alter_name = ('timerange')
- widget = widgets.TimerangeWidget
-
-
-class CheckboxField(BaseField):
- alter_names = ('checkbox',)
- choices = {}
- widget = widgets.CheckboxWidget
-
- def clear(self,):
- self._value = []
-
- def set_value(self, val):
-
- oldval = getattr(self, '_value', None)
- if not isinstance(oldval, list):
- self._value = [] if oldval is None else [oldval]
-
- if isinstance(val, (list, tuple)):
- self._value = val
- else:
- self._value.append(val)
-
- value = property(BaseField.get_value, set_value)
-
-
-class StructField(BaseField):
- alter_names = ('struct',)
-
-
-class PathField(StringField):
- alter_names = ('pathfield',)
-
- def set_value(self, val):
- if val:
- if not val.startswith("/"):
- val = "/%s" % (val,)
- self._value = val
-
- value = property(BaseField.get_value, set_value)
3  formgear/forms.py
View
@@ -1,3 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-
17 formgear/loader.py
View
@@ -1,17 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import models
-
-def _load(name):
- o = models.MetaModel(name, (models.Model,),
- {'__yaml__': name}
- )
-
- return o
-
-def load(name):
- ret = models.ModelRegistry.resolve(name, default=False)
- if ret:
- return ret
-
- return _load(name)
488 formgear/models.py
View
@@ -1,488 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-from __future__ import print_function
-import os
-import yaml
-
-from formgear.fields import FieldsRegistry
-from formgear.widgets import WidgetRegistry
-from registry import Registry
-from formgear.exceptions import *
-from formgear.utils import rel, yamls_files, file_resolve
-from formgear.ds import get_datasource
-
-from jinja2 import Environment, PackageLoader
-
-yamlsfiles = yamls_files()
-
-
-class ModelRegistry(Registry):
- NotFound = NotFoundModelException
-
-def model_wrap(model, **wrap_kw):
- def __init__(self, *a, **kw):
- kw.update(wrap_kw)
- model.__init__(self, *a, **kw)
-
- attrs = {"__init__": __init__, "__fake__": True}
- return MetaModel(model.__name__, (model,), attrs)
-
-class FormWrap(object):
- def __init__(self, forms, model):
- self.model = model
-
- self.forms = forms
-
- def get(self, name, silent=None):
- """ Return form fields as dict for a class:
-
- # >>> model.form(name='default')
- # [('email', <formgear.fields.StringField object at 4529231184>), ...)]
- # >>> model.form(name='search')
- # KeyError: "Form 'search' not found for model <class 'admin.auth.models.User'>"
-
- There is always 'default' form which contaions all model field.
-
- If `silent` param provided then wrong form name don't caught exception
-
- """
- name = name or 'default'
- for form in self.forms:
- if form['name'] == name:
- #print(name, ': ', form)
- return form
- if silent:
- return None
- else:
- raise KeyError("Form %r not found for model %r" % (name, self.model))
-
- def field(self, name):
- return self.model._fields_dict[name]
-
- def __call__(self, name=None, fields=[], **kw):
- if not fields:
- form = self.get(name or self.model.subform, **kw)
- if form:
- fields = form['fields']
-
- ret = [
- (name, self.field(name))
- for name in fields
- ]
- return ret
-
-
- def __getattribute__(self, name):
- try:
- return object.__getattribute__(self, name)
- except AttributeError:
- if self.get(name) is None:
- raise
-
- if isinstance(self.model, type):
- model = model_wrap(self.model, subform=name)
- model.subform = name
- return model
-
- obj = self.model.__class__(subform=name)
- obj._fields = self.model._fields
- return obj
-
-
-class MetaModel(type):
- """
- Base model metaclass
- """
- def __new__(cls, name, bases, attrs):
- meta = attrs.pop('Meta', None)
- abstract = getattr(meta, 'abstract', False)
- fake = attrs.pop('__fake__', None)
- registername = attrs.pop('name', name.lower())
-
- cfg = {}
- # we have search __yaml__ attribute only, when we
- # have initialize a subclass of formgear.models.Model
- if not abstract:
-
- # try to find out by __yaml__ or by class name
- # __yaml__ = "order" or class Order(Models):
- ypath = attrs.get('__yaml__') or name.lower()
- if not ypath.endswith('.yaml'):
- ypath = yamlsfiles.get(ypath, ypath)
- if not os.access(ypath, 0) or not os.access(rel(ypath), 0):
- raise YamlEntryNotFoundInListException
-
- cfg = yaml.safe_load(open(ypath))
-
- attrs["__yaml__"] = ypath
-
- # this block should make model registry list looks better
- _descr = ''
- if cfg.get('description', None):
- _descr = cfg.get('description')
- if attrs.get('__doc__', None) and len(attrs.get('__doc__')):
- _descr = attrs.get('__doc__')
- else:
- attrs['__doc__'] = _descr
- _title = registername
- if cfg.get('title', None):
- _title = cfg.get('title')
-
- cfg['_name'] = registername
- cfg['_descr'] = _descr
- cfg['_title'] = _title
-
- fields = []
- key_fields = attrs.get('__key__', [])
- if not isinstance(key_fields, (list,tuple)):
- key_fields = []
-
- for field in cfg.pop('fields', []):
- if 'name' not in field:
- raise ParsingException("Oops, we found nameless field!")
-
- field_typ = field.pop('type', 'string')
- field_class = FieldsRegistry.resolve(field_typ)
-
- # extracts widget information
- widget = field.pop('widget', field_class.widget)
-
- if isinstance(widget, dict):
- widget_typ = widget.pop('type', field_class.widget)
- widget_kw = widget
- else:
- widget_typ = widget
- widget_kw = {}
-
- if isinstance(widget_typ, basestring):
- widgt_class = WidgetRegistry.resolve(widget_typ)
- else:
- widgt_class = widget_typ
-
- wdgt = widgt_class(**widget_kw)
-
- file_resolve(field, "choices", ypath)
-
- if field['name'] in key_fields:
- field['required'] = True
-
- new_field = field_class(widget = wdgt, **field)
-
- # actual work with fields
- # XXX: here is missed part with validators
- fields.append((field.pop('name'), new_field))
-
- forms = []
- forms.extend(cfg.pop('forms', []))
- forms.append({
- "name": "default",
- "fields": [
- fname
- for fname, _field in fields
- if hasattr(_field, 'title')
- ],
- })
-
- cfg.update(attrs)
- newbornclass = super(MetaModel, cls).__new__(cls, name, bases, cfg)
-
- for fname, ffunc in fields:
- setattr(newbornclass, fname, ffunc)
-
- newbornclass._fields = fields
- newbornclass._fields_dict = dict(fields)
-
-
- newbornclass.form = FormWrap(forms, newbornclass)
-
- if not abstract and not fake:
- ModelRegistry.register(newbornclass, registername)
-
- return newbornclass
-
-class Model(object):
- __metaclass__ = MetaModel
- subform = None
-
- class Meta:
- abstract = True
-
- def __init__(self, data=None, subform=None, _id=None, _raw=False, datasource=None, **kw):
- assert data is None or not kw, 'Pass data in one way'
- if data:
- kw = data
- if _id:
- self._id = _id
-
- if datasource:
- self.datasource = datasource
- else:
- self.datasource = get_datasource()
-
- self.subform = subform
- form = self.form.get(subform)
- self.render_form = self._render_form
-
- subform_fields = []
- all_fields = []
- for name, _field in self._fields:
- field = _field.reinstance()
- all_fields.append((name,field))
-
- if name in form['fields']:
- subform_fields.append((name, field))
-
- self._fields = subform_fields
- self._fields_dict = dict(subform_fields)
- self._all_fields_dict = dict(all_fields)
- self.form = FormWrap(self.form.forms, self)
-
- self.update(kw, raw=_raw)
- if _id:
- self.lock_id()
-
- def update(self, data=None, raw=False, **kw):
- assert data is None or not kw, 'Pass data in one way'
- kw = data or kw
- if callable(getattr(kw, 'items', None)):
- kw = kw.items()
-
- for name, val in kw:
-
- field = self._field(name, raw=raw)
- if not field:
- continue
-
- if getattr(field, 'locked', False):
- continue
-
- field.value = val
-
- def items(self):
- for name, field in self._fields:
- yield name, field.value
-
- def __iter__(self):
- return iter(self.form(self.subform))
-
- def _field(self, name, raw=False):
- if raw:
- return self._all_fields_dict.get(name)
- return self._fields_dict.get(name)
-
- # getattr gives access to all loaded fields
- def __getattribute__(self, name):
- try:
- fields = object.__getattribute__(self,'_all_fields_dict')
- if name in fields:
- return fields.get(name).value
-
- except AttributeError:
- pass
-
- return object.__getattribute__(self, name)
-
- # setattr gives acces only to fields available in this subform
- def __setattr__(self, name, value):
- try:
- fields = object.__getattribute__(self,'_fields_dict')
- if name in fields:
- fields[name].value = value
- return
- elif name in object.__getattribute__(self,'_all_fields_dict'):
- raise TypeError(
- "Refused to update field %s missing in subform %s" %
- (name, self.subform)
- )
-
- except AttributeError:
- pass
-
- return object.__setattr__(self, name, value)
-
- def validate(self):
- for name, field in self._fields:
- if not hasattr(field, 'validate'):
- continue
-
- valid = field.validate()
- if not valid:
- return
-
- return True
-
- def to_mongo(self):
-
- doc = dict([
- (name, field.to_mongo)
- for name,field in self._all_fields_dict.items()
- ])
-
- if '_id' in doc:
- pass
- elif hasattr(self, 'key'):
- _id = self.key()
- if not (_id is None):
- doc['_id'] = _id
- elif hasattr(self, '_id'):
- doc['_id'] = self._id
-
- return doc
-
- def lock_id(self):
- if not hasattr(self.__class__, '__key__'):
- return
-
- if not isinstance(self.__key__, (list, tuple)):
- return
-
- for name in self.__key__:
- field = self._field(name)
- if not field:
- continue
-
- field.locked = True
-
- @classmethod
- def __key_type(cls, value):
- import bson
- if not hasattr(cls, '__key__'):
- return bson.objectid.ObjectId(value)
-
- return value
-
- def key(self):
- if not hasattr(self.__class__, '__key__'):
- return getattr(self, '_id', None)
-
- if isinstance(self.__key__, (list, tuple)):
- if self.__key__[0] == '_id':
-
- # don`t generate random id twice
- if hasattr(self, '_id'):
- return self._id
-
- import bson
- names = self.__key__[1:]
- vals = [
- unicode(bson.objectid.ObjectId())
- ]
- else:
- names = self.__key__
- vals = []
-
- vals.extend([
- getattr(self, fieldname)
- for fieldname in names
- ])
- assert None not in vals, "Field must have a value \
-if specified in __key__"
-
- return unicode.join(u"::", vals)
-
- elif isinstance(self.__key__, basestring):
- return getattr(self, self.__key__)
- elif callable(self.__key__):
- return self.__key__()
- elif hasattr(self.__class__.__key__, 'getter'):
- return self.__key__
-
- assert False, "Who is Mr. __key__?"
-
- def save(self, datasource=None):
- ds = None
- if datasource:
- ds = datasource
- elif hasattr(self, 'datasource'):
- ds = self.datasource
- else:
- ds = get_datasource()
-
- _id = getattr(self, '_id', None)
- self._id = ds.save(self.kind(), self.to_mongo(), _id)
- return self._id
-
- @classmethod
- def all(cls, datasource=None, **kw):
- ds = None
- if datasource:
- ds = datasource
- else:
- ds = get_datasource()
-
- return [
- cls(_raw=True, **data)
- for data in
- ds.find(cls.kind(), **kw)
- ]
-
- @classmethod
- def kind(cls):
- return cls.__name__.lower()
-
- @classmethod
- def count(cls):
- return cls.all().count()
-
- @classmethod
- def get(cls, key=None, **kw):
- if not kw and key:
- kw = {"_id": cls.__key_type(key)}
-
- data = list(cls.all(**kw)[:1])
- if not data:
- return
-
- return data[0]
-
- @classmethod
- def delete(cls, _filter, datasource=None):
- if not isinstance(filter, dict):
- _filter = {"_id": cls.__key_type(_filter)}
- ds = None
- if datasource:
- ds = datasource
- else:
- ds = get_datasource()
- ds.remove(cls.kind(), _filter)
-
- def render_form(self, env=None, state='edit', form=None, **kw):
- """
- Form rendering entry point.
- This method can be used to render both forms (model subclasses)
- and form instances (aka objects).
- Returns plain HTML.
-
- :param env: jinja2 envirement object used for template rendering.
- This param *should* be ommited when calling from jinja2 templates.
- Passed environment should have "form.html" template and widget
- templates availible.
-
- :param state: controls which state of form should be displayed.
- Common states are "edit" and "table_edit"
- Form states and field states are different concepts.
- Form states are implemented as macros in "form.html" template
-
- :param form: subform name used when rendering this form/model.
- Subform is a named set (slice) of fields, specified in model.yaml.
- This param should not be passed to forms or objects with subform
- attribute set to value other than None
- When no subforms defined in yaml, no param passed and no "subform"
- attribute set, all fields are rendered
-
- Default field set can be overriden by specifying "default" subform in
- yaml.
- """
- #print(form, '-', self.subform)
- assert form is None or self.subform is None
- env = env or Environment(loader=PackageLoader('formgear'))
- template = env.get_template('form.html')
- m = getattr(template.module, state, None)
-
- fields = self.form(form or self.subform or 'default')
-
- return m(form = fields, **kw)
-
- _render_form = render_form
- render_form.environmentfunction = True
- render_form = classmethod(render_form)
110 formgear/registry.py
View
@@ -1,110 +0,0 @@
-class NotFoundException(Exception):
- pass
-
-class DublicateRegistryEntryException(Exception):
- pass
-
-class Registry(object):
- """ Registry is singleton wich maintain list of registered classes and
- allow to quick resolve into class by simple key search.
-
- >>> from formgear.registry import Registry, NotFoundException
- >>> class NotFoundTestException(Exception):
- ... pass
- ...
-
- Sample class
-
- >>> class TestRegistry(Registry):
- ... NotFound = NotFoundTestException
- ...
- >>> type(TestRegistry)
- <class 'formgear.registry.__metaclass__'>
-
- >>> assert isinstance(TestRegistry, object)
-
- Actual usage example
-
- >>> class TestObject(object):
- ... alter_names = ('test1', 'test2', )
- ...
- >>> TestRegistry.register(TestObject, 'testobject')
- >>> TestRegistry.resolve('testobject')
- <class 'formgear.registry.TestObject'>
- >>> TestRegistry.resolve('test1')
- <class 'formgear.registry.TestObject'>
-
- Exception example if item is not found
-
- >>> TestRegistry.resolve('test_notfound')
- Traceback (most recent call last):
- ...
- NotFoundTestException: Key 'test_notfound' not found in <class 'formgear.registry.TestRegistry'>
-
- Resolved item is the same as original class
-
- >>> TestObject == TestRegistry.resolve('testobject')
- True
-
- Whole registry contains all name variations
-
- >>> TestRegistry.list()
- ['test1', 'test2', 'testobject']
-
- >>> TestRegistry.unregister('test2')
- >>> TestRegistry.list()
- ['test1', 'testobject']
-
-
- """
- class __metaclass__(type):
- def __new__(cls, name, bases, attrs):
- data = attrs.get('data', {})
- attrs['data'] = data.copy()
- return type.__new__(cls, name, bases, attrs)
-
- data = {}
-
- @classmethod
- def resolve(cls, name, default=None):
- name = name.lower()
- if name in cls.data:
- return cls.data[name]
- elif default is not None:
- return default
- else:
- Exc = getattr(cls, 'NotFound', NotFoundException)
- raise Exc('Key %r not found in %r' % (name, cls))
-
- @classmethod
- def lookup(cls, name):
- """ le Check da existence """
- return cls.data.has_key(name)
-
- @classmethod
- def register(cls, val, name):
- for x in getattr(val, 'alter_names', []):
- if not cls.data.has_key(x):
- cls.data[x] = val
- else:
- raise DublicateRegistryEntryException
-
- cls.data[name] = val
-
- @classmethod
- def unregister(cls, what):
- """ Remove items from registry """
- if type(what) == str:
- del cls.data[what]
- elif type(what) == list:
- for i in what:
- assert type(i) == str
- del cls.data[i]
- else:
- # some duck typing
- for i in getattr(what, 'alter_names', []):
- del cls.data[i]
-
- @classmethod
- def list(cls):
- return cls.data.keys()
29 formgear/templates/form.html
View
@@ -1,29 +0,0 @@
-<!-- Система форм -->
-
-{%- macro edit(form, action=None) -%}
- {% for name, field in form %}
- {{field.itype}}
- {% if field.locked %}
- {{ field(name = name, state='view')|safe }}
- {% else %}
- {{ field(name = name, state='edit')|safe }}
- {% endif %}
- {% endfor %}
- <input type="hidden" value="1" name="form.submitted">
- {% if action %}
- <div class="form-actions">
- <button type="submit" class="btn btn-primary">{{ action }}</button>
- </div>
-
- {% endif %}
-{%- endmacro -%}
-
-{%- macro table_edit(form) -%}
- <tr>
- {% for name, field in form %}
- <td field="{{name}}">
- {{ field(name = name, state='inline_edit', **kwargs)|safe }}
- </td>
- {% endfor %}
- </tr>
-{%- endmacro -%}
32 formgear/templates/form_old.html
View
@@ -1,32 +0,0 @@
-
-
-{% macro render_form(form, state) -%}
-
-{% for field in form %}
-{{ row(field, state=state, **kwargs) }}
-{% endfor %}
-<input type="hidden" value="1" name="form.submitted">
-{%- endmacro %}
-
-{% macro row(field, state='view') -%}
-<div class="clearfix {% if field.errors %}error{% endif %}">
- <label for="errorInput">{{ field.label }}</label>
- <div class="input">
- {{ field(state) }}
- {% if field.errors %}<span class="help-inline">{{ field.errors|join(', ') }}</span>{% endif %}
- {% if field.description %}<span class="help-block">{{ field.description }}</span>{% endif %}
- </div>
-</div>
-{%- endmacro %}
-
-{% macro table(field) -%}
-{# As table #}
-
-
-{%- endmacro %}
-
-{% macro search(field) -%}
-{# As table #}
-
-
-{%- endmacro %}
24 formgear/templates/widgets/base_widget.html
View
@@ -1,24 +0,0 @@
-{%- macro label(field, name, prefix, widget) -%}
-{{kwargs.____}} {#XXX#}
-<label for="form_{{ name }}_id">{{ field.title }}</label>
-{%- endmacro -%}
-
-{%- macro text_attrs(field, name, prefix, widget, class='') -%}
-{{
- {
- 'name': '%(prefix)s%(name)s'|format(prefix=prefix, name=name),
- 'type': widget.itype(),
- 'id':'form_%(name)s_id'|format(name=name),
- 'placeholder': field.placeholder,
- 'class': class,
- 'required': 'required' if field.required else None,
- 'readonly': 'on' if field.locked else None,
- 'pattern': field.pattern,
- 'autofocus': 'autofocus' if field.autofocus else None
- }|xmlattr
-}}
-{%- endmacro -%}
-
-{%- macro errors(field) -%}
-{% if field.errors %}<span class="help-inline">{{ field.errors|join(', ') }}</span>{% endif %}
-{%- endmacro -%}
37 formgear/templates/widgets/boolean.html
View
@@ -1,37 +0,0 @@
-{% import "base_widget.html" as b %}
-
-{%- macro view(name, field, prefix) %}
- <h3>{{ name }}</h3>
- <p>{% if field.value %}<i class="icon-ok"></i>{% else %}<i class="icon-remove"></i>{% endif %}</p>
-{%- endmacro %}
-
-{%- macro table_view(name, field, prefix) %}
-{% if field.value %}
- <i class="icon-ok"></i>
-{% else %}
- <i class="icon-remove"></i>
-{% endif %}
-{%- endmacro %}
-
-{%- macro edit(name, field, prefix) %}
-{{kwargs.____}} {#XXX#}
-<div class="control-group {% if field.errors %}error{% endif %}">
- {{ b.label(field, name, **kwargs) }}
- <div class="controls">
- <label class="checkbox">
- <input type="checkbox" id="form_{{ name }}_id" value="1" {% if field.value %}checked{% endif %}>
- </label>
- {% if field.errors %}<span class="help-inline">{{ field.errors|join(', ') }}</span>{% endif %}
- {% if field.description %}<span class="help-block">{{ field.description }}</span>{% endif %}
- </div>
-</div>
-{%- endmacro %}
-
-{%- macro inline_edit(name, field) -%}
-<label for="form_{{ name }}_id">
- <input {{ b.text_attrs(field, name, **kwargs) }}
- value="{{ field.value or field.empty }}" />
- {{name}}
-</label>
-
-{%- endmacro -%}
35 formgear/templates/widgets/checkbox.html
View
@@ -1,35 +0,0 @@
-{% import "base_widget.html" as b %}
-
-{%- macro view(name, field, prefix) %}
- <h3>{{ name }}</h3>
- <p>{{ field.value | join(', ') }}</p>
-{%- endmacro %}
-
-{%- macro table_view(name, field, prefix) %}
-{{ field.value|join(", ")|truncate}}
-{%- endmacro %}
-
-
-{%- macro edit(name, field, prefix) %}
-{{kwargs.____}} {#XXX#}
-<div class="control-group {% if field.errors %}error{% endif %}">
- {{ b.label(field, name, **kwargs) }}
- <div class="controls">
- {% if field.choices %}
- {% for key, val in field.choices %}
- <label class="checkbox">
- <input name="{{ prefix }}{{ name }}" type="checkbox"
- value="{{ key }}" {% if key in field.value %}checked{% endif %} />
- {{ val }}
- </label>
- {% endfor %}
- {% else %}
- <label class="checkbox">
- <input name="{{ prefix }}{{ name }}" type="checkbox" id="form_{{ name }}_id"
- value="1" /> {{ field.title }}</label>
- {% endif %}
- </div>
- {% if field.errors %}<span class="help-inline">{{ field.errors|join(', ') }}</span>{% endif %}
- {% if field.description %}<span class="help-block">{{ field.description }}</span>{% endif %}
- </div>
-{%- endmacro %}
30 formgear/templates/widgets/email.html
View
@@ -1,30 +0,0 @@
-{% import "base_widget.html" as b %}
-
-{%- macro view(name, field, prefix) %}
- <h3>{{ name }}</h3>
- <p>{{ field.value }}</p>
-{%- endmacro %}
-
-{%- macro table_view(name, field, prefix) %}
- {{ field.value }}
-{%- endmacro %}
-
-{%- macro edit(name, field) %}
-{{kwargs.____}} {#XXX#}
-<div class="control-group {% if field.errors %}error{% endif %}">
- {{ b.label(field, name, **kwargs) }}
- <div class="controls">
- <div class="input-prepend">
- <span class="add-on"><i class="icon-envelope"></i></span><input {{ b.text_attrs(field, name, **kwargs) }}
- value="{{ field.value or field.empty }}" />
- </div>
- {{ b.errors(field) }}
- {% if field.description %}<p class="help-block">{{ field.description }}</p>{% endif %}
- </div>
-</div>
-{%- endmacro %}
-
-{%- macro inline_edit(name, field) -%}
-<input {{ b.text_attrs(field, name, **kwargs) }}
- value="{{ field.value or field.empty }}" />
-{%- endmacro -%}
38 formgear/templates/widgets/markdown.html
View
@@ -1,38 +0,0 @@
-{% import "base_widget.html" as b %}
-
-{%- macro view(name, field, prefix) %}
- <h3>{{ name }}</h3>
- <p>{{ field.value }}</p> {# XXX: Processor filter here? #}
-{%- endmacro %}
-
-{%- macro table_view(name, field, prefix) %}
-{{ field.value|truncate }}
-{%- endmacro %}
-
-{%- macro edit(name, field, prefix) %}
-{{kwargs.____}} {#XXX#}
-<script type="text/javascript">
- $(document).ready(function() {
- var converter1 = Markdown.getSanitizingConverter();
- var editor1 = new Markdown.Editor(converter1);
- editor1.run();
- });
-</script>
-<div class="control-group {% if field.errors %}error{% endif %}">
- <label for="markItUp">{{ field.title }}</label>
- <div class="wmd-panel">
- <div id="wmd-button-bar"></div>
- <textarea name="{{ prefix }}{{ name }}" placeholder="{{ field.placeholder }}" class="wmd-input" id="wmd-input"
- {% if field.required %}required{% endif %}
- {% if field.autofocus %}autofocus{% endif %}>{{ field.value }}</textarea>
- </div>
- <div id="wmd-preview" class="wmd-panel wmd-preview"></div>
- {% if field.errors %}<span class="help-inline">{{ field.errors|join(', ') }}</span>{% endif %}
- {% if field.description %}<span class="help-block">{{ field.description }}</span>{% endif %}
-</div>
-{%- endmacro %}
-
-{%- macro inline_edit(name, field) -%}
-<input {{ b.text_attrs(field, name, **kwargs) }}
- value="{{ field.value or field.empty }}" />
-{%- endmacro -%}
28 formgear/templates/widgets/password.html
View
@@ -1,28 +0,0 @@
-{% import "base_widget.html" as b %}
-
-{%- macro view(field, name) %}
- <h3>{{ name }}</h3>
- <p><i class="icon-eye-close"></i>********</p>
-{%- endmacro %}
-
-{%- macro table_view(name, field, prefix) %}
-<i class="icon-eye-close"></i>********
-{%- endmacro %}
-
-{%- macro edit(name, field) %}
-{{kwargs.____}} {#XXX#}
-<div class="control-group {% if field.errors %}error{% endif %}">
- {{ b.label(field, name, **kwargs) }}
- <div class="controls">
- <input {{ b.text_attrs(field, name, **kwargs) }}
- value="{{ field.empty }}" />
- {% if field.errors %}<span class="help-inline">{{ field.errors|join(', ') }}</span>{% endif %}
- {% if field.description %}<span class="help-block">{{ field.description }}</span>{% endif %}
- </div>
-</div>
-{%- endmacro %}
-
-{%- macro inline_edit(name, field) -%}
-<input {{ b.text_attrs(field, name, **kwargs) }}
- value="{{ field.value or field.empty }}" />
-{%- endmacro -%}
42 formgear/templates/widgets/pricerange.html
View
@@ -1,42 +0,0 @@
-{% import "base_widget.html" as b %}
-
-{%- macro view(name, field, prefix) %}
- <h3>{{ name }}</h3>
- {% if field.value %}
- <p>{{ field.value.from }} - {{ field.value.to }} {{field.value.currency}}</p>
- {% else %}
- <p>{{ field.empty }}</p>
- {% endif %}
-
-{%- endmacro %}
-
-{%- macro table_view(name, field, prefix) %}
-{% if field.value %}
- {{ field.value.from }} - {{ field.value.to }} {{field.value.currency}}
-{% else %}
- {{ field.empty }}
-{% endif %}
-{%- endmacro %}
-
-
-{%- macro edit(name, field, prefix) %}
-{{kwargs.____}} {#XXX#}
-<div class="control-group {% if field.errors %}error{% endif %}">
- <label for="form_{{ name }}_id">{{ field.title }}</label>
- <input name="{{ prefix }}{{ name }}__from" type="text" id="form_{{ name }}_id"
- value="{{ field.value.from or field.empty }}" {% if field.required %}required{% endif %}
- pattern="\d+(\.\d{2})?" placeholder="120.00" maxlength="6" /> -
- <input name="{{ prefix }}{{ name }}__to" type="text" id="form_{{ name }}_id"
- value="{{ field.value.to or field.empty }}" {% if field.required %}required{% endif %}
- pattern="\d+(\.\d{2})?" placeholder="240.00" maxlength="6" />
- <select name="{{ prefix }}{{ name }}__currency" type="text" id="form_{{ name }}_id">
- <option value=""> - </option>
- {% for currency, name in [['UAH', 'грн.'],['USD', 'дол.'], ['EUR', 'евро']] %}
- <option {% if currency == field.value.currency %}selected{%endif%}
- value="{{currency}}">{{name}}</option>
- {% endfor %}
- </select>
- {% if field.errors %}<span class="help-inline">{{ field.errors|join(', ') }}</span>{% endif %}
- {% if field.description %}<span class="help-block">{{ field.description }}</span>{% endif %}
-</div>
-{%- endmacro %}
39 formgear/templates/widgets/select.html
View
@@ -1,39 +0,0 @@
-{% import "base_widget.html" as b %}
-
-{%- macro view(name, field, prefix) %}
- <h3>{{ name }}</h3>
- <p>{{ field.value }}</p>
-{%- endmacro %}
-
-{%- macro table_view(name, field, prefix) %}
-{{ field.value|truncate }}
-{%- endmacro %}
-
-{%- macro edit(name, field, prefix) %}
-{{kwargs.____}} {#XXX#}
-<div class="control-group {% if field.errors %}error{% endif %}">
- <label for="form_{{ name }}_id">{{ field.title }}</label>
- <div class="controls">
- {% if field.choices|length <= 5 %} {# 5 is magic number #}
- {% for key, val in field.choices %}
- <label class="radio">
- <input name="{{ prefix }}{{ name }}" type="radio"
- value="{{ key }}" {% if key == field.value %}checked{% endif %} />
- {{ val }}
- </label>
- {% endfor %}
- {% else %}
- <select name="{{ prefix }}{{ name }}">
- <option>Select</option>
- {% for key, val in field.choices %}
- <option {% if key == field.value %}selected{% endif %} value="{{ key }}">{{ val }}</option>
- {% endfor %}
- </select>
- {% endif %}
- </div>
- {% if field.errors %}<span class="help-inline">{{ field.errors|join(', ') }}</span>{% endif %}
- {% if field.description %}<span class="help-block">{{ field.description }}</span>{% endif %}
-</div>
-{%- endmacro %}
-
-
29 formgear/templates/widgets/string.html
View
@@ -1,29 +0,0 @@
-{% import "base_widget.html" as b %}
-
-{%- macro view(name, field, prefix, widget) %}
- <h3>{{ name }}</h3>
- <p id="{{ "form_%(name)s_id"|format(name=name)}}" >{{ field.value }}</p>
-{%- endmacro %}
-
-{%- macro table_view(name, field, prefix) %}
- {{ field.value }}
-{%- endmacro %}
-
-
-{%- macro edit(name, field) %}
-{{kwargs.____}} {#XXX#}
-<div class="control-group {% if field.errors %}error{% endif %}">
- {{ b.label(field, name, **kwargs) }}
- <div class="controls">
- <input {{ b.text_attrs(field, name, **kwargs) }}
- value="{{ field.value or field.empty }}" />
- {{ b.errors(field) }}
- {% if field.description %}<p class="help-block">{{ field.description }}</p>{% endif %}
- </div>
-</div>
-{%- endmacro %}
-
-{%- macro inline_edit(name, field) -%}
-<input {{ b.text_attrs(field, name, **kwargs) }}
- value="{{ field.value or field.empty }}" />
-{%- endmacro -%}
25 formgear/templates/widgets/text.html
View
@@ -1,25 +0,0 @@
-{% import "base_widget.html" as b %}
-
-{%- macro view(name, field, prefix) %}
- <h3>{{ name }}</h3>
- <p>{{ field.value }}</p> {# XXX: Processor filter here? #}
-{%- endmacro %}
-
-{%- macro table_view(name, field, prefix) %}
-{{ field.value|truncate }}
-{%- endmacro %}
-
-{%- macro edit(name, field, prefix) %}
-{{kwargs.____}} {#XXX#}
-<div class="control-group {% if field.errors %}error{% endif %}">
- <label for="form_{{ name }}_id">{{ field.title }}</label>
- <div class="controls">
- <textarea name="{{ prefix }}{{ name }}" placeholder="{{ field.placeholder }}" id="form_{{ name }}_id" class="input-xlarge"
- {% if field.required %}required{% endif %}
- {% if field.autofocus %}autofocus{% endif %}
- rows="4" cols="50">{{ field.value or field.empty }}</textarea>
- {% if field.errors %}<span class="help-inline">{{ field.errors|join(', ') }}</span>{% endif %}
- {% if field.description %}<span class="help-block">{{ field.description }}</span>{% endif %}
- </div>
-</div>
-{%- endmacro %}
32 formgear/templates/widgets/timerange.html
View
@@ -1,32 +0,0 @@
-{% import "base_widget.html" as b %}
-
-{%- macro view(name, field, prefix) %}
- <h3>{{ name }}</h3>
- {% if field.value %}
- <p>{{ field.value.from }} - {{ field.value.to }}</p>
- {% else %}
- <p>{{ field.empty }}</p>
- {% endif %}
-{%- endmacro %}
-
-{%- macro table_view(name, field, prefix) %}
-{{ field.value }}
-{%- endmacro %}
-
-
-{%- macro edit(name, field, prefix) %}
-{{kwargs.____}} {#XXX#}
-<div class="control-group {% if field.errors %}error{% endif %}">
- <label for="form_{{ name }}_id">{{ field.title }}</label>
- <div class="controls">
- <input name="{{ prefix }}{{ name }}__from" type="text" id="form_{{ name }}_from_id"
- value="{{ field.value.from or field.empty }}" {% if field.required %}required{% endif %}
- pattern="\d{1,2}:\d{2}" placeholder="2:00" maxlength="5" /> -
- <input name="{{ prefix }}{{ name }}__to" type="text" id="form_{{ name }}_to_id"
- value="{{ field.value.to or field.empty }}" {% if field.required %}required{% endif %}
- pattern="\d{1,2}:\d{2}" placeholder="20:00" maxlength="5" />
- {% if field.errors %}<span class="help-inline">{{ field.errors|join(', ') }}</span>{% endif %}
- {% if field.description %}<span class="help-block">{{ field.description }}</span>{% endif %}
- </div>
-</div>
-{%- endmacro %}
97 formgear/utils.py
View
@@ -1,97 +0,0 @@
-import sys
-import logging
-import os.path
-import re
-
-def rel(_file, *x):
- return os.path.normpath(
- os.path.join(
- os.path.abspath(
- os.path.dirname(_file)
- ), *x
- )
- )
-
-#rel(os.getcwd(), os.path.dirname(__file__), 'post.yaml')
-
-def find_yaml(yaml_list, dirname, names):
- """
- Callback for `yamls_files` function
- dirname - current directory name, that `yamls_files` walks
- names - list of dirs and files in the `dirname` directory
- yaml_list - accumulator from caller of callback function,
- in this variable we agrigrate obtained files
- """
- for name in names:
- path_to_file = os.path.join(dirname, name)
- if os.path.isfile(path_to_file):
- if ".yaml" in name:
- yaml_list[re.sub("\.yaml", "", name, 1)] = path_to_file
-
-
-def yamls_files():
- """
- Searching yaml files in sys.path.
- Return the dict like:
- {'yourfilename' : '/absolute/path/to/your/yourfilename.yaml'
- ...
- ...
- }
- """
- yaml_list = {}
- for cur_path in sys.path:
- os.path.walk(cur_path, find_yaml, yaml_list)
-
- logging.info("obtained yaml files %r" % (yaml_list,))
- return yaml_list
-
-
-def find_widget_template(widget_path_list, dirname, names):
- if os.path.isdir(dirname) and dirname.endswith("widgets"):
- widget_path_list.append(dirname)
-
-
-def widgets_path():
-
- widget_path_list = []
- for cur_path in sys.path:
- os.path.walk(cur_path, find_widget_template, widget_path_list)
- return widget_path_list
-
-
-def file_resolve(field, name, ypath):
- choicesf = field.get(name, None)
-
- if choicesf is None:
- return
-
- if not (isinstance(choicesf, basestring) and \
- choicesf.startswith("@")):
- return
-
- # try to open csv file
- choices_file = open(os.path.join(os.path.dirname(ypath), choicesf[1:]))
- choices = []
- for line in choices_file:
- line = line.decode("utf-8")
- key, val = line.split("\t", 1)
- choices.append((key, val))
-
- field[name] = choices
-
-def form_dict(form):
- ret = {}
- for key, val in form:
- container = ret
- while '__' in key:
- ckey, key = key.split('__', 1)
- if ckey.isdigit():
- ckey = int(ckey)
- _container = container.get(ckey, {})
- container[ckey] = _container
- container = _container
-
- container[key] = val
-
- return ret
-
207 formgear/widgets.py
View
@@ -1,207 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-from __future__ import print_function
-import os
-
-from jinja2 import Environment, FileSystemLoader
-from registry import Registry
-from utils import widgets_path
-
-
-widgetspath = widgets_path()
-
-
-class NotFoundWidgetException(Exception):
- pass
-
-
-class WidgetRegistry(Registry):
- NotFound = NotFoundWidgetException
-
-
-class MetaWidget(type):
- """
- Class for all widgets
- """
- def __new__(cls, name, bases, attrs):
- #print("Forming new widget class:", cls)
- #print("Class bases:", bases)
- #print("Class name:", name)
- #print("Class attrs", attrs)
- meta = attrs.pop('Meta', None)
- abstract = getattr(meta, 'abstract', False)
- registername = attrs.pop('name', name.lower())
- newbornclass = super(MetaWidget, cls).__new__(cls, name, bases, attrs)
-
- if not abstract:
- newbornclass.load_macros()
- #print("Register widget:", registername)
- WidgetRegistry.register(newbornclass, registername)
-
- return newbornclass
-
-
-class Widget(object):
- """
- Виджеты регистрируются в общем реестре и потом могут обратно резолвится
- через специальный реестр.
-
- Виджеты имеют следующие аттрибуты:
-
- hidden
- виджет не отображается в форме
-
- name
- удобное имя для виджета, по умолчанию подставляется имя класса
-
- template
- шаблон который занимается отображением. Внимание в шаблоне должны быть
- доступный определенный набор макросов для вызова. Для начала наверное что-то
- типа:
-
- * edit - режим редактирования в стандартной форме
- * view - режим просмотрта
- * table_edit - редактирование в табличной форме (для массового редактирования)
- * table_view - просмотр поля в табличном режиме
- * search_edit - в поисковой форме
-
- XXX: пока не решен вопрос с AJAX виджетами для которых нужны серверные методы
-
- """
- __metaclass__ = MetaWidget
-
- hidden = False
- error_class = 'error'
- css = None
- value = ""
- _type = "text"
-
- class Meta:
- abstract = True
-
- def __init__(self, **kw):
- self.__dict__.update(kw)
-
- def render(self, field, state, env=None, **kw):
- if self.hidden:
- return ''
-
- macro = getattr(self, '_macro_%s' % state, None)
- assert macro, 'Widget %s have no macro named %r' % (
- self.__class__.__name__, state
- )
- return macro(field=field, widget=self, **kw)
-
- def itype(self):
- return self._type
-
- @classmethod
- def load_macros(cls):
- env = Environment(loader=FileSystemLoader(widgetspath))
- tmplt = env.get_template(cls.template+".html")
- mod = tmplt.module
- for macro_name, macro in mod.__dict__.items():
- if macro_name[0] == '_':
- continue
-
- setattr(cls, '_macro_%s' % macro_name, macro)
-
-
-# html5 input fields, support status here http://www.w3schools.com/html5/html5_form_input_types.asp
-# color
-# date
-# datetime
-# datetime-local
-# email
-# month
-# number
-# range
-# search
-# tel
-# time
-# url
-# week
-
-class DateWidget(Widget):
- """
- DateWidget
- """
- template = 'string'
- alter_names = ('date',)
-
-
-class StringWidget(Widget):
- """
- InputWidget <input type="text"/>
- """
- _type = 'text'
- alter_names = ('string',)
- template = 'string' # We will try to find text.html template in widgets directory
- value = ""
-
-class PhoneWidget(Widget):
- alter_names = ('tel', 'phone', )
- _type = 'tel'
- template = 'string'
-
-class TextWidget(Widget):
- """
- TextWidget <textarea />
- """
- alter_names = ('text',)
- template = 'text'
-
-
-class PasswordWidget(StringWidget):
- """
- PasswordWidget <input type="password" />
- """
- alter_names = ('password', 'passw')
- template = 'password'
- _type = 'password'
-
-class BooleanWidget(Widget):
- """" Simple checkbox """
- alter_names = ('boolean', 'bool')
- template = 'boolean'
-
-class EmailWidget(StringWidget):
- """ Email input filed
- """
- alter_names = ('email',)
- template = 'email'
- _type = 'email'
-
-class CheckboxWidget(Widget):
- """
- CheckboxWidget <input type="checkbox" />
- """
- alter_names = ('checkbox',)
- template = 'checkbox'
-
-
-class PricerangeWidget(Widget):
- alter_names = ('pricerange',)
- template = 'pricerange'
-
-
-class TimerangeWidget(Widget):
- alter_names = ('timerange',)
- template = 'timerange'
-
-
-class SelectWidget(Widget):
- """ One choice with multiple list
- """
- alter_names = ('select',)
- template = 'select'
-
-'''class ImageWidget(Widget):
- """
- http://blueimp.github.com/jQuery-File-Upload/
- """
- pass'''
-
-class MarkdownWidget(Widget):
- alter_names = ('markdown',)
- template = 'markdown'
10 setup.py
View
@@ -3,22 +3,22 @@
from distutils.core import setup
-setup(name='formgear',
+setup(name='hopak',
version='0.3.5',
- description='Formgear framework base package',
+ description='hopak framework base package',
long_description = open("README.rst").read(),
author='Mikhail Kashkin',
author_email='mkashkin@gmail.com',
- url='https://github.com/xen/formgear',
+ url='https://github.com/xen/hopak',
# more examples here http://docs.python.org/distutils/examples.html#pure-python-distribution-by-package
- packages=['formgear', ],
+ packages=['hopak', ],
license = "BSD",
install_requires=[
'jinja2',
'pyyaml'
],
package_data = {
- 'formgear': [
+ 'hopak': [
'templates/*.html',
'templates/widgets/*.html',
]
4 tests/__init__.py
View
@@ -1,6 +1,6 @@
from __future__ import absolute_import
-# from formgear.models import Model, ModelRegistry
-# from formgear.fields import FieldsRegistry
+# from hopak.models import Model, ModelRegistry
+# from hopak.fields import FieldsRegistry
# import logging
# import yaml
4 tests/models.py
View
@@ -1,5 +1,5 @@
-from formgear.models import Model, ModelRegistry
-from formgear.fields import FieldsRegistry
+from hopak.models import Model, ModelRegistry
+from hopak.fields import FieldsRegistry
import yaml
Please sign in to comment.
Something went wrong with that request. Please try again.