Beispiel #1
0
class ResponseTimer(object):
    """Nearly trivial class, used for tracking how long the page took to
    create.

    Properties are `total_time`, `sql_time`, and `sql_queries`.

    In SQL debug mode, `sql_query_log` is also populated.  Its keys are
    queries; values are dicts of parameters, time, and caller.
    """

    def __init__(self):
        self._start_time = datetime.now()
        self._total_time = None

        self.from_cache = None

        # SQLAlchemy will add to these using the above event listeners; see
        # spline.config.environment
        self.sql_time = timedelta()
        self.sql_queries = 0
        self.sql_query_log = OrderedDict()

    @property
    def total_time(self):
        # Calculate and save the total render time as soon as this is accessed
        if self._total_time is None:
            self._total_time = datetime.now() - self._start_time
        return self._total_time

    def add_log(self, log):
        self.sql_query_log.setdefault(log["statement"], []).append(log)
Beispiel #2
0
 def __init__(self, model, **kwargs):
     BaseFieldSet.__init__(self, model, **kwargs)
     self.iface = model
     self.rebind(model)
     self._fields = OrderedDict()
     self._render_fields = OrderedDict()
     self._bound_pk = None
     for name, field in schema.getFieldsInOrder(self.iface):
         klass = field.__class__
         try:
             t = self._fields_mapping[klass]
         except KeyError:
             raise NotImplementedError("%s is not mapped to a type" % klass)
         else:
             self.append(Field(name=name, type=t))
             self._fields[name].label_text = field.title or name
             if field.description:
                 self._fields[name].set(instructions=field.description)
             if field.required:
                 self._fields[name].validators.append(validators.required)
             if klass is schema.Password:
                 self._fields[name].set(renderer=fields.PasswordFieldRenderer)
             if klass is schema.Text:
                 self._fields[name].set(renderer=fields.TextAreaFieldRenderer)
             if klass is schema.List:
                 value_type = self.iface[name].value_type
                 if isinstance(value_type, schema.Choice):
                     self._fields[name].set(options=value_type, multiple=True)
                 else:
                     self._fields[name].set(multiple=True)
             elif klass is schema.Choice:
                 self._fields[name].set(renderer=fields.SelectFieldRenderer, options=self.iface[name])
Beispiel #3
0
    def insert_after(self, field, new_field):
        """Insert a new field *after* an existing field.

        Use this if your business logic requires to add after a certain field,
        and not before.
        """
        fields_ = self._render_fields or self._fields
        if not isinstance(new_field, fields.Field):
            raise ValueError("Can only add Field objects; got %s instead" % field)
        if isinstance(field, fields.AbstractField):
            try:
                index = fields_.keys().index(field.name)
            except ValueError:
                raise ValueError("%s not in fields" % field.name)
        else:
            raise TypeError("field must be a Field. Got %r" % field)
        new_field.parent = self
        items = list(fields_.iteritems())
        new_item = (new_field.name, new_field)
        if index + 1 == len(items):  # after the last element ?
            items.append(new_item)
        else:
            items.insert(index + 1, new_item)
        if self._render_fields:
            self._render_fields = OrderedDict(items)
        else:
            self._fields = OrderedDict(items)
Beispiel #4
0
    def pkg_xl_dict_to_fs_dict(cls, pkg_xl_dict, logger=None):
        """Convert a Package represented in an Excel-type dictionary to a
        dictionary suitable for fieldset data.
        Takes Excel-type dict:
            {'name':'wikipedia', 
             'resource-0-url':'http://static.wikipedia.org/'}
        Returns Fieldset-type dict:
            {'name':'wikipedia',
             'resources':[{'url':'http://static.wikipedia.org/'}]}
        """
        import ckan.forms

        standard_fields = model.Package.get_fields()

        pkg_fs_dict = OrderedDict()
        for title, cell in pkg_xl_dict.items():
            if cell:
                if title in standard_fields:
                    pkg_fs_dict[title] = cell
                elif title == "license":
                    license_id = cls.license_2_license_id(cell)
                    if license:
                        pkg_fs_dict["license_id"] = license_id
                    else:
                        logger("Warning: No license name matches '%s'. Ignoring license." % cell)
                elif title.startswith("resource-"):
                    match = re.match("resource-(\d+)-(\w+)", title)
                    if match:
                        res_index, field = match.groups()
                        res_index = int(res_index)
                        field = str(field)
                        if not pkg_fs_dict.has_key("resources"):
                            pkg_fs_dict["resources"] = []
                        resources = pkg_fs_dict["resources"]
                        num_new_resources = 1 + res_index - len(resources)
                        for i in range(num_new_resources):
                            blank_dict = OrderedDict()
                            for blank_field in model.Resource.get_columns():
                                blank_dict[blank_field] = u""
                            pkg_fs_dict["resources"].append(blank_dict)

                        pkg_fs_dict["resources"][res_index][field] = cell
                    else:
                        logger("Warning: Could not understand resource title '%s'. Ignoring value: %s" % (title, cell))
                elif title.startswith("relationships"):
                    # TODO
                    pass
                elif title == "download_url":
                    # deprecated - only in there for compatibility
                    pass
                elif title in readonly_keys:
                    pass
                else:
                    if not pkg_fs_dict.has_key("extras"):
                        pkg_fs_dict["extras"] = {}
                    pkg_fs_dict["extras"][title] = cell
        return pkg_fs_dict
