示例#1
0
 def get_options(self):
     options = (
         Option(
             '-e',
             '--email',
             dest='email',
             nargs='*',
             help='One or more email addresses to send a test email to.'),
         Option(
             '-m',
             '--managers',
             dest='managers',
             action='store_true',
             help=
             'Send a test email to the addresses specified in settings.MANAGERS.'
         ),
         Option(
             '-a',
             '--admins',
             dest='admins',
             action='store_true',
             help=
             'Send a test email to the addresses specified in settings.ADMINS.'
         ),
     )
     return options
示例#2
0
 def get_options(self):
     options = (
         Option('name', help='Name of the application or project.'),
         Option('directory',
                nargs='?',
                help='Optional destination directory'),
         Option('--template',
                help='The path or URL to load the template from.'),
         Option('--extension',
                '-e',
                dest='extensions',
                action='append',
                default=['py'],
                help='The file extension(s) to render (default: "py"). '
                'Separate multiple extensions with commas, or use '
                '-e multiple times.'),
         Option(
             '--name',
             '-n',
             dest='files',
             action='append',
             default=[],
             help='The file name(s) to render. Separate multiple file names '
             'with commas, or use -n multiple times.'))
     return options
示例#3
0
 def get_options(self):
     options = (
         Option(
             '--locale',
             '-l',
             action='append',
             default=[],
             help=
             'Locale(s) to process (e.g. de_AT). Default is to process all. '
             'Can be used multiple times.'),
         Option(
             '--exclude',
             '-x',
             action='append',
             default=[],
             help=
             'Locales to exclude. Default is none. Can be used multiple times.'
         ),
         Option('--use-fuzzy',
                '-f',
                dest='fuzzy',
                action='store_true',
                help='Use fuzzy translations.'),
     )
     return options
示例#4
0
 def get_options(self):
     options = super().get_options()
     options += (
         Option('-h',
                '--host',
                default=self.default_host,
                help='Server hostname.'),
         Option('-p', '--port', required=True, help='Server port number.'),
     )
     return options
示例#5
0
 def get_options(self):
     return (
         Option('--no-ipython', action="store_true", dest='no_ipython', default=(not self.use_ipython),
                help="Do not use the IPython shell"),
         Option('--no-bpython', action="store_true", dest='no_bpython', default=(not self.use_bpython),
                help="Do not use the BPython shell"),
         Option('--no-ptipython', action="store_true", dest='no_ptipython', default=(not self.use_ptipython),
                help="Do not use the PtIPython shell"),
         Option('--no-ptpython', action="store_true", dest='no_ptpython', default=(not self.use_ptpython),
                help="Do not use the PtPython shell"),
     )
示例#6
0
class ApplicationChooser(Command):
    help = description = 'Choose application for administration.'
    option_list = (
        Option('name', help='Name of the application.'),
    )

    def run(self, *args, **kwargs):
        pass
示例#7
0
class GeoIPMMDBUpdate(Command):
    help = description = 'Creates or updates geoip2 mmdb databases.'
    option_list = (Option('-p',
                          '--path',
                          default='',
                          help='Path where files to save'), )

    def run(self, path):
        update(path)
