Skip to content

Commit

Permalink
Version 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
exonian committed Nov 5, 2015
1 parent 0dcd516 commit b5a104e
Show file tree
Hide file tree
Showing 19 changed files with 631 additions and 23 deletions.
51 changes: 51 additions & 0 deletions build/lib.linux-x86_64-2.7/django_grepdb/management/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from django.core.management import CommandError, BaseCommand, get_commands, load_command_class


def call_command(name, *args, **options):
"""
Calls the given command, with the given options and args/kwargs.
This is the primary API you should use for calling specific commands.
Some examples:
call_command('migrate')
call_command('shell', plain=True)
call_command('sqlmigrate', 'myapp')
Copy of the function from django.core.management. In addition to the
standard functionality, stores the raw args on the command instance.
"""
# Load the command object.
try:
app_name = get_commands()[name]
except KeyError:
raise CommandError("Unknown command: %r" % name)

if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it directly.
command = app_name
else:
command = load_command_class(app_name, name)

# Store the raw args on the command so they can be used later if needed
command.raw_args = args

# Simulate argument parsing to get the option defaults (see #10080 for details).
parser = command.create_parser('', name)
if command.use_argparse:
# Use the `dest` option name from the parser option
opt_mapping = {sorted(s_opt.option_strings)[0].lstrip('-').replace('-', '_'): s_opt.dest
for s_opt in parser._actions if s_opt.option_strings}
arg_options = {opt_mapping.get(key, key): value for key, value in options.items()}
defaults = parser.parse_args(args=args)
defaults = dict(defaults._get_kwargs(), **arg_options)
# Move positional args out of options to mimic legacy optparse
args = defaults.pop('args', ())
else:
# Legacy optparse method
defaults, _ = parser.parse_args(args=[])
defaults = dict(defaults.__dict__, **options)
if 'skip_checks' not in options:
defaults['skip_checks'] = True

return command.execute(*args, **defaults)
Original file line number Diff line number Diff line change
Expand Up @@ -32,33 +32,44 @@ def add_arguments(self, parser):
'or provide the mode "a" to show the entire field ' +
'or an integer to show that many characters either side of a match.')
parser.add_argument('--ignore-case', '-i', action='store_true', help='Match case-insensitively')
parser.add_argument('--find-text-fields', '-t', dest='field_types', action='append_const', const='TextField',
help='Search all TextField fields on a model if no field is specified')
parser.add_argument('--find-char-fields', '-c', dest='field_types', action='append_const', const='CharField',
help='Search all CharField fields on a model if no field is specified')
parser.add_argument('--find-fields', '-f', dest='field_types', action='append', type=str,
help='Search all fields of this type on a model if no field is specified')
parser.add_argument('--admin-links', '-l', nargs='*', default=['http://localhost:8000'],
help='Generate admin links. Defaults to true, using http://localhost:8000/ as hostname.' +
'Can be passed one or more hostnames to use instead. If DJANGO_GREPDB_SITES is a dict ' +
'defined in settings, keys from it can also be passed to use their values as hostnames.' +
'Links can be disabled by using this argument without any values.')
parser.add_argument('--find-text-fields', '-t', dest='field_type', action='append_const', const='TextField',
help='Search all TextField fields (and subclasses) on a model if no field is specified')
parser.add_argument('--find-char-fields', '-c', dest='field_type', action='append_const', const='CharField',
help='Search all CharField fields (and subclasses) on a model if no field is specified')
parser.add_argument('--find-fields', '-f', dest='field_type', action='append', type=str,
help='Search all fields of this type (and subclasses) on a model if no field is specified')
parser.add_argument('--preset', '-p', help='The name of a preset configuration in DJANGO_GREPDB_PRESETS. ' +
'DJANGO_GREPDB_PRESETS should be a dict of dicts, with each config dict providing ' +
'default values for any number of parser args.')
if apps.is_installed('django.contrib.admin'):
parser.add_argument('--admin-links', '-l', dest='admin_hostname', nargs='*', default=['localhost:8000'],
help='Generate admin links. Defaults to true, using http://localhost:8000/ as hostname. ' +
'Can be passed one or more hostnames to use instead. If DJANGO_GREPDB_SITES is a ' +
'dict defined in settings, keys from it can also be passed to use their values as ' +
'hostnames. Links can be disabled by using this argument without any values.')
self.parser = parser