Beispiel #5
0
 def records(self):
     """Returns each record as a dict."""
     for row_index in range(self._first_record_row, self._data.get_num_rows()):
         row = self._data.get_row(row_index)
         row_has_content = False
         for cell in row:
             if cell:
                 row_has_content = True
                 break
         if row_has_content:
             record_dict = OrderedDict(zip(self.titles, row))
             if record_dict.has_key(None):
                 del record_dict[None]
             yield record_dict
Beispiel #6
0
    def _grab_table_elements(self):
        schema = self.table.schema
        self.columns = OrderedDict()
        for c in self.table.c:
            c_copy = c.copy(schema=schema)
            c_copy.unique = c_copy.index = False
            # ensure that the type object was copied,
            # as we may need to modify it in-place
            if isinstance(c.type, SchemaEventTarget):
                assert c_copy.type is not c.type
            self.columns[c.name] = c_copy
        self.named_constraints = {}
        self.unnamed_constraints = []
        self.indexes = {}
        self.new_indexes = {}
        for const in self.table.constraints:
            if _is_type_bound(const):
                continue
            elif const.name:
                self.named_constraints[const.name] = const
            else:
                self.unnamed_constraints.append(const)

        for idx in self.table.indexes:
            self.indexes[idx.name] = idx

        for k in self.table.kwargs:
            self.table_kwargs.setdefault(k, self.table.kwargs[k])
Beispiel #7
0
 def __init__(self, table_name, columns=None):
     self.table_name = table_name
     self._options = {}
     self._annot = OrderedDict()
     if columns:
         for info in columns:
             self._annot[info["name"]] = info
Beispiel #8
0
    def create_title_mapping(self):
        """Creates a mapping between the spreadsheet\'s actual column
        titles and the normalised versions.

        Results in self.title_map and self.title_reverse_map which are
        comprehensive for this spreadsheet.

        """
        self.title_map = OrderedDict()
        for title in self.titles:
            for norm_title, regex in self.title_normaliser:
                if regex.match(title):
                    self.title_map[title] = norm_title
                    break
            else:
                raise AssertionError("Did not recognise title: %r" % title)
        self.title_reverse_map = dict((v, k) for k, v in self.title_map.iteritems())
        # check all keys map both ways
        unmatched_keys = set(self.title_map.keys()) - set(self.title_reverse_map.values())
        if unmatched_keys:
            msg = "Columns not identified by REs: %r" % (
                set(self.title_map.keys()) - set(self.title_reverse_map.values())
            )
            msg += "\nColumns over identified by REs: %r" % (
                set(self.title_reverse_map.keys()) - set(self.title_map.values())
            )
            raise AssertionError(msg)
Beispiel #9
0
 def __init__(self, table, table_args, table_kwargs):
     self.table = table  # this is a Table object
     self.table_args = table_args
     self.table_kwargs = table_kwargs
     self.new_table = None
     self.column_transfers = OrderedDict((c.name, {"expr": c}) for c in self.table.c)
     self._grab_table_elements()
Beispiel #10
0
    def __init__(self, table, association_tables, inflect_engine, detect_joined):
        super(ModelClass, self).__init__(table)
        self.name = self._tablename_to_classname(table.name, inflect_engine)
        self.children = []
        self.attributes = OrderedDict()

        # Assign attribute names for columns
        for column in table.columns:
            self._add_attribute(column.name, column)

        # Add many-to-one relationships
        pk_column_names = set(col.name for col in table.primary_key.columns)
        for constraint in sorted(table.constraints, key=_get_constraint_sort_key):
            if isinstance(constraint, ForeignKeyConstraint):
                target_cls = self._tablename_to_classname(constraint.elements[0].column.table.name, inflect_engine)
                if detect_joined and self.parent_name == "Base" and set(constraint.columns) == pk_column_names:
                    self.parent_name = target_cls
                else:
                    relationship_ = ManyToOneRelationship(self.name, target_cls, constraint, inflect_engine)
                    self._add_attribute(relationship_.preferred_name, relationship_)

        # Add many-to-many relationships
        for association_table in association_tables:
            fk_constraints = [c for c in association_table.constraints if isinstance(c, ForeignKeyConstraint)]
            fk_constraints.sort(key=_get_constraint_sort_key)
            target_cls = self._tablename_to_classname(fk_constraints[1].elements[0].column.table.name, inflect_engine)
            relationship_ = ManyToManyRelationship(self.name, target_cls, association_table, inflect_engine)
            self._add_attribute(relationship_.preferred_name, relationship_)
Beispiel #11
0
 def render_fields(self):
     """
     The set of attributes that will be rendered, as a (ordered)
     dict of `{fieldname: Field}` pairs
     """
     if not self._render_fields:
         self._render_fields = OrderedDict([(field.key, field) for field in self._get_fields()])
     return self._render_fields