示例#8
0
class DumpData(Command):
    help = description = 'Output the contents of the database as a fixture of the given format.'

    option_list = (
        Option('args',
               metavar='model_name',
               nargs='*',
               help='Restricts dumped data to the specified model name.'),
        Option('--format',
               default='json',
               help='Specifies the output serialization format for fixtures.'),
        Option(
            '--indent',
            type=int,
            help=
            'Specifies the indent level to use when pretty-printing output.'),
        Option('-e',
               '--exclude',
               action='append',
               default=[],
               help='A model name to exclude '
               '(use multiple --exclude to exclude multiple models).'),
        Option(
            '--pks',
            dest='primary_keys',
            help=
            'Only dump objects with given primary keys. Accepts a comma-separated '
            'list of keys. This option only works when you specify one model.'
        ),
        Option('-o',
               '--output',
               help='Specifies file to which the output is written.'))

    # noinspection PyAttributeOutsideInit
    def run(self, *model_names, **options):
        self.format = options['format']
        self.indent = options['indent']
        self.excluded_models = options['exclude']
        self.output = options['output']

        pks = options['primary_keys']
        if pks:
            self.primary_keys = [pk.strip() for pk in pks.split(',')]
        else:
            self.primary_keys = []

        from anthill.framework.apps.builder import app

        if not model_names:
            if self.primary_keys:
                raise InvalidCommand(
                    "You can only use --pks option with one model")
            self.models = list(
                filter(lambda m: m.__name__ not in self.excluded_models,
                       app.get_models()))
        else:
            if len(model_names) > 1 and self.primary_keys:
                raise InvalidCommand(
                    "You can only use --pks option with one model")
            self.models = []
            for model_name in model_names:
                model = app.get_model(model_name)
                if model is None:
                    raise InvalidCommand("Unknown model: %s" % model_name)
                self.models.append(model)

        try:
            self.stdout.ending = None
            progress_output = None
            object_count = 0
            # If dumpdata is outputting to stdout, there is no way to display progress
            if self.output and self.stdout.isatty():
                progress_output = self.stdout
                object_count = sum(self.get_objects(count_only=True))
            stream = open(self.output, 'w') if self.output else None
            try:
                serialize(self.format,
                          self.get_objects(),
                          indent=indent,
                          stream=stream or self.stdout,
                          progress_output=progress_output,
                          object_count=object_count)
            finally:
                if stream:
                    stream.close()
        except Exception as e:
            raise InvalidCommand("Unable to serialize database: %s" % e)

    def get_objects(self, count_only=False):
        """
        Collate the objects to be serialized. If count_only is True, just
        count the number of objects to be serialized.
        """
        for model in self.models:
            if model in excluded_models:
                continue
            query = Model.query
            if self.primary_keys:
                query = query.filter(Model.id.in_(self.primary_keys))
            if count_only:
                yield query.count()
            else:
                yield query.all()
示例#9
0
class ReplaceCommand(Command):
    help = 'Perform replace operations.'
    name = 'replace'

    option_list = (
        Option('-f', '--file', dest='file', default='replaces.json',
               help='JSON file with a list of replace pairs.'),
        Option('-t', '--target', dest='target', default='$',
               help='Target path of json tree.'),
        Option('-u', '--users', dest='users', default=None,
               help='User id list separated by commas.'),
    )

    @staticmethod
    def _load_replaces(path: str) -> Dict[Any, Any]:
        """Load replace pairs from JSON file."""
        with open(path) as f:
            replaces = json.load(f)
        return dict(replaces)

    def get_replaces(self, path: str) -> Dict[Any, Any]:
        try:
            replaces = self._load_replaces(path)
            if not replaces:
                self.stdout.write('No replaces to perform.')
                sys.exit()
        except (FileNotFoundError, JSONDecodeError) as e:
            self.stderr.write(str(e))
            sys.exit(GET_REPLACES_ERROR)
        return replaces

    @staticmethod
    def parse_users(raw_users: Optional[str] = None) -> List[str]:
        """
        Parse string of user ids list separated by commas.
        :return: user ids list.
        """
        if raw_users is not None:
            return re.split(r'\s*,\s*', raw_users)
        return []

    @staticmethod
    def get_profiles(users: Optional[List[str]] = None) -> List[Profile]:
        """Load profiles from database."""
        query = Profile.query
        if users:
            query = query.filter(Profile.user_id.in_(users))
        return query.all()

    @staticmethod
    def replace(profile: Profile, target: str, replaces: Dict[Any, Any]) -> None:
        """Apply all replace operations on profile payload."""
        matches = profile.find_payload(target, lambda x: x.value in replaces)
        for match in matches:
            new_value = replaces[match.value]
            # do replace operation without committing to database
            profile.update_payload(match.full_path, new_value, commit=False)
        if matches:
            # finally commit changes to database
            profile.save()

    def run(self, file: str, target: str, users: Optional[str] = None) -> None:
        replaces = self.get_replaces(path=file)
        profiles = self.get_profiles(users=self.parse_users(users))

        with tqdm.tqdm(total=len(profiles), unit=' profile') as pb:
            for profile in profiles:
                self.replace(profile, target, replaces)
                pb.update()