def handle(self, **options):
colorama.init()
preset = self.get_preset(options['preset'])
if preset:
self.parser.set_defaults(**preset)
# re-parse the command linei arguments with new defaults in place
options = vars(self.parser.parse_args(self.argv[2:]))
# re-parse the command line arguments with new defaults in place
try:
options = vars(self.parser.parse_args(self.raw_args))
except AttributeError:
if not self._called_from_command_line:
# regular call_command doesn't store raw_args
msg = '--preset mode is not compatible with django.core.management.call_command: you need to ' \
'use django_grepdb.management.call_command instead'
raise CommandError(msg)
else:
# if it was called from the command line, the problem is something unknown
raise
self.pattern = options['pattern']
self.ignore_case = options['ignore_case']
self.show_values = options.get('show_values', False)
self.field_types = options['field_types'] or ['TextField']
self.field_type = options['field_type'] or ['TextField']
self.admin_hostnames = self.get_admin_hostnames(options)

identifiers = options['identifiers']
Expand All @@ -76,12 +87,12 @@ def handle(self, **options):
self.stdout.write(self.get_value(result, query))

def run_from_argv(self, argv):
# store argv so that we can re-parse it with new defaults if preset mode is used
self.argv = argv
# store raw args so that we can re-parse them with new defaults if preset mode is used
self.raw_args = argv[2:]
super(Command, self).run_from_argv(argv)

def get_admin_hostnames(self, options):
from_options = options.get('admin_links', False)
from_options = options.get('admin_hostname', False)
if not from_options:
return
from django.contrib.admin import site as admin_site
Expand All @@ -92,10 +103,10 @@ def get_admin_hostnames(self, options):
return hostnames