Beispiel #12
0
 def __init__(self, model, session=None, data=None, prefix=None):
     self._fields = OrderedDict()
     self._render_fields = OrderedDict()
     self.model = self.session = None
     BaseFieldSet.rebind(self, model, data=data)
     self.prefix = prefix
     self.model = model
     self.readonly = False
     self.focus = True
     self._errors = []
     focus = True
     for k, v in model.__dict__.iteritems():
         if not k.startswith("_"):
             descriptor = type(v)
             t = self._mapping.get(descriptor)
             if t:
                 self.append(Field(name=k, type=t))
Beispiel #13
0
class TableAnnotation(object):
    """
    Annotations for Table objects, to annotate as needed, the notion
    is that the annotation keys correspond to column, and values correspond
    to application specific column metadata.
    """

    _marker = object()
    schema_invariants = ()

    def __init__(self, table_name, columns=(), properties=(), schema_order=(), listing_columns=(), order_by=()):
        self.table_name = table_name
        self._options = {}
        self._annot = OrderedDict()

        for info in columns:
            self._annot[info["name"]] = info

        self.properties = properties
        self.schema_order = schema_order
        self.listing_columns = listing_columns
        self.order_by = order_by

    def setOption(self, name, value):
        self._options[name] = value

    def getOption(self, name, default=None):
        return self._options.get(name, default)

    def __call__(self, iface):
        return self

    def __setitem__(self, name, value):
        self._annot[name] = value

    def get(self, name, default=None):
        return self._annot.get(name, default)

    def __getitem__(self, name):
        return self.get(name)

    def values(self):
        return self._annot.values()

    def __contains__(self, name):
        return not self._marker == self.get(name, self._marker)
Beispiel #14
0
    def __init__(self):
        self._start_time = datetime.now()
        self._total_time = None

        self.from_cache = None

        # SQLAlchemy will add to these using the above event listeners; see
        # spline.config.environment
        self.sql_time = timedelta()
        self.sql_queries = 0
        self.sql_query_log = OrderedDict()
Beispiel #15
0
class TableAnnotation(object):

    # __slots__ = ("table_name", "_annot", "_options")

    def __init__(self, table_name, columns=(), properties=(), schema_order=(), table_columns=(), order_by=()):
        self.table_name = table_name
        self._options = {}
        self._annot = OrderedDict()

        for info in columns:
            self._annot[info["name"]] = info

        self.properties = properties
        self.schema_order = schema_order
        self.table_columns = table_columns
        self.order_by = order_by

    def setOption(self, name, value):
        self._options[name] = value

    def getOption(self, name, default=None):
        return self._options.get(name, default)

    def __call__(self, context):
        return ModelAnnotation(context, self)

    def __setitem__(self, name, value):
        self._annot[name] = value

    def get(self, name, default=None):
        return self._annot.get(name, default)

    def __getitem__(self, anme):
        return self.get(name)

    def values(self):
        return self._annot.values()

    def __contains__(self, name):
        marker = object()
        return not marker == self.get(name, marker)
Beispiel #16
0
    def __init__(self, table_name, columns=(), properties=(), schema_order=(), table_columns=(), order_by=()):
        self.table_name = table_name
        self._options = {}
        self._annot = OrderedDict()

        for info in columns:
            self._annot[info["name"]] = info

        self.properties = properties
        self.schema_order = schema_order
        self.table_columns = table_columns
        self.order_by = order_by
 def __init__(self, model, session=None, data=None, prefix=None):
     self._fields = OrderedDict()
     self._render_fields = OrderedDict()
     self.model = self.session = None
     BaseFieldSet.rebind(self, model, data=data)
     self.prefix = prefix
     self.model = model
     self.readonly = False
     self.focus = True
     self._errors = []
     focus = True
     for k, v in model().iteritems():
         if not k.startswith("_"):
             try:
                 t = getattr(fatypes, v.__class__.__name__.replace("Property", ""))
             except AttributeError:
                 raise NotImplementedError("%s is not mapped to a type" % v.__class__)
             else:
                 self.add(Field(name=k, type=t))
                 if v.required:
                     self._fields[k].validators.append(validators.required)
 def __init__(self, model, session=None, data=None, prefix=None):
     self._fields = OrderedDict()
     self._render_fields = OrderedDict()
     self.model = self.session = None
     self.prefix = prefix
     self.model = model
     self.readonly = False
     self.focus = True
     self._errors = []
     self.iface = model
     focus = True
     for name, field in schema.getFieldsInOrder(model):
         try:
             t = FIELDS_MAPPING[field.__class__]
         except KeyError:
             raise NotImplementedError("%s is not mapped to a type" % field.__class__)
         else:
             self.add(Field(name=name, type=t))
             if field.title:
                 self._fields[name].label_text = field.title
             if field.required:
                 self._fields[name].validators.append(validators.required)
