Пример #1
0
 def transitive_dependencies(field, seen=[]):
     if field in seen:
         return
     for seq1 in dependencies[field]:
         yield seq1
         exceptions = (Exception,) if field.base_field.manual else ()
         with ignore(*exceptions):
             for seq2 in transitive_dependencies(seq1[-1], seen + [field]):
                 yield concat(seq1[:-1], seq2)
Пример #2
0
 def _mark_for_gc(self, fname):
     """ Add ``fname`` in a checklist for the filestore garbage collection. """
     # we use a spooldir: add an empty file in the subdirectory 'checklist'
     full_path = os.path.join(self._full_path('checklist'), fname)
     if not os.path.exists(full_path):
         dirname = os.path.dirname(full_path)
         if not os.path.isdir(dirname):
             with tools.ignore(OSError):
                 os.makedirs(dirname)
         open(full_path, 'ab').close()
Пример #3
0
    def _file_gc(self):
        """ Perform the garbage collection of the filestore. """
        if self._storage() != 'file':
            return

        # Continue in a new transaction. The LOCK statement below must be the
        # first one in the current transaction, otherwise the database snapshot
        # used by it may not contain the most recent changes made to the table
        # ir_attachment! Indeed, if concurrent transactions create attachments,
        # the LOCK statement will wait until those concurrent transactions end.
        # But this transaction will not see the new attachements if it has done
        # other requests before the LOCK (like the method _storage() above).
        cr = self._cr
        cr.commit()

        # prevent all concurrent updates on ir_attachment while collecting,
        # but only attempt to grab the lock for a little bit, otherwise it'd
        # start blocking other transactions. (will be retried later anyway)
        cr.execute("SET LOCAL lock_timeout TO '10s'")
        cr.execute("LOCK ir_attachment IN SHARE MODE")

        # retrieve the file names from the checklist
        checklist = {}
        for dirpath, _, filenames in os.walk(self._full_path('checklist')):
            dirname = os.path.basename(dirpath)
            for filename in filenames:
                fname = "%s/%s" % (dirname, filename)
                checklist[fname] = os.path.join(dirpath, filename)

        # determine which files to keep among the checklist
        whitelist = set()
        for names in cr.split_for_in_conditions(checklist):
            cr.execute(
                "SELECT store_fname FROM ir_attachment WHERE store_fname IN %s",
                [names])
            whitelist.update(row[0] for row in cr.fetchall())

        # remove garbage files, and clean up checklist
        removed = 0
        for fname, filepath in checklist.items():
            if fname not in whitelist:
                try:
                    os.unlink(self._full_path(fname))
                    removed += 1
                except (OSError, IOError):
                    _logger.info("_file_gc could not unlink %s",
                                 self._full_path(fname),
                                 exc_info=True)
            with tools.ignore(OSError):
                os.unlink(filepath)

        # commit to release the lock
        cr.commit()
        _logger.info("filestore gc %d checked, %d removed", len(checklist),
                     removed)
Пример #4
0
 def validate_numerical_box(self, post, answer_tag):
     self.ensure_one()
     errors = {}
     answer = post[answer_tag].strip()
     # Empty answer to mandatory question
     if self.constr_mandatory and not answer:
         errors.update({answer_tag: self.constr_error_msg})
     # Checks if user input is a number
     if answer:
         try:
             floatanswer = float(answer)
         except ValueError:
             errors.update({answer_tag: _('This is not a number')})
     # Answer validation (if properly defined)
     if answer and self.validation_required:
         # Answer is not in the right range
         with tools.ignore(Exception):
             floatanswer = float(
                 answer)  # check that it is a float has been done hereunder
             if not (self.validation_min_float_value <= floatanswer <=
                     self.validation_max_float_value):
                 errors.update({answer_tag: self.validation_error_msg})
     return errors
Пример #5
0
    def setup_models(self, cr):
        """ Complete the setup of models.
            This must be called after loading modules and before using the ORM.
        """
        lazy_property.reset_all(self)
        env = harpiya.api.Environment(cr, SUPERUSER_ID, {})

        if env.all.tocompute:
            _logger.error(
                "Remaining fields to compute before setting up registry: %s",
                env.all.tocompute, stack_info=True,
            )

        # add manual models
        if self._init_modules:
            env['ir.model']._add_manual_models()

        # prepare the setup on all models
        models = list(env.values())
        for model in models:
            model._prepare_setup()

        # do the actual setup from a clean state
        self._m2m = defaultdict(list)
        for model in models:
            model._setup_base()

        for model in models:
            model._setup_fields()

        # determine field dependencies
        dependencies = {}
        for model in models:
            if model._abstract:
                continue
            for field in model._fields.values():
                # dependencies of custom fields may not exist; ignore that case
                exceptions = (Exception,) if field.base_field.manual else ()
                with ignore(*exceptions):
                    dependencies[field] = set(field.resolve_depends(model))

        # determine transitive dependencies
        def transitive_dependencies(field, seen=[]):
            if field in seen:
                return
            for seq1 in dependencies[field]:
                yield seq1
                exceptions = (Exception,) if field.base_field.manual else ()
                with ignore(*exceptions):
                    for seq2 in transitive_dependencies(seq1[-1], seen + [field]):
                        yield concat(seq1[:-1], seq2)

        def concat(seq1, seq2):
            if seq1 and seq2:
                f1, f2 = seq1[-1], seq2[0]
                if f1.type == 'one2many' and f2.type == 'many2one' and \
                        f1.model_name == f2.comodel_name and f1.inverse_name == f2.name:
                    return concat(seq1[:-1], seq2[1:])
            return seq1 + seq2

        # determine triggers based on transitive dependencies
        triggers = {}
        for field in dependencies:
            for path in transitive_dependencies(field):
                if path:
                    tree = triggers
                    for label in reversed(path):
                        tree = tree.setdefault(label, {})
                    tree.setdefault(None, set()).add(field)

        self.field_triggers = triggers

        for model in models:
            model._setup_complete()

        self.registry_invalidated = True