def _construct_models(self): # only do this once if '_models' in self.__dict__: return # collect fields for all the models blueprints = copy.deepcopy(BASE_MODELS) from feedplatform import addins for addin in addins.get_addins(): if hasattr(addin, 'get_fields'): for table, new_fields in addin.get_fields().items(): if not table in blueprints: blueprints[table] = {} blueprints[table].update(new_fields) # "Unregister" current models from storm - otherwise we'll see stuff # like "PropertyPathError: Path 'feed_id' matches multiple properties". Storm._storm_property_registry.clear() # create the actual model objects new_models = {} for name, fields in blueprints.items(): table_options = config.TABLES.get(name) model_name = cap_model_name(name) attrs = {'__storm_table__': getattr(table_options, '__table__', name)} for field_name, field_value in fields.items(): if isinstance(field_value, tuple): klass, args, kwargs = field_value field_value = klass(*args, **kwargs) attrs[field_name] = field_value # user may want to map this field to a custom table column column_name = getattr(table_options, field_name, None) if column_name: attrs[field_name]._name = column_name model = type(model_name, (Storm,), attrs) new_models[model_name] = model # don't let invalid entries in config.TABLES go unnoticed # XXX: the whole config.TABLES code needs testing for model_name, table in config.TABLES.items(): model_name = cap_model_name(model_name) if not model_name in new_models: raise ValueError('Failed to process TABLES setting: ' '"%s" is not a valid model name' % model_name) self._models = new_models
def get_commands(): """Returns a dictionary mapping all available command names to either a Command class, or the module name in which the command class is defined. Commands can be defined: - in ``feedplatform/management/commands``, each file representing an individual command. - by addins. The list is loaded once, and then cached. """ global _COMMANDS if _COMMANDS is None: _COMMANDS = {} # load from filesystem try: command_dir = os.path.join(__path__[0], "commands") _COMMANDS.update( dict( [ (file[:-3], "feedplatform.management.commands") for file in os.listdir(command_dir) if not file.startswith("_") and file.endswith(".py") ] ) ) except OSError: pass # load from addins for addin in get_addins(): if hasattr(addin, "get_commands"): _COMMANDS.update(addin.get_commands()) return _COMMANDS
def handle(self, *args, **options): # setup the log according to the options requested loglevel = options.get('level') if loglevel: try: loglevel = logging._levelNames[loglevel.upper()] except KeyError: raise CommandError('invalid value for --level: %s' % loglevel) logfile = options.get('log') if logfile: filehandler = logging.FileHandler(logfile) filehandler.setFormatter(logging.Formatter( '%(asctime)-18s %(name)-12s: %(levelname)-8s %(message)s', '%m-%d-%y %H:%M:%S')) handlers=[filehandler] else: handlers = None if loglevel or handlers: log.reset(level=loglevel, handlers=handlers) # determine which daemons are available, and which one to run # TODO: better handle duplicate names named_daemons = {} unnamed_daemons = [] for addin in addins.get_addins(): if isinstance(addin, base_daemon): if addin.name: named_daemons[addin.name] = addin else: unnamed_daemons.append(addin) args = list(args) # make mutable if len(named_daemons) + len(unnamed_daemons) == 1: # If only one daemon is available, we can start it pretty # much right away. if named_daemons and args and named_daemons.keys()[0] == args[0]: # If the user specified the only existing daemon by # name, we make sure that name is not passed along # as a subargument to the daemon itself. args.remove(args[0]) daemon_to_start = unnamed_daemons and \ unnamed_daemons[0] or \ named_daemons.values()[0] # Otherwise, we have to determine which one the use wants to start else: s_daemon_list = '' for name in named_daemons.keys(): s_daemon_list += ' %s\n' % name if unnamed_daemons: s_daemon_list += 'Additionally, %d unnamed daemons are '+\ 'installed.\n' % len(unnamed_daemons) if len(args) == 0: raise CommandError('multiple daemons are installed, you ' 'need to specify which one to run:\n%s' % s_daemon_list) else: daemon_name = args[0] args.remove(args[0]) if not daemon_name in named_daemons: raise CommandError('"%s" is not a known daemon, '+ 'installed are:\n%s' % s_daemon_list) else: daemon_to_start = named_daemons[daemon_name] # fork off as daemon, if requested if options.get('daemonize'): if os.name != 'posix': raise CommandError('--daemonize not supported on this platform') daemon.daemonize() try: # If daemon threads make trouble (http://bugs.python.org/issue1856), # we can always disable it. It's there for convenience's sake, # but our daemons/threads have a stop-flag mechanism that should # work just fine as well. # TODO: parse the rest of the args, pass along as args/options daemon_to_start.start(daemon=True) while daemon_to_start.isAlive(): # join with a timeout, so KeyboardInterrupts get through daemon_to_start.join(DEFAULT_LOOP_SLEEP) except KeyboardInterrupt: daemon_to_start.stop()