Beispiel #19
0
 def reconfigure(
     self, pk=False, focus=True, readonly=False, global_validator=None, exclude=[], include=[], options=[]
 ):
     """
     Like `configure`, but does not undo the effects of a previous call
     to `configure` or `reconfigure`.
     """
     self.focus = focus
     self.readonly = readonly
     self.validator = global_validator
     self._render_fields = OrderedDict(
         [(field.key, field) for field in self._get_fields(pk, exclude, include, options, use_rendered=True)]
     )
    def __init__(self, engine=None):
        self._tables = OrderedDict()
        self._peer_factories = {}

        self.engine = engine or ProxyEngine()
        self.generateDefaults()

        self.serializer = self.serializer_factory(self)

        # rebind
        self.ident_translate = self.translator_factory.ident_translate
        self.saveObject = self.serializer.saveObject
        self.deleteObject = self.serializer.deleteObject
Beispiel #21
0
    def insert(self, field, new_field):
        """Insert a new field *before* an existing field.

        This is like the normal ``insert()`` function of ``list`` objects. It
        takes the place of the previous element, and pushes the rest forward.
        """
        fields_ = self._render_fields or self._fields
        if not isinstance(new_field, fields.Field):
            raise ValueError("Can only add Field objects; got %s instead" % field)
        if isinstance(field, fields.AbstractField):
            try:
                index = fields_.keys().index(field.name)
            except ValueError:
                raise ValueError("%s not in fields" % field.name)
        else:
            raise TypeError("field must be a Field. Got %r" % field)
        new_field.parent = self
        items = list(fields_.iteritems())  # prepare for Python 3
        items.insert(index, (new_field.name, new_field))
        if self._render_fields:
            self._render_fields = OrderedDict(items)
        else:
            self._fields = OrderedDict(items)
Beispiel #22
0
 def __init__(self, model, session=None, data=None, prefix=None):
     self._fields = OrderedDict()
     self._render_fields = OrderedDict()
     self.model = self.session = None
     self.prefix = prefix
     self.model = model
     self.readonly = False
     self.focus = True
     self._errors = []
     self._bound_pk = None
     self.data = None
     self.validator = None
     self.iface = model
     focus = True
     for name, field in schema.getFieldsInOrder(model):
         klass = field.__class__
         try:
             t = self._fields_mapping[klass]
         except KeyError:
             raise NotImplementedError("%s is not mapped to a type" % klass)
         else:
             self.append(Field(name=name, type=t))
             self._fields[name].label_text = field.title or name
             if field.description:
                 self._fields[name].set(instructions=field.description)
             if field.required:
                 self._fields[name].validators.append(validators.required)
             if klass is schema.Text:
                 self._fields[name].set(renderer=fields.TextAreaFieldRenderer)
             if klass is schema.List:
                 value_type = self.model[name].value_type
                 if isinstance(value_type, schema.Choice):
                     self._fields[name].set(options=value_type, multiple=True)
                 else:
                     self._fields[name].set(multiple=True)
             elif klass is schema.Choice:
                 self._fields[name].set(renderer=fields.SelectFieldRenderer, options=self.model[name])
Beispiel #23
0
class Relationship(object):
    def __init__(self, source_cls, target_cls):
        super(Relationship, self).__init__()
        self.source_cls = source_cls
        self.target_cls = target_cls
        self.kwargs = OrderedDict()

    def render(self):
        text = "relationship("
        args = [repr(self.target_cls)]

        if "secondaryjoin" in self.kwargs:
            text += "\n        "
            delimiter, end = ",\n        ", "\n    )"
        else:
            delimiter, end = ", ", ")"

        args.extend([key + "=" + value for key, value in self.kwargs.items()])
        return text + delimiter.join(args) + end
Beispiel #24
0
class Relationship(object):
    def __init__(self, source_cls, target_cls):
        super(Relationship, self).__init__()
        self.source_cls = source_cls
        self.target_cls = target_cls
        self.kwargs = OrderedDict()
        self.backref_name = _underscore(self.source_cls)

    def render(self):
        text = _flask_prepend + "relationship("
        args = [repr(self.target_cls)]

        if "secondaryjoin" in self.kwargs:
            text += "\n        "
            delimiter, end = ",\n        ", "\n    )"
        else:
            delimiter, end = ", ", ")"

        args.extend([key + "=" + value for key, value in self.kwargs.items()])
        return text + delimiter.join(args) + end

    def make_backref(self, relationships, classes):
        backref = self.backref_name
        original_backref = backref
        # Check if backref already exists for relationship source_cls to target_cls and add suffix
        suffix = 0
        while (self.target_cls, backref) in [(x.target_cls, x.backref_name) for x in relationships]:
            backref = original_backref + str("_{0}".format(suffix))
            suffix += 1

        self.kwargs["backref"] = repr(backref)
        # Check if any of the target_cls inherit from other target_cls
        # If so, modify backref name of descendant
        # "backref({0}, lazy='dynamic')".format(repr(backref))
        for rel in [x for x in relationships if "backref" in x.kwargs]:
            if self.target_cls in classes and rel.target_cls in classes:
                if _is_model_descendant(classes[self.target_cls], classes[rel.target_cls]):
                    self.backref_name = self.target_cls.lower() + "_" + backref
                    self.kwargs["backref"] = repr(self.backref_name)
                if _is_model_descendant(classes[rel.target_cls], classes[self.target_cls]):
                    backref = rel.backref_name
                    rel.backref_name = rel.target_cls.lower() + "_" + backref
                    rel.kwargs["backref"] = repr(rel.backref_name)