def get_admin_hostname(self, reference):
"""Treats the reference as a hostname if it contains a dot or the string 'localhost'.
"""Treats the reference as a hostname if it contains either 'http' or 'localhost'.
If it contains neither, looks up the reference in settings.DJANGO_GREPDB_SITES
"""
if '.' in reference or 'localhost' in reference:
if 'http' in reference or 'localhost' in reference:
return reference
try:
sites = getattr(settings, 'DJANGO_GREPDB_SITES')
Expand All @@ -118,6 +129,9 @@ def get_preset(self, preset_name):
raise CommandError(u'Preset specified but DJANGO_GREPDB_PRESETS is not configured in settings')
try:
preset = presets[preset_name]
except TypeError:
msg = u'DJANGO_GREPDB_PRESETS is not a dict-like object'
raise CommandError(msg)
except KeyError:
msg = u'Preset "{preset_name}" not found in DJANGO_GREPDB_PRESETS. Available values are: {values}'
raise CommandError(msg.format(preset_name=preset_name, values=', '.join(presets.keys())))
Expand Down Expand Up @@ -155,7 +169,7 @@ def parse_identifier(self, identifier):
return (model, field_names)

def get_field_names_for_model(self, model):
return [field.name for field in model._meta.fields if field.get_internal_type() in self.field_types]
return [field.name for field in model._meta.fields if field.get_internal_type() in self.field_type]

def get_queryset_params(self, field_name):
lookup_type = 'regex'
Expand Down Expand Up @@ -227,3 +241,7 @@ def get_admin_links(self, result):
admin_url_pattern = 'admin:{app}_{model}_change'.format(app=content_type.app_label, model=content_type.model)
relative_url = reverse(admin_url_pattern, args=[result.pk])
return '\n'.join([colored(hostname + relative_url, 'green') for hostname in self.admin_hostnames])

def get_version(self):
from ...version import VERSION
return VERSION
Empty file.
12 changes: 12 additions & 0 deletions build/lib.linux-x86_64-2.7/django_grepdb/tests/admin_urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.conf.urls import include, url
from django.contrib import admin

from models import TestModel, TestModelTwo

admin.site.register(TestModel)
admin.site.register(TestModelTwo)


urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
]

operations = [
migrations.CreateModel(
name='TestModel',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('text_field', models.TextField(blank=True)),
('text_field_two', models.TextField(blank=True)),
('char_field', models.CharField(max_length=255, blank=True)),
],
),
migrations.CreateModel(
name='TestModelTwo',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('text_field', models.TextField(blank=True)),
('char_field', models.CharField(max_length=255, blank=True)),
('url', models.URLField(blank=True)),
],
),
]
Empty file.
19 changes: 19 additions & 0 deletions build/lib.linux-x86_64-2.7/django_grepdb/tests/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from django.db import models


class TestModel(models.Model):
text_field = models.TextField(blank=True)
text_field_two = models.TextField(blank=True)
char_field = models.CharField(blank=True, max_length=255)

class Meta:
app_label = 'tests'


class TestModelTwo(models.Model):
text_field = models.TextField(blank=True)
char_field = models.CharField(blank=True, max_length=255)
url = models.URLField(blank=True)

class Meta:
app_label = 'tests'
114 changes: 114 additions & 0 deletions build/lib.linux-x86_64-2.7/django_grepdb/tests/test_admin_links.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
from django.conf import settings
from django.core.management import call_command, CommandError
from django.test import TestCase, override_settings
from django.utils.six import StringIO

from models import TestModel


class TestWithoutAdminInstalled(TestCase):
@classmethod
def setUpTestData(cls):
TestModel.objects.create(text_field="The quick brown fox")

def test_admin_option_not_used_by_default(self):
out = StringIO()
call_command('grepdb', 'brown', 'tests.TestModel.text_field', '-s', stdout=out)
expected = "\x1b[1m\x1b[36m\n<class 'django_grepdb.tests.models.TestModel'> " \
"text_field\x1b[0m\n\x1b[1m\x1b[32mTestModel object (pk=1)\x1b[0m\n"
self.assertEqual(out.getvalue(), expected)

def test_admin_option_fails(self):
with self.assertRaises(CommandError) as cm:
call_command('grepdb', 'brown', 'tests.TestModel.text_field', '-s', '-l')
self.assertEqual(cm.exception.message, u'Error: unrecognized arguments: -l')


@override_settings(
INSTALLED_APPS=[
'django.contrib.admin',
'django.contrib.contenttypes',
'django_grepdb',
'django_grepdb.tests',
],
ROOT_URLCONF='django_grepdb.tests.admin_urls'
)
class TestWithAdminInstalled(TestCase):
@classmethod
def setUpTestData(cls):
TestModel.objects.create(text_field="The quick brown fox")

def test_default_link_generation_output(self):
"""Default is to generate admin links, and to use localhost:8000 as the hostname"""
out = StringIO()
call_command('grepdb', 'quick', 'tests.TestModel.text_field', '-s', stdout=out)
expected = "\x1b[1m\x1b[36m\n<class 'django_grepdb.tests.models.TestModel'> " \
"text_field\x1b[0m\n\x1b[1m\x1b[32mTestModel object " \
"(pk=1)\x1b[0m\n\x1b[32mlocalhost:8000/admin/tests/testmodel/1/\x1b[0m\n"
self.assertEqual(out.getvalue(), expected)

def test_option_without_argument_turns_off_link_generation(self):
out = StringIO()
call_command('grepdb', 'quick', 'tests.TestModel.text_field', '-s', '-l', stdout=out)
expected = "\x1b[1m\x1b[36m\n<class 'django_grepdb.tests.models.TestModel'> " \
"text_field\x1b[0m\n\x1b[1m\x1b[32mTestModel object (pk=1)\x1b[0m\n"
self.assertEqual(out.getvalue(), expected)

def test_option_with_http_hostname(self):
out = StringIO()
call_command('grepdb', 'quick', 'tests.TestModel.text_field', '-s', '-l', 'http://fox.example.com', stdout=out)
expected = "\x1b[1m\x1b[36m\n<class 'django_grepdb.tests.models.TestModel'> " \
"text_field\x1b[0m\n\x1b[1m\x1b[32mTestModel object " \
"(pk=1)\x1b[0m\n\x1b[32mhttp://fox.example.com/admin/tests/testmodel/1/\x1b[0m\n"
self.assertEqual(out.getvalue(), expected)

def test_option_with_https_hostname(self):
out = StringIO()
call_command('grepdb', 'quick', 'tests.TestModel.text_field', '-s', '-l', 'https://fox.example.com', stdout=out)
expected = "\x1b[1m\x1b[36m\n<class 'django_grepdb.tests.models.TestModel'> " \
"text_field\x1b[0m\n\x1b[1m\x1b[32mTestModel object " \
"(pk=1)\x1b[0m\n\x1b[32mhttps://fox.example.com/admin/tests/testmodel/1/\x1b[0m\n"
self.assertEqual(out.getvalue(), expected)

def test_option_with_schemeless_hostname(self):
with self.assertRaises(CommandError) as cm:
call_command('grepdb', 'quick', 'tests.TestModel.text_field', '-s', '-l', 'fox.example.com')
msg = u'Reference fox.example.com is not recognised as a hostname and was not found in DJANGO_GREPDB_SITES'
self.assertEqual(cm.exception.message, msg)

def test_option_with_localhost(self):
out = StringIO()
call_command('grepdb', 'quick', 'tests.TestModel.text_field', '-s', '-l', 'localhost:4000', stdout=out)
expected = "\x1b[1m\x1b[36m\n<class 'django_grepdb.tests.models.TestModel'> " \
"text_field\x1b[0m\n\x1b[1m\x1b[32mTestModel object " \
"(pk=1)\x1b[0m\n\x1b[32mlocalhost:4000/admin/tests/testmodel/1/\x1b[0m\n"
self.assertEqual(out.getvalue(), expected)

def test_option_with_sites_key(self):
out = StringIO()
call_command('grepdb', 'quick', 'tests.TestModel.text_field', '-s', '-l', 'production', stdout=out)
expected = "\x1b[1m\x1b[36m\n<class 'django_grepdb.tests.models.TestModel'> " \
"text_field\x1b[0m\n\x1b[1m\x1b[32mTestModel object " \
"(pk=1)\x1b[0m\n\x1b[32mhttps://example.com/admin/tests/testmodel/1/\x1b[0m\n"
self.assertEqual(out.getvalue(), expected)

def test_option_with_mixed_arguments(self):
out = StringIO()
call_command('grepdb', 'quick', 'tests.TestModel.text_field', '-s', '-l', 'staging', 'production',
'https://dev.example.com', stdout=out)
expected = "\x1b[1m\x1b[36m\n<class 'django_grepdb.tests.models.TestModel'> " \
"text_field\x1b[0m\n\x1b[1m\x1b[32mTestModel object (pk=1)\x1b[0m\n" \
"\x1b[32mhttps://staging.example.com/admin/tests/testmodel/1/\x1b[0m\n" \
"\x1b[32mhttps://example.com/admin/tests/testmodel/1/\x1b[0m\n" \
"\x1b[32mhttps://dev.example.com/admin/tests/testmodel/1/\x1b[0m\n"
self.assertEqual(out.getvalue(), expected)

@override_settings()
def test_option_without_sites_setting(self):
del settings.DJANGO_GREPDB_SITES
with self.assertRaises(CommandError) as cm:
call_command('grepdb', 'quick', 'tests.TestModel.text_field', '-s', '-l', 'fox.example.com')
msg = u'Reference fox.example.com is not recognised as a hostname and DJANGO_GREPDB_SITES is not ' \
'configured in settings'
self.assertEqual(cm.exception.message, msg)
Loading

0 comments on commit b5a104e

Please sign in to comment.