示例#10
0
class LoadData(Command):
    help = description = 'Installs the named fixture(s) in the database.'

    option_list = (
        Option('args', metavar='fixture', nargs='+', help='Fixture labels.'),
        Option(
            '--ignorenonexistent',
            '-i',
            action='store_true',
            dest='ignore',
            help='Ignores entries in the serialized data for fields that do not '
            'currently exist on the model.'),
        Option('-e',
               '--exclude',
               action='append',
               default=[],
               help='A model name to exclude. Can be used multiple times.'),
        Option('--format',
               help='Format of serialized data when reading from stdin.'),
    )

    # noinspection PyAttributeOutsideInit
    def run(self, *fixture_labels, **options):
        self.ignore = options['ignore']
        self.excluded_models = options['exclude']
        self.format = options['format']

        self.loaddata(fixture_labels)

    # noinspection PyAttributeOutsideInit
    def loaddata(self, fixture_labels):
        # Keep a count of the installed objects and fixtures
        self.fixture_count = 0
        self.loaded_object_count = 0
        self.fixture_object_count = 0
        self.models = set()

        self.serialization_formats = get_deserializers(keys=True)

        self.compression_formats = {
            None: (open, 'rb'),
            'gz': (gzip.GzipFile, 'rb'),
            'zip': (SingleZipReader, 'r'),
            'stdin': (lambda *args: sys.stdin, None),
        }
        if has_bz2:
            self.compression_formats['bz2'] = (bz2.BZ2File, 'r')

        # Anthill's test suite repeatedly tries to load initial_data fixtures
        # from apps that don't have any fixtures. Because disabling constraint
        # checks can be expensive on some database (especially MSSQL), bail
        # out early if no fixtures are found.
        for fixture_label in fixture_labels:
            if self.find_fixtures(fixture_label):
                break
        else:
            return

        for fixture_label in fixture_labels:
            self.load_label(fixture_label)

        if self.fixture_object_count == self.loaded_object_count:
            self.stdout.write("Installed %d object(s) from %d fixture(s)" %
                              (self.loaded_object_count, self.fixture_count))
        else:
            self.stdout.write(
                "Installed %d object(s) (of %d) from %d fixture(s)" %
                (self.loaded_object_count, self.fixture_object_count,
                 self.fixture_count))

    def load_label(self, fixture_label):
        """Load fixtures files for a given label."""
        for fixture_file, fixture_dir, fixture_name in self.find_fixtures(
                fixture_label):
            _, ser_fmt, cmp_fmt = self.parse_name(
                os.path.basename(fixture_file))
            open_method, mode = self.compression_formats[cmp_fmt]
            fixture = open_method(fixture_file, mode)
            try:
                self.fixture_count += 1
                objects_in_fixture = 0
                loaded_objects_in_fixture = 0
                self.stdout.write(
                    "Installing %s fixture '%s' from %s." %
                    (ser_fmt, fixture_name, humanize(fixture_dir)))

                objects = deserialize(ser_fmt,
                                      fixture,
                                      ignorenonexistent=self.ignore)

                for obj in objects:
                    objects_in_fixture += 1
                    if obj.__class__.__name__ in self.excluded_models:
                        continue
                    loaded_objects_in_fixture += 1
                    self.models.add(obj.__class__)
                    try:
                        obj.save()
                        self.stdout.write('\rProcessed %i object(s).' %
                                          loaded_objects_in_fixture,
                                          ending='')
                    except Exception as e:
                        e.args = (
                            "Could not load %(class_name)s(id=%(id)s): %(error_msg)s"
                            % {
                                'class_name': obj.__class__.__name__,
                                'id': obj.id,
                                'error_msg': e,
                            }, )
                        raise
                if objects:
                    self.stdout.write(
                        '')  # add a newline after progress indicator
                self.loaded_object_count += loaded_objects_in_fixture
                self.fixture_object_count += objects_in_fixture
            except Exception as e:
                if not isinstance(e, InvalidCommand):
                    e.args = ("Problem installing fixture '%s': %s" %
                              (fixture_file, e), )
                raise
            finally:
                fixture.close()

            # Warn if the fixture we loaded contains 0 objects.
            if objects_in_fixture == 0:
                warnings.warn(
                    "No fixture data found for '%s'. (File format may be "
                    "invalid.)" % fixture_name, RuntimeWarning)

    @functools.lru_cache(maxsize=None)
    def find_fixtures(self, fixture_label):
        """Find fixture files for a given label."""
        if fixture_label == READ_STDIN:
            return [(READ_STDIN, None, READ_STDIN)]

        fixture_name, ser_fmt, cmp_fmt = self.parse_name(fixture_label)
        cmp_fmts = list(
            self.compression_formats) if cmp_fmt is None else [cmp_fmt]
        ser_fmts = self.serialization_formats if ser_fmt is None else [ser_fmt]

        self.stdout.write("Loading '%s' fixtures..." % fixture_name)

        if os.path.isabs(fixture_name):
            fixture_dirs = [os.path.dirname(fixture_name)]
            fixture_name = os.path.basename(fixture_name)
        else:
            fixture_dirs = self.fixture_dirs
            if os.path.sep in os.path.normpath(fixture_name):
                fixture_dirs = [
                    os.path.join(dir_, os.path.dirname(fixture_name))
                    for dir_ in fixture_dirs
                ]
                fixture_name = os.path.basename(fixture_name)

        suffixes = ('.'.join(ext for ext in combo if ext)
                    for combo in product(ser_fmts, cmp_fmts))
        targets = {'.'.join((fixture_name, suffix)) for suffix in suffixes}

        fixture_files = []
        for fixture_dir in fixture_dirs:
            self.stdout.write("Checking %s for fixtures..." %
                              humanize(fixture_dir))
            fixture_files_in_dir = []
            path = os.path.join(fixture_dir, fixture_name)
            for candidate in glob.iglob(glob.escape(path) + '*'):
                if os.path.basename(candidate) in targets:
                    # Save the fixture_dir and fixture_name for future error messages.
                    fixture_files_in_dir.append(
                        (candidate, fixture_dir, fixture_name))

            if not fixture_files_in_dir:
                self.stdout.write("No fixture '%s' in %s." %
                                  (fixture_name, humanize(fixture_dir)))

            # Check kept for backwards-compatibility; it isn't clear why
            # duplicates are only allowed in different directories.
            if len(fixture_files_in_dir) > 1:
                raise InvalidCommand(
                    "Multiple fixtures named '%s' in %s. Aborting." %
                    (fixture_name, humanize(fixture_dir)))
            fixture_files.extend(fixture_files_in_dir)

        if not fixture_files:
            raise InvalidCommand("No fixture named '%s' found." % fixture_name)

        return fixture_files

    @cached_property
    def fixture_dirs(self):
        """Return a list of fixture directories."""
        dirs = []
        fixture_dirs = settings.FIXTURE_DIRS
        if len(fixture_dirs) != len(set(fixture_dirs)):
            raise ImproperlyConfigured(
                "settings.FIXTURE_DIRS contains duplicates.")

        dirs.extend(fixture_dirs)
        dirs.append('')

        return [os.path.realpath(d) for d in dirs]

    def parse_name(self, fixture_name):
        """
        Split fixture name in name, serialization format, compression format.
        """
        if fixture_name == READ_STDIN:
            if not self.format:
                raise InvalidCommand(
                    '--format must be specified when reading from stdin.')
            return READ_STDIN, self.format, 'stdin'

        parts = fixture_name.rsplit('.', 2)

        if len(parts) > 1 and parts[-1] in self.compression_formats:
            cmp_fmt = parts[-1]
            parts = parts[:-1]
        else:
            cmp_fmt = None

        if len(parts) > 1:
            if parts[-1] in self.serialization_formats:
                ser_fmt = parts[-1]
                parts = parts[:-1]
            else:
                raise InvalidCommand(
                    "Problem installing fixture '%s': %s is not a known "
                    "serialization format." %
                    ('.'.join(parts[:-1]), parts[-1]))
        else:
            ser_fmt = None

        name = '.'.join(parts)

        return name, ser_fmt, cmp_fmt