Beispiel #25
0
    def _grab_table_elements(self):
        schema = self.table.schema
        self.columns = OrderedDict()
        for c in self.table.c:
            c_copy = c.copy(schema=schema)
            c_copy.unique = c_copy.index = False
            self.columns[c.name] = c_copy
        self.named_constraints = {}
        self.unnamed_constraints = []
        self.indexes = {}
        for const in self.table.constraints:
            if _is_type_bound(const):
                continue
            if const.name:
                self.named_constraints[const.name] = const
            else:
                self.unnamed_constraints.append(const)

        for idx in self.table.indexes:
            self.indexes[idx.name] = idx
Beispiel #26
0
class FieldSet(BaseFieldSet):
    """FieldSet aware of zope schema. See :class:`formalchemy.forms.FieldSet` for full api."""

    __sa__ = False
    _fields_mapping = {
        schema.TextLine: fatypes.Unicode,
        schema.Text: fatypes.Unicode,
        schema.Int: fatypes.Integer,
        schema.Bool: fatypes.Boolean,
        schema.Float: fatypes.Float,
        schema.Date: fatypes.Date,
        schema.Datetime: fatypes.DateTime,
        schema.Time: fatypes.Time,
        schema.Choice: fatypes.Unicode,
        schema.List: fatypes.List,
        schema.Password: fatypes.Unicode,
    }

    def __init__(self, model, **kwargs):
        BaseFieldSet.__init__(self, model, **kwargs)
        self.iface = model
        self.rebind(model)
        self._fields = OrderedDict()
        self._render_fields = OrderedDict()
        self._bound_pk = None
        for name, field in schema.getFieldsInOrder(self.iface):
            klass = field.__class__
            try:
                t = self._fields_mapping[klass]
            except KeyError:
                raise NotImplementedError("%s is not mapped to a type" % klass)
            else:
                self.append(Field(name=name, type=t))
                self._fields[name].label_text = field.title or name
                if field.description:
                    self._fields[name].set(instructions=field.description)
                if field.required:
                    self._fields[name].validators.append(validators.required)
                if klass is schema.Password:
                    self._fields[name].set(renderer=fields.PasswordFieldRenderer)
                if klass is schema.Text:
                    self._fields[name].set(renderer=fields.TextAreaFieldRenderer)
                if klass is schema.List:
                    value_type = self.iface[name].value_type
                    if isinstance(value_type, schema.Choice):
                        self._fields[name].set(options=value_type, multiple=True)
                    else:
                        self._fields[name].set(multiple=True)
                elif klass is schema.Choice:
                    self._fields[name].set(renderer=fields.SelectFieldRenderer, options=self.iface[name])

    def bind(self, model, session=None, data=None, request=None):
        if not (model is not None or session or data):
            raise Exception("must specify at least one of {model, session, data}")
        # copy.copy causes a stacktrace on python 2.5.2/OSX + pylons.  unable to reproduce w/ simpler sample.
        mr = object.__new__(self.__class__)
        mr.__dict__ = dict(self.__dict__)
        # two steps so bind's error checking can work
        mr.rebind(model, session, data)
        mr._request = request
        mr._fields = OrderedDict([(key, renderer.bind(mr)) for key, renderer in self._fields.items()])
        if self._render_fields:
            mr._render_fields = OrderedDict(
                [(field.key, field) for field in [field.bind(mr) for field in self._render_fields.values()]]
            )
        return mr

    def gen_model(self, model=None, dict_like=False, **kwargs):
        if model and self.iface.providedBy(model):
            return model
        factory = gen_model(self.iface, model, dict_like=dict_like)
        model = factory(context=model, **kwargs)
        return model

    def rebind(self, model, session=None, data=None):
        if model is not self.iface:
            if model and not self.iface.providedBy(model):
                if getattr(model, "__implemented__", None) is not None:
                    raise ValueError("%r does not provide %r" % (model, self.iface))
                model = self.gen_model(model)
        self.model = model
        self._bound_pk = fields._pk(model)
        if data is None:
            self.data = None
        elif hasattr(data, "getall") and hasattr(data, "getone"):
            self.data = data
        else:
            try:
                self.data = SimpleMultiDict(data)
            except:
                raise Exception(
                    "unsupported data object %s. currently only dicts and Paste multidicts are supported" % self.data
                )
Beispiel #27
0
class ApplyBatchImpl(object):
    def __init__(self, table, table_args, table_kwargs):
        self.table = table  # this is a Table object
        self.table_args = table_args
        self.table_kwargs = table_kwargs
        self.new_table = None
        self.column_transfers = OrderedDict((c.name, {"expr": c}) for c in self.table.c)
        self._grab_table_elements()

    def _grab_table_elements(self):
        schema = self.table.schema
        self.columns = OrderedDict()
        for c in self.table.c:
            c_copy = c.copy(schema=schema)
            c_copy.unique = c_copy.index = False
            self.columns[c.name] = c_copy
        self.named_constraints = {}
        self.unnamed_constraints = []
        self.indexes = {}
        for const in self.table.constraints:
            if _is_type_bound(const):
                continue
            if const.name:
                self.named_constraints[const.name] = const
            else:
                self.unnamed_constraints.append(const)

        for idx in self.table.indexes:
            self.indexes[idx.name] = idx

    def _transfer_elements_to_new_table(self):
        assert self.new_table is None, "Can only create new table once"

        m = MetaData()
        schema = self.table.schema
        self.new_table = new_table = Table(
            "_alembic_batch_temp",
            m,
            *(list(self.columns.values()) + list(self.table_args)),
            schema=schema,
            **self.table_kwargs
        )

        for const in list(self.named_constraints.values()) + self.unnamed_constraints:

            const_columns = set([c.key for c in _columns_for_constraint(const)])

            if not const_columns.issubset(self.column_transfers):
                continue
            const_copy = const.copy(schema=schema, target_table=new_table)
            if isinstance(const, ForeignKeyConstraint):
                self._setup_referent(m, const)
            new_table.append_constraint(const_copy)

        for index in self.indexes.values():
            Index(index.name, unique=index.unique, *[new_table.c[col] for col in index.columns.keys()], **index.kwargs)

    def _setup_referent(self, metadata, constraint):
        spec = constraint.elements[0]._get_colspec()
        parts = spec.split(".")
        tname = parts[-2]
        if len(parts) == 3:
            referent_schema = parts[0]
        else:
            referent_schema = None
        if tname != "_alembic_batch_temp":
            key = sql_schema._get_table_key(tname, referent_schema)
            if key in metadata.tables:
                t = metadata.tables[key]
                for elem in constraint.elements:
                    colname = elem._get_colspec().split(".")[-1]
                    if not t.c.contains_column(colname):
                        t.append_column(Column(colname, sqltypes.NULLTYPE))
            else:
                Table(
                    tname,
                    metadata,
                    *[
                        Column(n, sqltypes.NULLTYPE)
                        for n in [elem._get_colspec().split(".")[-1] for elem in constraint.elements]
                    ],
                    schema=referent_schema
                )

    def _create(self, op_impl):
        self._transfer_elements_to_new_table()

        op_impl.prep_table_for_batch(self.table)
        op_impl.create_table(self.new_table)

        try:
            op_impl._exec(
                self.new_table.insert(inline=True).from_select(
                    list(k for k, transfer in self.column_transfers.items() if "expr" in transfer),
                    select([transfer["expr"] for transfer in self.column_transfers.values() if "expr" in transfer]),
                )
            )
            op_impl.drop_table(self.table)
        except:
            op_impl.drop_table(self.new_table)
            raise
        else:
            op_impl.rename_table("_alembic_batch_temp", self.table.name, schema=self.table.schema)

    def alter_column(
        self,
        table_name,
        column_name,
        nullable=None,
        server_default=False,
        name=None,
        type_=None,
        autoincrement=None,
        **kw
    ):
        existing = self.columns[column_name]
        existing_transfer = self.column_transfers[column_name]
        if name is not None and name != column_name:
            # note that we don't change '.key' - we keep referring
            # to the renamed column by its old key in _create().  neat!
            existing.name = name
            existing_transfer["name"] = name

        if type_ is not None:
            type_ = sqltypes.to_instance(type_)
            existing.type = type_
            existing_transfer["expr"] = cast(existing_transfer["expr"], type_)
        if nullable is not None:
            existing.nullable = nullable
        if server_default is not False:
            existing.server_default = server_default
        if autoincrement is not None:
            existing.autoincrement = bool(autoincrement)

    def add_column(self, table_name, column, **kw):
        # we copy the column because operations.add_column()
        # gives us a Column that is part of a Table already.
        self.columns[column.name] = column.copy(schema=self.table.schema)
        self.column_transfers[column.name] = {}

    def drop_column(self, table_name, column, **kw):
        del self.columns[column.name]
        del self.column_transfers[column.name]

    def add_constraint(self, const):
        if not const.name:
            raise ValueError("Constraint must have a name")
        self.named_constraints[const.name] = const

    def drop_constraint(self, const):
        if not const.name:
            raise ValueError("Constraint must have a name")
        try:
            del self.named_constraints[const.name]
        except KeyError:
            raise ValueError("No such constraint: '%s'" % const.name)

    def add_index(self, idx):
        self.indexes[idx.name] = idx

    def drop_index(self, idx):
        try:
            del self.indexes[idx.name]
        except KeyError:
            raise ValueError("No such index: '%s'" % idx.name)

    def rename_table(self, *arg, **kw):
        raise NotImplementedError("TODO")
Beispiel #28
0
 def __init__(self, keyfunc):
     MappedCollection.__init__(self, keyfunc)
     OrderedDict.__init__(self)  # @UndefinedVariable
Beispiel #29
0
class ApplyBatchImpl(object):
    def __init__(self, table, table_args, table_kwargs):
        self.table = table  # this is a Table object
        self.table_args = table_args
        self.table_kwargs = table_kwargs
        self.new_table = None
        self.column_transfers = OrderedDict((c.name, {"expr": c}) for c in self.table.c)
        self._grab_table_elements()

    def _grab_table_elements(self):
        schema = self.table.schema
        self.columns = OrderedDict()
        for c in self.table.c:
            c_copy = c.copy(schema=schema)
            c_copy.unique = c_copy.index = False
            # ensure that the type object was copied,
            # as we may need to modify it in-place
            if isinstance(c.type, SchemaEventTarget):
                assert c_copy.type is not c.type
            self.columns[c.name] = c_copy
        self.named_constraints = {}
        self.unnamed_constraints = []
        self.indexes = {}
        self.new_indexes = {}
        for const in self.table.constraints:
            if _is_type_bound(const):
                continue
            elif const.name:
                self.named_constraints[const.name] = const
            else:
                self.unnamed_constraints.append(const)

        for idx in self.table.indexes:
            self.indexes[idx.name] = idx

        for k in self.table.kwargs:
            self.table_kwargs.setdefault(k, self.table.kwargs[k])

    def _transfer_elements_to_new_table(self):
        assert self.new_table is None, "Can only create new table once"

        m = MetaData()
        schema = self.table.schema

        self.new_table = new_table = Table(
            "_alembic_batch_temp",
            m,
            *(list(self.columns.values()) + list(self.table_args)),
            schema=schema,
            **self.table_kwargs
        )

        for const in list(self.named_constraints.values()) + self.unnamed_constraints:

            const_columns = set([c.key for c in _columns_for_constraint(const)])

            if not const_columns.issubset(self.column_transfers):
                continue

            if isinstance(const, ForeignKeyConstraint):
                if _fk_is_self_referential(const):
                    # for self-referential constraint, refer to the
                    # *original* table name, and not _alembic_batch_temp.
                    # This is consistent with how we're handling
                    # FK constraints from other tables; we assume SQLite
                    # no foreign keys just keeps the names unchanged, so
                    # when we rename back, they match again.
                    const_copy = const.copy(schema=schema, target_table=self.table)
                else:
                    # "target_table" for ForeignKeyConstraint.copy() is
                    # only used if the FK is detected as being
                    # self-referential, which we are handling above.
                    const_copy = const.copy(schema=schema)
            else:
                const_copy = const.copy(schema=schema, target_table=new_table)
            if isinstance(const, ForeignKeyConstraint):
                self._setup_referent(m, const)
            new_table.append_constraint(const_copy)

    def _gather_indexes_from_both_tables(self):
        idx = []
        idx.extend(self.indexes.values())
        for index in self.new_indexes.values():
            idx.append(
                Index(
                    index.name,
                    unique=index.unique,
                    *[self.new_table.c[col] for col in index.columns.keys()],
                    **index.kwargs
                )
            )
        return idx

    def _setup_referent(self, metadata, constraint):
        spec = constraint.elements[0]._get_colspec()
        parts = spec.split(".")
        tname = parts[-2]
        if len(parts) == 3:
            referent_schema = parts[0]
        else:
            referent_schema = None

        if tname != "_alembic_batch_temp":
            key = sql_schema._get_table_key(tname, referent_schema)
            if key in metadata.tables:
                t = metadata.tables[key]
                for elem in constraint.elements:
                    colname = elem._get_colspec().split(".")[-1]
                    if not t.c.contains_column(colname):
                        t.append_column(Column(colname, sqltypes.NULLTYPE))
            else:
                Table(
                    tname,
                    metadata,
                    *[
                        Column(n, sqltypes.NULLTYPE)
                        for n in [elem._get_colspec().split(".")[-1] for elem in constraint.elements]
                    ],
                    schema=referent_schema
                )

    def _create(self, op_impl):
        self._transfer_elements_to_new_table()

        op_impl.prep_table_for_batch(self.table)
        op_impl.create_table(self.new_table)

        try:
            op_impl._exec(
                self.new_table.insert(inline=True).from_select(
                    list(k for k, transfer in self.column_transfers.items() if "expr" in transfer),
                    select([transfer["expr"] for transfer in self.column_transfers.values() if "expr" in transfer]),
                )
            )
            op_impl.drop_table(self.table)
        except:
            op_impl.drop_table(self.new_table)
            raise
        else:
            op_impl.rename_table("_alembic_batch_temp", self.table.name, schema=self.table.schema)
            self.new_table.name = self.table.name
            try:
                for idx in self._gather_indexes_from_both_tables():
                    op_impl.create_index(idx)
            finally:
                self.new_table.name = "_alembic_batch_temp"

    def alter_column(
        self,
        table_name,
        column_name,
        nullable=None,
        server_default=False,
        name=None,
        type_=None,
        autoincrement=None,
        **kw
    ):
        existing = self.columns[column_name]
        existing_transfer = self.column_transfers[column_name]
        if name is not None and name != column_name:
            # note that we don't change '.key' - we keep referring
            # to the renamed column by its old key in _create().  neat!
            existing.name = name
            existing_transfer["name"] = name

        if type_ is not None:
            type_ = sqltypes.to_instance(type_)
            # old type is being discarded so turn off eventing
            # rules. Alternatively we can
            # erase the events set up by this type, but this is simpler.
            # we also ignore the drop_constraint that will come here from
            # Operations.implementation_for(alter_column)
            if isinstance(existing.type, SchemaEventTarget):
                existing.type._create_events = existing.type.create_constraint = False

            existing.type = type_

            # we *dont* however set events for the new type, because
            # alter_column is invoked from
            # Operations.implementation_for(alter_column) which already
            # will emit an add_constraint()

            existing_transfer["expr"] = cast(existing_transfer["expr"], type_)
        if nullable is not None:
            existing.nullable = nullable
        if server_default is not False:
            if server_default is None:
                existing.server_default = None
            else:
                sql_schema.DefaultClause(server_default)._set_parent(existing)
        if autoincrement is not None:
            existing.autoincrement = bool(autoincrement)

    def add_column(self, table_name, column, **kw):
        # we copy the column because operations.add_column()
        # gives us a Column that is part of a Table already.
        self.columns[column.name] = column.copy(schema=self.table.schema)
        self.column_transfers[column.name] = {}

    def drop_column(self, table_name, column, **kw):
        del self.columns[column.name]
        del self.column_transfers[column.name]

    def add_constraint(self, const):
        if not const.name:
            raise ValueError("Constraint must have a name")
        if isinstance(const, sql_schema.PrimaryKeyConstraint):
            if self.table.primary_key in self.unnamed_constraints:
                self.unnamed_constraints.remove(self.table.primary_key)

        self.named_constraints[const.name] = const

    def drop_constraint(self, const):
        if not const.name:
            raise ValueError("Constraint must have a name")
        try:
            del self.named_constraints[const.name]
        except KeyError:
            if _is_type_bound(const):
                # type-bound constraints are only included in the new
                # table via their type object in any case, so ignore the
                # drop_constraint() that comes here via the
                # Operations.implementation_for(alter_column)
                return
            raise ValueError("No such constraint: '%s'" % const.name)

    def create_index(self, idx):
        self.new_indexes[idx.name] = idx

    def drop_index(self, idx):
        try:
            del self.indexes[idx.name]
        except KeyError:
            raise ValueError("No such index: '%s'" % idx.name)

    def rename_table(self, *arg, **kw):
        raise NotImplementedError("TODO")
Beispiel #30
0
class FieldSet(BaseFieldSet):
    _mapping = {
        descriptors.rdfSingle: fatypes.String,
        descriptors.rdfMultiple: fatypes.List,
        descriptors.rdfList: fatypes.List,
    }

    def __init__(self, model, session=None, data=None, prefix=None):
        self._fields = OrderedDict()
        self._render_fields = OrderedDict()
        self.model = self.session = None
        BaseFieldSet.rebind(self, model, data=data)
        self.prefix = prefix
        self.model = model
        self.readonly = False
        self.focus = True
        self._errors = []
        focus = True
        for k, v in model.__dict__.iteritems():
            if not k.startswith("_"):
                descriptor = type(v)
                t = self._mapping.get(descriptor)
                if t:
                    self.append(Field(name=k, type=t))

    def bind(self, model=None, session=None, data=None):
        """Bind to an instance"""
        if not (model or session or data):
            raise Exception("must specify at least one of {model, session, data}")
        if not model:
            if not self.model:
                raise Exception("model must be specified when none is already set")
            else:
                model = self.model()
        # copy.copy causes a stacktrace on python 2.5.2/OSX + pylons.  unable to reproduce w/ simpler sample.
        mr = object.__new__(self.__class__)
        mr.__dict__ = dict(self.__dict__)
        # two steps so bind's error checking can work
        mr.rebind(model, session, data)
        mr._fields = OrderedDict([(key, renderer.bind(mr)) for key, renderer in self._fields.iteritems()])
        if self._render_fields:
            mr._render_fields = OrderedDict(
                [(field.key, field) for field in [field.bind(mr) for field in self._render_fields.itervalues()]]
            )
        return mr

    def rebind(self, model, session=None, data=None):
        if model:
            if isinstance(model, type):
                try:
                    model = model()
                except:
                    raise Exception(
                        "%s appears to be a class, not an instance, but FormAlchemy cannot instantiate it.  (Make sure all constructor parameters are optional!)"
                        % model
                    )
            self.model = model
            self._bound_pk = None
        if data is None:
            self.data = None
        elif hasattr(data, "getall") and hasattr(data, "getone"):
            self.data = data
        else:
            try:
                self.data = SimpleMultiDict(data)
            except:
                raise Exception(
                    "unsupported data object %s.  currently only dicts and Paste multidicts are supported" % self.data
                )