From 30c8142ed654f38fb85771829987305d989b1110 Mon Sep 17 00:00:00 2001 From: Krzysztof Bonecki Date: Fri, 8 Jan 2021 22:29:33 +0100 Subject: [PATCH] Update venv --- .../INSTALLER | 1 + .../django_extensions-3.1.0.dist-info/LICENSE | 19 + .../METADATA | 160 ++ .../django_extensions-3.1.0.dist-info/RECORD | 269 ++++ .../REQUESTED | 0 .../django_extensions-3.1.0.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../django_extensions/__init__.py | 20 + .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 647 bytes .../__pycache__/apps.cpython-37.pyc | Bin 0 -> 464 bytes .../collision_resolvers.cpython-37.pyc | Bin 0 -> 11789 bytes .../__pycache__/compat.cpython-37.pyc | Bin 0 -> 2336 bytes .../import_subclasses.cpython-37.pyc | Bin 0 -> 2612 bytes .../__pycache__/models.cpython-37.pyc | Bin 0 -> 186 bytes .../__pycache__/settings.cpython-37.pyc | Bin 0 -> 1105 bytes .../__pycache__/validators.cpython-37.pyc | Bin 0 -> 3736 bytes .../django_extensions/admin/__init__.py | 165 ++ .../admin/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 6949 bytes .../admin/__pycache__/filter.cpython-37.pyc | Bin 0 -> 2267 bytes .../admin/__pycache__/widgets.cpython-37.pyc | Bin 0 -> 3136 bytes .../django_extensions/admin/filter.py | 53 + .../django_extensions/admin/widgets.py | 90 ++ .../site-packages/django_extensions/apps.py | 7 + .../django_extensions/auth/__init__.py | 0 .../auth/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 193 bytes .../auth/__pycache__/mixins.cpython-37.pyc | Bin 0 -> 909 bytes .../django_extensions/auth/mixins.py | 15 + .../django_extensions/collision_resolvers.py | 265 ++++ .../site-packages/django_extensions/compat.py | 67 + .../conf/app_template/__init__.py.tmpl | 0 .../conf/app_template/forms.py.tmpl | 3 + .../app_template/migrations/__init__.py.tmpl | 0 .../conf/app_template/models.py.tmpl | 3 + .../conf/app_template/urls.py.tmpl | 3 + .../conf/app_template/views.py.tmpl | 1 + .../management/__init__.py.tmpl | 0 .../management/commands/__init__.py.tmpl | 0 .../management/commands/sample.py.tmpl | 11 + .../conf/jobs_template/jobs/__init__.py.tmpl | 0 .../jobs_template/jobs/daily/__init__.py.tmpl | 0 .../jobs/hourly/__init__.py.tmpl | 0 .../jobs/monthly/__init__.py.tmpl | 0 .../conf/jobs_template/jobs/sample.py.tmpl | 9 + .../jobs/weekly/__init__.py.tmpl | 0 .../jobs/yearly/__init__.py.tmpl | 0 .../templatetags/__init__.py.tmpl | 0 .../templatetags/sample.py.tmpl | 3 + .../django_extensions/db/__init__.py | 0 .../db/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 191 bytes .../db/__pycache__/models.cpython-37.pyc | Bin 0 -> 5378 bytes .../django_extensions/db/fields/__init__.py | 593 +++++++ .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 17643 bytes .../db/fields/__pycache__/json.cpython-37.pyc | Bin 0 -> 3611 bytes .../django_extensions/db/fields/json.py | 107 ++ .../django_extensions/db/models.py | 134 ++ .../django_extensions/import_subclasses.py | 57 + .../django_extensions/jobs/__init__.py | 0 .../jobs/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 193 bytes .../django_extensions/jobs/daily/__init__.py | 0 .../daily/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 199 bytes .../__pycache__/cache_cleanup.cpython-37.pyc | Bin 0 -> 983 bytes .../__pycache__/daily_cleanup.cpython-37.pyc | Bin 0 -> 796 bytes .../jobs/daily/cache_cleanup.py | 24 + .../jobs/daily/daily_cleanup.py | 17 + .../django_extensions/jobs/hourly/__init__.py | 0 .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 200 bytes .../jobs/minutely/__init__.py | 0 .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 202 bytes .../jobs/monthly/__init__.py | 0 .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 201 bytes .../django_extensions/jobs/weekly/__init__.py | 0 .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 200 bytes .../django_extensions/jobs/yearly/__init__.py | 0 .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 200 bytes .../locale/da/LC_MESSAGES/django.mo | Bin 0 -> 797 bytes .../locale/da/LC_MESSAGES/django.po | 79 + .../locale/de/LC_MESSAGES/django.mo | Bin 0 -> 1227 bytes .../locale/de/LC_MESSAGES/django.po | 77 + .../locale/el/LC_MESSAGES/django.mo | Bin 0 -> 1581 bytes .../locale/el/LC_MESSAGES/django.po | 79 + .../locale/en/LC_MESSAGES/django.mo | Bin 0 -> 367 bytes .../locale/en/LC_MESSAGES/django.po | 112 ++ .../locale/es/LC_MESSAGES/django.mo | Bin 0 -> 1260 bytes .../locale/es/LC_MESSAGES/django.po | 77 + .../locale/fr/LC_MESSAGES/django.mo | Bin 0 -> 743 bytes .../locale/fr/LC_MESSAGES/django.po | 81 + .../locale/hu/LC_MESSAGES/django.mo | Bin 0 -> 1242 bytes .../locale/hu/LC_MESSAGES/django.po | 77 + .../locale/id/LC_MESSAGES/django.mo | Bin 0 -> 1508 bytes .../locale/id/LC_MESSAGES/django.po | 98 ++ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 1247 bytes .../locale/it/LC_MESSAGES/django.po | 77 + .../locale/ja/LC_MESSAGES/django.mo | Bin 0 -> 1397 bytes .../locale/ja/LC_MESSAGES/django.po | 77 + .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 2002 bytes .../locale/pl/LC_MESSAGES/django.po | 109 ++ .../locale/pt/LC_MESSAGES/django.mo | Bin 0 -> 1262 bytes .../locale/pt/LC_MESSAGES/django.po | 77 + .../locale/pt_BR/LC_MESSAGES/django.mo | Bin 0 -> 1310 bytes .../locale/pt_BR/LC_MESSAGES/django.po | 79 + .../locale/ro/LC_MESSAGES/django.mo | Bin 0 -> 1352 bytes .../locale/ro/LC_MESSAGES/django.po | 80 + .../locale/ru/LC_MESSAGES/django.mo | Bin 0 -> 2009 bytes .../locale/ru/LC_MESSAGES/django.po | 126 ++ .../django_extensions/logging/__init__.py | 0 .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 196 bytes .../__pycache__/filters.cpython-37.pyc | Bin 0 -> 1133 bytes .../django_extensions/logging/filters.py | 36 + .../django_extensions/management/__init__.py | 0 .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 199 bytes .../__pycache__/base.cpython-37.pyc | Bin 0 -> 1862 bytes .../__pycache__/color.cpython-37.pyc | Bin 0 -> 1013 bytes .../__pycache__/debug_cursor.cpython-37.pyc | Bin 0 -> 3427 bytes .../email_notifications.cpython-37.pyc | Bin 0 -> 4809 bytes .../__pycache__/jobs.cpython-37.pyc | Bin 0 -> 5844 bytes .../__pycache__/modelviz.cpython-37.pyc | Bin 0 -> 13049 bytes .../__pycache__/mysql.cpython-37.pyc | Bin 0 -> 1233 bytes .../notebook_extension.cpython-37.pyc | Bin 0 -> 557 bytes .../__pycache__/shells.cpython-37.pyc | Bin 0 -> 10369 bytes .../__pycache__/signals.cpython-37.pyc | Bin 0 -> 472 bytes .../technical_response.cpython-37.pyc | Bin 0 -> 1731 bytes .../__pycache__/utils.cpython-37.pyc | Bin 0 -> 2577 bytes .../django_extensions/management/base.py | 53 + .../django_extensions/management/color.py | 29 + .../management/commands/__init__.py | 0 .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 208 bytes .../admin_generator.cpython-37.pyc | Bin 0 -> 10309 bytes .../__pycache__/clean_pyc.cpython-37.pyc | Bin 0 -> 1709 bytes .../__pycache__/clear_cache.cpython-37.pyc | Bin 0 -> 1669 bytes .../__pycache__/compile_pyc.cpython-37.pyc | Bin 0 -> 1538 bytes .../__pycache__/create_command.cpython-37.pyc | Bin 0 -> 3329 bytes .../__pycache__/create_jobs.cpython-37.pyc | Bin 0 -> 2434 bytes .../create_template_tags.cpython-37.pyc | Bin 0 -> 2553 bytes .../delete_squashed_migrations.cpython-37.pyc | Bin 0 -> 4918 bytes .../__pycache__/describe_form.cpython-37.pyc | Bin 0 -> 2732 bytes .../drop_test_database.cpython-37.pyc | Bin 0 -> 4267 bytes .../__pycache__/dumpscript.cpython-37.pyc | Bin 0 -> 21740 bytes .../__pycache__/export_emails.cpython-37.pyc | Bin 0 -> 6019 bytes .../__pycache__/find_template.cpython-37.pyc | Bin 0 -> 1066 bytes .../generate_password.cpython-37.pyc | Bin 0 -> 1302 bytes .../generate_secret_key.cpython-37.pyc | Bin 0 -> 833 bytes .../__pycache__/graph_models.cpython-37.pyc | Bin 0 -> 9449 bytes .../list_model_info.cpython-37.pyc | Bin 0 -> 4522 bytes .../__pycache__/list_signals.cpython-37.pyc | Bin 0 -> 2541 bytes .../__pycache__/mail_debug.cpython-37.pyc | Bin 0 -> 3038 bytes .../merge_model_instances.cpython-37.pyc | Bin 0 -> 6336 bytes .../commands/__pycache__/notes.cpython-37.pyc | Bin 0 -> 2537 bytes .../__pycache__/pipchecker.cpython-37.pyc | Bin 0 -> 11129 bytes .../__pycache__/print_settings.cpython-37.pyc | Bin 0 -> 2835 bytes .../print_user_for_session.cpython-37.pyc | Bin 0 -> 2242 bytes .../__pycache__/reset_db.cpython-37.pyc | Bin 0 -> 5403 bytes .../__pycache__/reset_schema.cpython-37.pyc | Bin 0 -> 2750 bytes .../__pycache__/runjob.cpython-37.pyc | Bin 0 -> 2030 bytes .../__pycache__/runjobs.cpython-37.pyc | Bin 0 -> 3431 bytes .../runprofileserver.cpython-37.pyc | Bin 0 -> 8894 bytes .../__pycache__/runscript.cpython-37.pyc | Bin 0 -> 8496 bytes .../__pycache__/runserver_plus.cpython-37.pyc | Bin 0 -> 15874 bytes .../set_default_site.cpython-37.pyc | Bin 0 -> 2391 bytes .../set_fake_emails.cpython-37.pyc | Bin 0 -> 3040 bytes .../set_fake_passwords.cpython-37.pyc | Bin 0 -> 1970 bytes .../__pycache__/shell_plus.cpython-37.pyc | Bin 0 -> 16473 bytes .../show_template_tags.cpython-37.pyc | Bin 0 -> 3801 bytes .../__pycache__/show_urls.cpython-37.pyc | Bin 0 -> 7636 bytes .../__pycache__/sqlcreate.cpython-37.pyc | Bin 0 -> 3669 bytes .../__pycache__/sqldiff.cpython-37.pyc | Bin 0 -> 46698 bytes .../__pycache__/sqldsn.cpython-37.pyc | Bin 0 -> 4236 bytes .../__pycache__/sync_s3.cpython-37.pyc | Bin 0 -> 11060 bytes .../__pycache__/syncdata.cpython-37.pyc | Bin 0 -> 6684 bytes .../unreferenced_files.cpython-37.pyc | Bin 0 -> 1632 bytes .../update_permissions.cpython-37.pyc | Bin 0 -> 2545 bytes .../validate_templates.cpython-37.pyc | Bin 0 -> 2986 bytes .../management/commands/admin_generator.py | 347 +++++ .../management/commands/clean_pyc.py | 45 + .../management/commands/clear_cache.py | 37 + .../management/commands/compile_pyc.py | 36 + .../management/commands/create_command.py | 91 ++ .../management/commands/create_jobs.py | 64 + .../commands/create_template_tags.py | 72 + .../commands/delete_squashed_migrations.py | 183 +++ .../management/commands/describe_form.py | 74 + .../management/commands/drop_test_database.py | 151 ++ .../management/commands/dumpscript.py | 758 +++++++++ .../management/commands/export_emails.py | 157 ++ .../management/commands/find_template.py | 22 + .../management/commands/generate_password.py | 28 + .../commands/generate_secret_key.py | 15 + .../management/commands/graph_models.py | 319 ++++ .../management/commands/list_model_info.py | 149 ++ .../management/commands/list_signals.py | 74 + .../management/commands/mail_debug.py | 85 + .../commands/merge_model_instances.py | 222 +++ .../management/commands/notes.py | 62 + .../management/commands/pipchecker.py | 326 ++++ .../management/commands/print_settings.py | 83 + .../commands/print_user_for_session.py | 63 + .../management/commands/reset_db.py | 195 +++ .../management/commands/reset_schema.py | 79 + .../management/commands/runjob.py | 58 + .../management/commands/runjobs.py | 88 ++ .../management/commands/runprofileserver.py | 291 ++++ .../management/commands/runscript.py | 301 ++++ .../management/commands/runserver_plus.py | 487 ++++++ .../management/commands/set_default_site.py | 74 + .../management/commands/set_fake_emails.py | 96 ++ .../management/commands/set_fake_passwords.py | 53 + .../management/commands/shell_plus.py | 556 +++++++ .../management/commands/show_template_tags.py | 113 ++ .../management/commands/show_urls.py | 237 +++ .../management/commands/sqlcreate.py | 93 ++ .../management/commands/sqldiff.py | 1381 +++++++++++++++++ .../management/commands/sqldsn.py | 156 ++ .../management/commands/sync_s3.py | 400 +++++ .../management/commands/syncdata.py | 224 +++ .../management/commands/unreferenced_files.py | 48 + .../management/commands/update_permissions.py | 63 + .../management/commands/validate_templates.py | 96 ++ .../management/debug_cursor.py | 113 ++ .../management/email_notifications.py | 140 ++ .../django_extensions/management/jobs.py | 182 +++ .../django_extensions/management/modelviz.py | 440 ++++++ .../django_extensions/management/mysql.py | 43 + .../management/notebook_extension.py | 10 + .../django_extensions/management/shells.py | 345 ++++ .../django_extensions/management/signals.py | 13 + .../management/technical_response.py | 44 + .../django_extensions/management/utils.py | 74 + .../site-packages/django_extensions/models.py | 0 .../django_extensions/mongodb/__init__.py | 0 .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 196 bytes .../mongodb/__pycache__/models.cpython-37.pyc | Bin 0 -> 3551 bytes .../mongodb/fields/__init__.py | 268 ++++ .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 8749 bytes .../fields/__pycache__/json.cpython-37.pyc | Bin 0 -> 2898 bytes .../django_extensions/mongodb/fields/json.py | 80 + .../django_extensions/mongodb/models.py | 89 ++ .../django_extensions/settings.py | 30 + .../css/jquery.autocomplete.css | 38 + .../django_extensions/img/indicator.gif | Bin 0 -> 1553 bytes .../django_extensions/js/jquery.ajaxQueue.js | 119 ++ .../js/jquery.autocomplete.js | 1152 ++++++++++++++ .../django_extensions/js/jquery.bgiframe.js | 39 + .../graph_models/django2018/digraph.dot | 26 + .../graph_models/django2018/label.dot | 33 + .../graph_models/django2018/relation.dot | 10 + .../graph_models/original/digraph.dot | 26 + .../graph_models/original/label.dot | 33 + .../graph_models/original/relation.dot | 10 + .../widgets/foreignkey_searchinput.html | 61 + .../templatetags/__init__.py | 0 .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 201 bytes .../__pycache__/debugger_tags.cpython-37.pyc | Bin 0 -> 883 bytes .../__pycache__/highlighting.cpython-37.pyc | Bin 0 -> 3559 bytes .../__pycache__/indent_text.cpython-37.pyc | Bin 0 -> 1787 bytes .../__pycache__/syntax_color.cpython-37.pyc | Bin 0 -> 3544 bytes .../__pycache__/widont.cpython-37.pyc | Bin 0 -> 2409 bytes .../templatetags/debugger_tags.py | 37 + .../templatetags/highlighting.py | 102 ++ .../templatetags/indent_text.py | 55 + .../templatetags/syntax_color.py | 111 ++ .../django_extensions/templatetags/widont.py | 64 + .../django_extensions/utils/__init__.py | 2 + .../utils/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 242 bytes .../__pycache__/deprecation.cpython-37.pyc | Bin 0 -> 535 bytes .../__pycache__/dia2django.cpython-37.pyc | Bin 0 -> 5486 bytes .../__pycache__/internal_ips.cpython-37.pyc | Bin 0 -> 2637 bytes .../django_extensions/utils/deprecation.py | 8 + .../django_extensions/utils/dia2django.py | 217 +++ .../django_extensions/utils/internal_ips.py | 70 + .../django_extensions/validators.py | 108 ++ 269 files changed, 16269 insertions(+) create mode 100644 venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/LICENSE create mode 100644 venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/METADATA create mode 100644 venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/RECORD create mode 100644 venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/REQUESTED create mode 100644 venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/WHEEL create mode 100644 venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/top_level.txt create mode 100644 venv/lib/python3.7/site-packages/django_extensions/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/__pycache__/apps.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/__pycache__/collision_resolvers.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/__pycache__/compat.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/__pycache__/import_subclasses.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/__pycache__/models.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/__pycache__/settings.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/__pycache__/validators.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/admin/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/admin/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/admin/__pycache__/filter.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/admin/__pycache__/widgets.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/admin/filter.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/admin/widgets.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/apps.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/auth/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/auth/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/auth/__pycache__/mixins.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/auth/mixins.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/collision_resolvers.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/compat.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/app_template/__init__.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/app_template/forms.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/app_template/migrations/__init__.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/app_template/models.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/app_template/urls.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/app_template/views.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/command_template/management/__init__.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/command_template/management/commands/__init__.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/command_template/management/commands/sample.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/__init__.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/daily/__init__.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/hourly/__init__.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/monthly/__init__.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/sample.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/weekly/__init__.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/yearly/__init__.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/template_tags_template/templatetags/__init__.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/conf/template_tags_template/templatetags/sample.py.tmpl create mode 100644 venv/lib/python3.7/site-packages/django_extensions/db/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/db/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/db/__pycache__/models.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/db/fields/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/db/fields/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/db/fields/__pycache__/json.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/db/fields/json.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/db/models.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/import_subclasses.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__pycache__/cache_cleanup.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__pycache__/daily_cleanup.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/daily/cache_cleanup.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/daily/daily_cleanup.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/hourly/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/hourly/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/minutely/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/minutely/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/monthly/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/monthly/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/weekly/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/weekly/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/yearly/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/jobs/yearly/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/da/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/da/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/de/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/de/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/el/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/el/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/en/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/en/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/es/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/es/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/fr/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/fr/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/hu/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/hu/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/id/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/id/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/it/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/it/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/ja/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/ja/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/pl/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/pl/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/pt/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/pt/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/pt_BR/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/pt_BR/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/ro/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/ro/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/ru/LC_MESSAGES/django.mo create mode 100644 venv/lib/python3.7/site-packages/django_extensions/locale/ru/LC_MESSAGES/django.po create mode 100644 venv/lib/python3.7/site-packages/django_extensions/logging/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/logging/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/logging/__pycache__/filters.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/logging/filters.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/base.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/color.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/debug_cursor.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/email_notifications.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/jobs.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/modelviz.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/mysql.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/notebook_extension.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/shells.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/signals.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/technical_response.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/utils.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/base.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/color.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/admin_generator.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/clean_pyc.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/clear_cache.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/compile_pyc.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/create_command.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/create_jobs.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/create_template_tags.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/delete_squashed_migrations.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/describe_form.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/drop_test_database.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/dumpscript.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/export_emails.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/find_template.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/generate_password.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/generate_secret_key.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/graph_models.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/list_model_info.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/list_signals.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/mail_debug.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/merge_model_instances.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/notes.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/pipchecker.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/print_settings.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/print_user_for_session.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/reset_db.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/reset_schema.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/runjob.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/runjobs.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/runprofileserver.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/runscript.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/runserver_plus.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/set_default_site.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/set_fake_emails.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/set_fake_passwords.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/shell_plus.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/show_template_tags.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/show_urls.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/sqlcreate.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/sqldiff.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/sqldsn.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/sync_s3.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/syncdata.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/unreferenced_files.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/update_permissions.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/validate_templates.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/admin_generator.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/clean_pyc.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/clear_cache.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/compile_pyc.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/create_command.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/create_jobs.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/create_template_tags.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/delete_squashed_migrations.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/describe_form.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/drop_test_database.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/dumpscript.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/export_emails.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/find_template.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/generate_password.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/generate_secret_key.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/graph_models.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/list_model_info.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/list_signals.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/mail_debug.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/merge_model_instances.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/notes.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/pipchecker.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/print_settings.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/print_user_for_session.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/reset_db.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/reset_schema.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/runjob.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/runjobs.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/runprofileserver.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/runscript.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/runserver_plus.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/set_default_site.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/set_fake_emails.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/set_fake_passwords.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/shell_plus.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/show_template_tags.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/show_urls.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/sqlcreate.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/sqldiff.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/sqldsn.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/sync_s3.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/syncdata.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/unreferenced_files.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/update_permissions.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/commands/validate_templates.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/debug_cursor.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/email_notifications.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/jobs.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/modelviz.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/mysql.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/notebook_extension.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/shells.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/signals.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/technical_response.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/management/utils.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/models.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/mongodb/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/mongodb/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/mongodb/__pycache__/models.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/__pycache__/json.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/json.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/mongodb/models.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/settings.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/css/jquery.autocomplete.css create mode 100644 venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/img/indicator.gif create mode 100644 venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.ajaxQueue.js create mode 100644 venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.autocomplete.js create mode 100644 venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.bgiframe.js create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templates/django_extensions/graph_models/django2018/digraph.dot create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templates/django_extensions/graph_models/django2018/label.dot create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templates/django_extensions/graph_models/django2018/relation.dot create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templates/django_extensions/graph_models/original/digraph.dot create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templates/django_extensions/graph_models/original/label.dot create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templates/django_extensions/graph_models/original/relation.dot create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templates/django_extensions/widgets/foreignkey_searchinput.html create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/__pycache__/debugger_tags.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/__pycache__/highlighting.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/__pycache__/indent_text.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/__pycache__/syntax_color.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/__pycache__/widont.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/debugger_tags.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/highlighting.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/indent_text.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/syntax_color.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/templatetags/widont.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/utils/__init__.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/utils/__pycache__/__init__.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/utils/__pycache__/deprecation.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/utils/__pycache__/dia2django.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/utils/__pycache__/internal_ips.cpython-37.pyc create mode 100644 venv/lib/python3.7/site-packages/django_extensions/utils/deprecation.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/utils/dia2django.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/utils/internal_ips.py create mode 100644 venv/lib/python3.7/site-packages/django_extensions/validators.py diff --git a/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/INSTALLER b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/LICENSE b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/LICENSE new file mode 100644 index 0000000..279c6da --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2007 Michael Trier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/METADATA b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/METADATA new file mode 100644 index 0000000..c1bd714 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/METADATA @@ -0,0 +1,160 @@ +Metadata-Version: 2.1 +Name: django-extensions +Version: 3.1.0 +Summary: Extensions for Django +Home-page: http://github.com/django-extensions/django-extensions +Author: Michael Trier +Author-email: mtrier@gmail.com +Maintainer: Bas van Oostveen +Maintainer-email: v.oostveen@gmail.com +License: MIT License +Platform: any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Django +Classifier: Framework :: Django :: 2.2 +Classifier: Framework :: Django :: 3.0 +Classifier: Framework :: Django :: 3.1 +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Utilities +Requires-Python: >=3.5 + +=================== + Django Extensions +=================== + +.. image:: https://img.shields.io/pypi/l/django-extensions.svg + :target: https://raw.githubusercontent.com/django-extensions/django-extensions/master/LICENSE + +.. image:: https://secure.travis-ci.org/django-extensions/django-extensions.svg?branch=master + :alt: Build Status + :target: http://travis-ci.org/django-extensions/django-extensions + +.. image:: https://img.shields.io/pypi/v/django-extensions.svg + :target: https://pypi.python.org/pypi/django-extensions/ + :alt: Latest PyPI version + +.. image:: https://img.shields.io/pypi/wheel/django-extensions.svg + :target: https://pypi.python.org/pypi/django-extensions/ + :alt: Supports Wheel format + +.. image:: https://coveralls.io/repos/django-extensions/django-extensions/badge.svg?branch=master + :target: https://coveralls.io/r/django-extensions/django-extensions?branch=master + :alt: Coverage + +Django Extensions is a collection of custom extensions for the Django Framework. + + +Getting Started +=============== + +The easiest way to figure out what Django Extensions are all about is to watch the +`excellent screencast by Eric Holscher`__ (`watch the video on vimeo`__). In a couple +minutes Eric walks you through a half a dozen command extensions. There is also a +`short screencast on GoDjango's Youtube Channel`__ to help show you even more. + + +Requirements +============ + +Django Extensions requires Django 2.2 or later. + + +Getting It +========== + +You can get Django Extensions by using pip:: + + $ pip install django-extensions + +If you want to install it from source, grab the git repository from GitHub and run setup.py:: + + $ git clone git://github.com/django-extensions/django-extensions.git + $ cd django-extensions + $ python setup.py install + + +Installing It +============= + +To enable `django_extensions` in your project you need to add it to `INSTALLED_APPS` in your projects +`settings.py` file:: + + INSTALLED_APPS = ( + ... + 'django_extensions', + ... + ) + + +Using It +======== + +Generate (and view) a graphviz graph of app models:: + + $ python manage.py graph_models -a -o myapp_models.png + +Produce a tab-separated list of `(url_pattern, view_function, name)` tuples for a project:: + + $ python manage.py show_urls + +Check templates for rendering errors:: + + $ python manage.py validate_templates + +Run the enhanced django shell:: + + $ python manage.py shell_plus + +Run the enhanced django runserver, (requires Werkzeug install):: + + $ python manage.py runserver_plus + + +Getting Involved +================ + +Open Source projects can always use more help. Fixing a problem, documenting a feature, adding +translation in your language. If you have some time to spare and like to help us, here are the places to do so: + +- GitHub: https://github.com/django-extensions/django-extensions +- Mailing list: http://groups.google.com/group/django-extensions +- Translations: https://www.transifex.net/projects/p/django-extensions/ + + +Documentation +============= + +You can view documentation online at: + +- https://django-extensions.readthedocs.io + +Or you can look at the docs/ directory in the repository. + + +Support +======= + +Django Extensions is free and always will be. It is development and maintained by developers in an Open Source manner. +Any support is welcome. You could help by writing documentation, pull-requests, report issues and/or translations. + +Please remember that nobody is paid directly to develop or maintain Django Extensions so we do have to divide our time +between putting food on the table, family, this project and the rest of life :-) + + +__ http://ericholscher.com/blog/2008/sep/12/screencast-django-command-extensions/ +__ http://vimeo.com/1720508 +__ https://www.youtube.com/watch?v=1F6G3ONhr4k + + diff --git a/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/RECORD b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/RECORD new file mode 100644 index 0000000..e721c19 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/RECORD @@ -0,0 +1,269 @@ +django_extensions-3.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +django_extensions-3.1.0.dist-info/LICENSE,sha256=hfh-J08r7s6vlJVWdNgyPZ_B69b8NdSvzdOLVEygyyA,1057 +django_extensions-3.1.0.dist-info/METADATA,sha256=s6kXf5nBkTspRmS5YFVVQvDe724Mhvw3heUNnWWS24E,5017 +django_extensions-3.1.0.dist-info/RECORD,, +django_extensions-3.1.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions-3.1.0.dist-info/WHEEL,sha256=EVRjI69F5qVjm_YgqcTXPnTAv3BfSUr0WVAHuSP3Xoo,92 +django_extensions-3.1.0.dist-info/top_level.txt,sha256=a-Shg8eC0Rl6_AoTRvqIUhzOFzQeCFU1Z7ee7myIYMg,18 +django_extensions/__init__.py,sha256=UgrVIRBD1b4giDXwgcRs3XYQEKTuc9by2RG1QFSGCnc,533 +django_extensions/__pycache__/__init__.cpython-37.pyc,, +django_extensions/__pycache__/apps.cpython-37.pyc,, +django_extensions/__pycache__/collision_resolvers.cpython-37.pyc,, +django_extensions/__pycache__/compat.cpython-37.pyc,, +django_extensions/__pycache__/import_subclasses.cpython-37.pyc,, +django_extensions/__pycache__/models.cpython-37.pyc,, +django_extensions/__pycache__/settings.cpython-37.pyc,, +django_extensions/__pycache__/validators.cpython-37.pyc,, +django_extensions/admin/__init__.py,sha256=-gJP3Ttnx-bAFgZLo7zguKH2FlSFNfL99hrpj4eysxc,6853 +django_extensions/admin/__pycache__/__init__.cpython-37.pyc,, +django_extensions/admin/__pycache__/filter.cpython-37.pyc,, +django_extensions/admin/__pycache__/widgets.cpython-37.pyc,, +django_extensions/admin/filter.py,sha256=1MFZ71zlx1fp5QdKxOe3GpTu2yMKWeHOPxObLAk1JjU,1819 +django_extensions/admin/widgets.py,sha256=7Auq1-VIsdbLW20tpVjEB2cAfL6YqDteHEwXr0gYcKE,3191 +django_extensions/apps.py,sha256=oJlK-RUVkhL9ZKtjS3vKsEJJc17UmYbQMEdS8Ocbf3s,171 +django_extensions/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/auth/__pycache__/__init__.cpython-37.pyc,, +django_extensions/auth/__pycache__/mixins.cpython-37.pyc,, +django_extensions/auth/mixins.py,sha256=t55Wjt2B0tSaW10liVHj8NSJb6yyKbmcGCJv8sQP89o,488 +django_extensions/collision_resolvers.py,sha256=roO-zKNAt6PEcN6FZVl4scP6ujM73ppZw48dLMLUJrQ,10644 +django_extensions/compat.py,sha256=xQT_I6tUhWYRvupMj10gxo9fvkwE47iZ0L_Ee0MKQXs,1930 +django_extensions/conf/app_template/__init__.py.tmpl,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/conf/app_template/forms.py.tmpl,sha256=_K9nXjI1BEn-aPQYmNM9mcBwp21EnzAvtHF6lXeLQmY,55 +django_extensions/conf/app_template/migrations/__init__.py.tmpl,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/conf/app_template/models.py.tmpl,sha256=Vjc0p2XbAPgE6HyTF6vll98A4eDhA5AvaQqsc4kQ9AQ,57 +django_extensions/conf/app_template/urls.py.tmpl,sha256=nzK9G5Qi-8ECvgQ-5A5UhVYB9nmKTuWxKkrqWYgSzS4,69 +django_extensions/conf/app_template/views.py.tmpl,sha256=F42JXgnqFqK0fajXeutyJJxwOszRxoLMNkIhfc4Z7KI,26 +django_extensions/conf/command_template/management/__init__.py.tmpl,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/conf/command_template/management/commands/__init__.py.tmpl,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/conf/command_template/management/commands/sample.py.tmpl,sha256=VWqndBmkpZ5jw_3DrisYjXD76Si5lVSVcZlkifG57gs,306 +django_extensions/conf/jobs_template/jobs/__init__.py.tmpl,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/conf/jobs_template/jobs/daily/__init__.py.tmpl,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/conf/jobs_template/jobs/hourly/__init__.py.tmpl,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/conf/jobs_template/jobs/monthly/__init__.py.tmpl,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/conf/jobs_template/jobs/sample.py.tmpl,sha256=r2cd8E0jNTKIJYQmPULuxjZFxzg1yrv72IHsipWkWtY,178 +django_extensions/conf/jobs_template/jobs/weekly/__init__.py.tmpl,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/conf/jobs_template/jobs/yearly/__init__.py.tmpl,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/conf/template_tags_template/templatetags/__init__.py.tmpl,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/conf/template_tags_template/templatetags/sample.py.tmpl,sha256=IOMcdXaX3IBAawoGoteRYqF5Y2ggxsLweR5XZqxfpMk,59 +django_extensions/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/db/__pycache__/__init__.cpython-37.pyc,, +django_extensions/db/__pycache__/models.cpython-37.pyc,, +django_extensions/db/fields/__init__.py,sha256=sd1YBoBKQOQNPmzT4dbnvL6zgnMN2l9PwOzkQCGFKbg,20607 +django_extensions/db/fields/__pycache__/__init__.cpython-37.pyc,, +django_extensions/db/fields/__pycache__/json.cpython-37.pyc,, +django_extensions/db/fields/json.py,sha256=WfaRzlIwxCHgppPMAI1QOlq2WfDr5rsUMlFkpy6peTY,2862 +django_extensions/db/models.py,sha256=i2Aa72Driz1LSf1ed4kFZqKK18ZZd8pkCAurUPQw6bg,3811 +django_extensions/import_subclasses.py,sha256=sPRpMDQDobPnefJq7M9_B0Gn7-VcXofaWi4Maee7XFE,2291 +django_extensions/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/jobs/__pycache__/__init__.cpython-37.pyc,, +django_extensions/jobs/daily/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/jobs/daily/__pycache__/__init__.cpython-37.pyc,, +django_extensions/jobs/daily/__pycache__/cache_cleanup.cpython-37.pyc,, +django_extensions/jobs/daily/__pycache__/daily_cleanup.cpython-37.pyc,, +django_extensions/jobs/daily/cache_cleanup.py,sha256=KcT78D0Y3a4orSlG0eTfh1HqebRn48iYXCxUkyuiww0,646 +django_extensions/jobs/daily/daily_cleanup.py,sha256=r_NSWoDPWlR2GvubWt4GZIgjx24GBeNOfOlIRpRu1wI,388 +django_extensions/jobs/hourly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/jobs/hourly/__pycache__/__init__.cpython-37.pyc,, +django_extensions/jobs/minutely/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/jobs/minutely/__pycache__/__init__.cpython-37.pyc,, +django_extensions/jobs/monthly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/jobs/monthly/__pycache__/__init__.cpython-37.pyc,, +django_extensions/jobs/weekly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/jobs/weekly/__pycache__/__init__.cpython-37.pyc,, +django_extensions/jobs/yearly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/jobs/yearly/__pycache__/__init__.cpython-37.pyc,, +django_extensions/locale/da/LC_MESSAGES/django.mo,sha256=R7WNKaXc0q4iM1cUsgzdbdRZ08r7m14EmM1znFTo1FI,797 +django_extensions/locale/da/LC_MESSAGES/django.po,sha256=Zl33Wn5Sz6JsDUcbR_2aMtFCTqmDYz1XpXXsrY2GBl0,1667 +django_extensions/locale/de/LC_MESSAGES/django.mo,sha256=kuhHiXWrfazxsvFzvENWfY5sN3XpLvy1-AKQ0jKOnAs,1227 +django_extensions/locale/de/LC_MESSAGES/django.po,sha256=OLFLDJbZLPk3oK5DUcJ-V7eeBKZcHjlu_Vl0WTHW9F4,1755 +django_extensions/locale/el/LC_MESSAGES/django.mo,sha256=0CafRFBnuy4QdqtoaipoKpONaVMvtfP1J_4eMBB2gAg,1581 +django_extensions/locale/el/LC_MESSAGES/django.po,sha256=UC2b1GCXVnUteg1ZFqooRp6wkcxBufQGWCSZW8Hxndw,2116 +django_extensions/locale/en/LC_MESSAGES/django.mo,sha256=9JJOWscsqQUH_P7IWH5P5MEJPDJjDGzGl-Zz5-xGDFo,367 +django_extensions/locale/en/LC_MESSAGES/django.po,sha256=l27VRI3peRt_aKdlaQ7zVXj03wR2PfIex2X3SWrrSBc,2229 +django_extensions/locale/es/LC_MESSAGES/django.mo,sha256=SH8ojro4wqhcR8yKM2vn9JVxTMbke7zwUjsc_W60jfA,1260 +django_extensions/locale/es/LC_MESSAGES/django.po,sha256=euh9NBu3f-f-CuNgPGaJDebN0TbalfKKJ_X5q55VqA8,1788 +django_extensions/locale/fr/LC_MESSAGES/django.mo,sha256=XIMBOSYt8pHAhP3pUBs1N-iKLn3e0LRgTNYe_ippr58,743 +django_extensions/locale/fr/LC_MESSAGES/django.po,sha256=kU4F92g2mcd5y73onqKOM5F3V1YkIUk9ezu1OrKiQi0,1930 +django_extensions/locale/hu/LC_MESSAGES/django.mo,sha256=7rWzOkIurHDcvi4uCgh4hkQjUpV182FSyjKZz6mIBFU,1242 +django_extensions/locale/hu/LC_MESSAGES/django.po,sha256=SOHXX186PGybAII05VA5QRZvSjtXR9fLJpgS2acxwt8,1770 +django_extensions/locale/id/LC_MESSAGES/django.mo,sha256=X3tKDCM5qiuVi5dYOnzxAxx6mQ3w-wTJBvP7_ENnHhg,1508 +django_extensions/locale/id/LC_MESSAGES/django.po,sha256=a4dguUsySnXLdDDafyXcq2lXFmYN-DS6uoEOQQJGEV4,2243 +django_extensions/locale/it/LC_MESSAGES/django.mo,sha256=y3dS8jT30b2P9il5kxQaCj_JgaLLCCkR_vLEllX8L0g,1247 +django_extensions/locale/it/LC_MESSAGES/django.po,sha256=AENMGV_gkuUqp2gVWnENI5hlCtJipNykZkAWcvlRia0,1775 +django_extensions/locale/ja/LC_MESSAGES/django.mo,sha256=5fTQjN83bExfQbkaAMq3zve2B3fEWkf6rF-QYGZf9fA,1397 +django_extensions/locale/ja/LC_MESSAGES/django.po,sha256=CGrMk9hH64qBE_6NF-qPMwHpdfW57FwY3PlF0g0_g0M,1925 +django_extensions/locale/pl/LC_MESSAGES/django.mo,sha256=G3yZYzIwUHJ0PK14VhRXxJaYSXRkBQWa4yfFwJyhSBs,2002 +django_extensions/locale/pl/LC_MESSAGES/django.po,sha256=hVRdMxQmgRhtruCm66bZQVY-OIfSSYVBSJViuZNHB_4,2788 +django_extensions/locale/pt/LC_MESSAGES/django.mo,sha256=F_q92e6dFwPbjvYWHNBvCjgd5mIj3_ezrHvCOFeUZCw,1262 +django_extensions/locale/pt/LC_MESSAGES/django.po,sha256=oKucDPxqIFZAOeVa_mbvOsmXXwyTydd82_Z_pXpkfvI,1790 +django_extensions/locale/pt_BR/LC_MESSAGES/django.mo,sha256=bN2RG97zI3S6qEuMmvbDvPCo4YSZ_KEY5UxviD9WzlA,1310 +django_extensions/locale/pt_BR/LC_MESSAGES/django.po,sha256=VDIRUodyxJr4PDcgiOuR6o3k1Ss_4ge5rx0DZgk5QwY,2082 +django_extensions/locale/ro/LC_MESSAGES/django.mo,sha256=8-8B-I7iFCGZKBj1XKMbMqQLl6Yg2W1IEG39miSI8Hk,1352 +django_extensions/locale/ro/LC_MESSAGES/django.po,sha256=CWaWS2C08-8lNWMCtPSPvDj4xONYrD3UGx4QSWXuWgg,1891 +django_extensions/locale/ru/LC_MESSAGES/django.mo,sha256=C_kjCXvZuZ2ZdiU8ffcjKwcnA-d5IiUTgpglX7JdD-U,2009 +django_extensions/locale/ru/LC_MESSAGES/django.po,sha256=luenXP4hypDODQUVWowDSCkYW9VMF_9NBlTUVkAmB3o,3820 +django_extensions/logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/logging/__pycache__/__init__.cpython-37.pyc,, +django_extensions/logging/__pycache__/filters.cpython-37.pyc,, +django_extensions/logging/filters.py,sha256=02Yp6Xmcp5ORr-JweyG6xHBZZsOKD0DnqbgXHVewGSI,1126 +django_extensions/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/management/__pycache__/__init__.cpython-37.pyc,, +django_extensions/management/__pycache__/base.cpython-37.pyc,, +django_extensions/management/__pycache__/color.cpython-37.pyc,, +django_extensions/management/__pycache__/debug_cursor.cpython-37.pyc,, +django_extensions/management/__pycache__/email_notifications.cpython-37.pyc,, +django_extensions/management/__pycache__/jobs.cpython-37.pyc,, +django_extensions/management/__pycache__/modelviz.cpython-37.pyc,, +django_extensions/management/__pycache__/mysql.cpython-37.pyc,, +django_extensions/management/__pycache__/notebook_extension.cpython-37.pyc,, +django_extensions/management/__pycache__/shells.cpython-37.pyc,, +django_extensions/management/__pycache__/signals.cpython-37.pyc,, +django_extensions/management/__pycache__/technical_response.cpython-37.pyc,, +django_extensions/management/__pycache__/utils.cpython-37.pyc,, +django_extensions/management/base.py,sha256=onLx3r71rBL0Io91s05V9yvXg4BGxvd9o3sYaMn4CIA,1431 +django_extensions/management/color.py,sha256=rQcRJBfXdsV4LlM15dONb_n_rzRL2qXH1c1-WljiNcM,907 +django_extensions/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/management/commands/__pycache__/__init__.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/admin_generator.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/clean_pyc.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/clear_cache.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/compile_pyc.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/create_command.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/create_jobs.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/create_template_tags.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/delete_squashed_migrations.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/describe_form.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/drop_test_database.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/dumpscript.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/export_emails.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/find_template.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/generate_password.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/generate_secret_key.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/graph_models.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/list_model_info.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/list_signals.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/mail_debug.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/merge_model_instances.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/notes.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/pipchecker.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/print_settings.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/print_user_for_session.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/reset_db.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/reset_schema.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/runjob.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/runjobs.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/runprofileserver.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/runscript.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/runserver_plus.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/set_default_site.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/set_fake_emails.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/set_fake_passwords.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/shell_plus.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/show_template_tags.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/show_urls.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/sqlcreate.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/sqldiff.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/sqldsn.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/sync_s3.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/syncdata.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/unreferenced_files.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/update_permissions.cpython-37.pyc,, +django_extensions/management/commands/__pycache__/validate_templates.cpython-37.pyc,, +django_extensions/management/commands/admin_generator.py,sha256=TAGUX36o-wxVmfXOzDhSuSqJcByjkNNR7BudhbKUQlk,11791 +django_extensions/management/commands/clean_pyc.py,sha256=dArLJ7HXcJHoaXdfMAzNpQgcpMPGVQzAuDWLBDEChgU,1523 +django_extensions/management/commands/clear_cache.py,sha256=y44-TSpULDtIwhpCsV7Ii2ofsYjNIgHrEPUixoDepsU,1486 +django_extensions/management/commands/compile_pyc.py,sha256=YrXmZO2MNFkNfcCb4CAnppRR4_Ggkv_r76raA77xVxE,1241 +django_extensions/management/commands/create_command.py,sha256=L9h1R2NlVK0C74dPXymaI7wmkWwh9piNEDKiUIEZPKk,3748 +django_extensions/management/commands/create_jobs.py,sha256=d6-wAaKtes7A3GkJwxVso89PBuYnuiiT-XZyZcOU8YQ,2425 +django_extensions/management/commands/create_template_tags.py,sha256=qQ32iY08O8yYjcXwyS2MQZGKbwr1lPL20itakud66K4,2823 +django_extensions/management/commands/delete_squashed_migrations.py,sha256=_Ktv14Yw-w0YvmitUR-1TqZEJjP3uMEt-rDf8pVvV0A,7241 +django_extensions/management/commands/describe_form.py,sha256=LSgGaFjL2mGs5aWoqQefaPXAvhmHoFGTLK5OX9kmpss,2737 +django_extensions/management/commands/drop_test_database.py,sha256=SdsUMoJs-qlcy6umERHQ3B6p7eO4UDPYo6XTA4RAScI,5805 +django_extensions/management/commands/dumpscript.py,sha256=yBec7XSgpkBHMX4Nas6usYHlXTtM5_wdzYYQGtbkJJQ,27651 +django_extensions/management/commands/export_emails.py,sha256=AzR__ZLuVMBR0ZHtLIKI9FCwrjU9QBa5sJA3az-0uSk,5565 +django_extensions/management/commands/find_template.py,sha256=k9Nj_Ll_LdL8dWz-n3eZV7XeYO8h-hRxCIb6ZkiQu-4,695 +django_extensions/management/commands/generate_password.py,sha256=9IYh3FUVGucb2xJOPn4hZutkupPXVkZhwRXop0e_FT4,938 +django_extensions/management/commands/generate_secret_key.py,sha256=83xqSJ7FQQJ04Psl5BnYj4RwG0cUUeqnvMKopk8QXo0,451 +django_extensions/management/commands/graph_models.py,sha256=k9vpQZxxkCwUDRe5_UOkq-ATdWBdWyAIjFuetOUojmo,13180 +django_extensions/management/commands/list_model_info.py,sha256=cfDVmVGNAUDLvgC0rSjRHhK4SX2ALofw6yhHXwVYr-A,6038 +django_extensions/management/commands/list_signals.py,sha256=LIWtwMeJz8Pg1-JPSv9NNi4tsQc0xLr64bWlt7TazwE,2602 +django_extensions/management/commands/mail_debug.py,sha256=9FeOfB5opR1IXbkHqPx6JriQq3qWbSzzofX-D-WVeX8,2894 +django_extensions/management/commands/merge_model_instances.py,sha256=DeoGYz6OnVgprhx3O1gfB9egZ6HYqKk0jJSnFst616w,9552 +django_extensions/management/commands/notes.py,sha256=3sEUcMYk2sNFlbVomXHBJajoQdpRFKlm2IC6AInXhx0,2716 +django_extensions/management/commands/pipchecker.py,sha256=V5p9S9u0FN68buQCOeGr3g6zW-94ki3tVfzetW0bvko,14292 +django_extensions/management/commands/print_settings.py,sha256=pEiCq41QZuoVg4_XtmXabrQquTBJX0TRGeLm1V8N3SM,2640 +django_extensions/management/commands/print_user_for_session.py,sha256=r1Ot7yBsxOwYv8trFuKQVwBXTIUl3m-wyc-Hx_HZ1lA,2144 +django_extensions/management/commands/reset_db.py,sha256=tSXzyMEiAJA6vU_o8wpMOINnjPcLZlAtd70G81dLdMw,7734 +django_extensions/management/commands/reset_schema.py,sha256=aumuxdXbJanxllbulRBbl-OLNvRsxvWLraTUmHJ_a1g,2845 +django_extensions/management/commands/runjob.py,sha256=OMeFDVJgYlTc7NO8aWS-2QgE3pPIwtd8tGrelviGVhE,1987 +django_extensions/management/commands/runjobs.py,sha256=k3Um1dlGPuWIs7P9MPxNDNcCNq3pAdH7cV4xmmcJMRQ,3384 +django_extensions/management/commands/runprofileserver.py,sha256=XBfJqovLmWnXUhdgprBbM8-vgOTm7dM2tZo3Z6OiTFk,11625 +django_extensions/management/commands/runscript.py,sha256=-0nR_Kqs10V3ToB6w4YCTO4igKmmkBhNya__sXpNXlc,12005 +django_extensions/management/commands/runserver_plus.py,sha256=wxZQVWMa0gbbEkG33iUk4PeJQAJSUF_yoHOXEM7GiLQ,21850 +django_extensions/management/commands/set_default_site.py,sha256=LmNNKP84iryahh7cMAVwPlRcJ7EpFsoWTKUpjSxCezQ,2800 +django_extensions/management/commands/set_fake_emails.py,sha256=fZtLNjEFHVre2XZOcbAHRM-C6_o-Zb7_FuQd9vPNLCs,3841 +django_extensions/management/commands/set_fake_passwords.py,sha256=T3TlDt-z0VYAyoq0js7cWLqWqRy2_RZsRvq5t-l1e6Q,1731 +django_extensions/management/commands/shell_plus.py,sha256=Q4itLhgf-GmbBMGndNRpVPi8uH9Mrdv7yAYNLrWo1Wc,21659 +django_extensions/management/commands/show_template_tags.py,sha256=NAiUI80ak_4-szlphl-13RRVv__9MdyO52ELFqDnVvk,3909 +django_extensions/management/commands/show_urls.py,sha256=uz5WNQcykAcmeOf70DDCi-AAUvMkLcmcT1BQ9oAtmi4,9135 +django_extensions/management/commands/sqlcreate.py,sha256=iZ1nsCePzIbPlJKircrAJw_lFNTpAr8pkYwfC9QvqP8,4230 +django_extensions/management/commands/sqldiff.py,sha256=B04cQQT-byyU7J9vtzKzV32GJdvrLlSFzAZRQFN6SSM,63193 +django_extensions/management/commands/sqldsn.py,sha256=DB8W2v3D7wcXeGfCKSaAWyPLFnTYpd5aNW63fWt4dJw,5268 +django_extensions/management/commands/sync_s3.py,sha256=mpz4BjbWJIgSpGKnGbovwzudr0agsErx19aBZfJ1iuY,15720 +django_extensions/management/commands/syncdata.py,sha256=h7QKa0A2HSoTbWpS5U920B02l-Ou-bPr9d-a417ZPFI,9771 +django_extensions/management/commands/unreferenced_files.py,sha256=SMQG4SXhSEkjxSuUteaXVTyJ4StmC9A9mZwYOQBzaco,1787 +django_extensions/management/commands/update_permissions.py,sha256=0KDqKHO5ynSNYtyWkWC9K2uinuSsiAU-hJTy7XO3rnU,3033 +django_extensions/management/commands/validate_templates.py,sha256=GrkhQJQBlGuNI634BLfBToSCirl3b4rh1EzL3OlNyg4,3627 +django_extensions/management/debug_cursor.py,sha256=8f-JS1rt3O-EksKs5hIPB27xlAHQSmaj5icWCeOWqzw,4391 +django_extensions/management/email_notifications.py,sha256=hHPG_1mzJDYf5jchevEOC-rAzhJGM5EOkgYmaRFpk_M,5360 +django_extensions/management/jobs.py,sha256=nPYJH2n2jrjt38TMxBuftvMSHFpgn2hZSa_2XW4mw90,5043 +django_extensions/management/modelviz.py,sha256=kOmEJ8m0EJGcq47hhdsBel6dHaCzIIUAYD-28pY0-go,17254 +django_extensions/management/mysql.py,sha256=xUBDaNhnoGbOPjRtq5zkd5Z8NtmJLdS8MTlHVPigeHQ,1506 +django_extensions/management/notebook_extension.py,sha256=h5-bWrDK8RkoblyiprJZjFRRqbin3Vj8W6PmBWI2KpM,324 +django_extensions/management/shells.py,sha256=2eTZ6s9bSHAtR7u6-IroDuUQAcBGNYxBEhJAPCsxN_8,15410 +django_extensions/management/signals.py,sha256=yWTcyz8hhcB-PLJKeH2UWOAypCIvaeijKy3CfNJ3ZhU,307 +django_extensions/management/technical_response.py,sha256=FbMGGbFMHpwjc6SEQ3vZ0lNmIGL5TnCQzAeDzJzVqBQ,1758 +django_extensions/management/utils.py,sha256=vEWTbV3PrUJwh4r5VK8WGkICTZlAx6uXqo2wypDFAVY,2259 +django_extensions/models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/mongodb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/mongodb/__pycache__/__init__.cpython-37.pyc,, +django_extensions/mongodb/__pycache__/models.cpython-37.pyc,, +django_extensions/mongodb/fields/__init__.py,sha256=a9HmyN0YjPG3MN9kM_m79l0fwVaIKWNXa6h3E2PdnvM,9341 +django_extensions/mongodb/fields/__pycache__/__init__.cpython-37.pyc,, +django_extensions/mongodb/fields/__pycache__/json.cpython-37.pyc,, +django_extensions/mongodb/fields/json.py,sha256=ep3CuSkBE5LyixMbmFo2u_jK2D4J9aziIlCra5Fb-w8,2158 +django_extensions/mongodb/models.py,sha256=BVvXqlgVEfWNUy19ykvlwD0qXv0B3gGcIiPi7RBcJjc,2405 +django_extensions/settings.py,sha256=CdN-y7loiLzEyIicwj1OQPViTFZZQdXHNTnKxMipzg8,1079 +django_extensions/static/django_extensions/css/jquery.autocomplete.css,sha256=3yUz9XJFKdXHv34Xe4QNWjA9ghEr2ieEoQ0KaO3e49Q,740 +django_extensions/static/django_extensions/img/indicator.gif,sha256=0-OUTUZJRQ3uZqVcae7O0tgltsoaNJ9yx1_TeArj8AY,1553 +django_extensions/static/django_extensions/js/jquery.ajaxQueue.js,sha256=IVCgQ2MMHxrmrHMc4Pu0TxdEaVhuQSofxotZgEffUdk,2911 +django_extensions/static/django_extensions/js/jquery.autocomplete.js,sha256=5DV9zxN6TgVpbkscqlkoiK5qhEEGdmxV2v7d265QQog,36679 +django_extensions/static/django_extensions/js/jquery.bgiframe.js,sha256=JLLyZyn1DRAFry-ikBRSrf0qfX6PsqTFkwnPu9jj68k,1820 +django_extensions/templates/django_extensions/graph_models/django2018/digraph.dot,sha256=dqhYYv2LnG31IFxqooP5zplpABcQKxgSkLDdX1rL6EI,818 +django_extensions/templates/django_extensions/graph_models/django2018/label.dot,sha256=vsKxchMm6DQVTPx8gFxijpHOGNJuqdItN2WEI8mvc14,1875 +django_extensions/templates/django_extensions/graph_models/django2018/relation.dot,sha256=6KlECRFCmCmTTOQs5vYEr2sPWdDgiUbgH4ZkWLt_SjE,589 +django_extensions/templates/django_extensions/graph_models/original/digraph.dot,sha256=D2Kh5rWOJcIFeXChDHm7hotL0sTqgnGQpghWDHkUyZM,823 +django_extensions/templates/django_extensions/graph_models/original/label.dot,sha256=0-UHhFDl-XTkOr1wUAoEBd-xSfnAea922vUX0N1cCeQ,1697 +django_extensions/templates/django_extensions/graph_models/original/relation.dot,sha256=Y-wvocs_14QreSILBv9ESWvnF6B3pUcrRrjx_q0oINk,591 +django_extensions/templates/django_extensions/widgets/foreignkey_searchinput.html,sha256=8DhLt6B0oUlpVq1gSoPy4uImyJxUueUczwYHraZeKNg,2032 +django_extensions/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_extensions/templatetags/__pycache__/__init__.cpython-37.pyc,, +django_extensions/templatetags/__pycache__/debugger_tags.cpython-37.pyc,, +django_extensions/templatetags/__pycache__/highlighting.cpython-37.pyc,, +django_extensions/templatetags/__pycache__/indent_text.cpython-37.pyc,, +django_extensions/templatetags/__pycache__/syntax_color.cpython-37.pyc,, +django_extensions/templatetags/__pycache__/widont.cpython-37.pyc,, +django_extensions/templatetags/debugger_tags.py,sha256=M6RUSObtGln_LQXDeu8m396auIOAsxdnJQa3AeV5T1I,596 +django_extensions/templatetags/highlighting.py,sha256=v94urI9kE6-Z-2Cm0F5glgY-crh89fp0jdKsFNl_FOk,3224 +django_extensions/templatetags/indent_text.py,sha256=ByaKtl7VaPBx_4PB3V-Bg9foY1zvraZ2VNHBh5gBdek,1751 +django_extensions/templatetags/syntax_color.py,sha256=X6aMvDIxHHBt_AFaR4qXHAmafpPsitZshUN4_FiJ1Pc,3171 +django_extensions/templatetags/widont.py,sha256=6uTu7oGT98rPy1TaTRUOE3A6LkLell_XyVIWPmt_uZo,1925 +django_extensions/utils/__init__.py,sha256=Xb0RrRwc1dqCwkASV8I2MSLy14c_FhmE1HeaxxaeO1E,70 +django_extensions/utils/__pycache__/__init__.cpython-37.pyc,, +django_extensions/utils/__pycache__/deprecation.cpython-37.pyc,, +django_extensions/utils/__pycache__/dia2django.cpython-37.pyc,, +django_extensions/utils/__pycache__/internal_ips.cpython-37.pyc,, +django_extensions/utils/deprecation.py,sha256=XfN9X_w6PGMvQ5JldtdYZyqSNvO5w9TTaST8nZvQl2U,155 +django_extensions/utils/dia2django.py,sha256=YWerQ-Fh5qgH5C72riN3jrqT64BEF3u0L0H2dbUMgx0,10177 +django_extensions/utils/internal_ips.py,sha256=O8XzFk_In7xSaSAtTjKMorSyib7GxiPTVeAapad80QM,1952 +django_extensions/validators.py,sha256=mTPGQ5xVqo8ei4Zmuz8uusaI-sjVa2qLrPZpG_iB__g,3754 diff --git a/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/REQUESTED b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/WHEEL b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/WHEEL new file mode 100644 index 0000000..83ff02e --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/top_level.txt b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/top_level.txt new file mode 100644 index 0000000..ee49386 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions-3.1.0.dist-info/top_level.txt @@ -0,0 +1 @@ +django_extensions diff --git a/venv/lib/python3.7/site-packages/django_extensions/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/__init__.py new file mode 100644 index 0000000..0330155 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +VERSION = (3, 1, 0) + + +def get_version(version): + """Dynamically calculate the version based on VERSION tuple.""" + if len(version) > 2 and version[2] is not None: + if isinstance(version[2], int): + str_version = "%s.%s.%s" % version[:3] + else: + str_version = "%s.%s_%s" % version[:3] + else: + str_version = "%s.%s" % version[:2] + + return str_version + + +__version__ = get_version(VERSION) + +default_app_config = 'django_extensions.apps.DjangoExtensionsConfig' diff --git a/venv/lib/python3.7/site-packages/django_extensions/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8ea9f89d07645bef84aa268ad20f9f78f814854 GIT binary patch literal 647 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 N=D(S9Q)5$O{|6kNFc|;< literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/__pycache__/compat.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/__pycache__/compat.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10f5f9e211d856f7fd5ed9eb1162cc50317b88c9 GIT binary patch literal 2336 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/__pycache__/validators.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/__pycache__/validators.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d54168f244f8553bed2a942979abe5e784aa30f GIT binary patch literal 3736 zcmb_fOOM>f5oR|Z!+Gq=k+qJsQ4~gw9Zw+7ATgi>K_Cc`?Kprv2@ofW2^b8Q-8;)2 z4!P>)NIQesi`Q3QeD=XUCVwJ-ASWMr%_+xRbMjYB&STdr%ZG5##bQ6mdVN(jzunpC zSh&9W=YOMr>{`~p>0xy_U>;!T1&FW&%dD`zvykDLXMAdhHlsN^bEa6)1x!Tx0Rd;h`rtx=y< z*ZvY`sff$8$lq3~P&6fEQslZ+v!qN9GKs17VWAQkVGa+yu`Ek@T1HvCm?!k2)n$Wu zfT8b!NQ+boxwHj?aE{=iE9}q{9pMP~6Bf2=;X_{-k;AsIAzHV(H7Xt!d8vx*;ZdyO zq?AfGQWk3Q>t-$3ECyLRkwGq>g2|;03Kf*`fevDY*`f^MEGwQ$F$nkaB7$o4>L^*i zdz6q{=%PEvc!;6zfGnBnEZNeEtR+`BmK+>g+UoYw2FHa3dD*CMSFNekIv&f)NeUsW z_S2)Zlv%3FzEe3`W{0YUw<(`U8|3en>f-jl@$k-Z+Vq2|lZb;yBL7MFg+NT*H?*Qv0<~ zdT=tY{3uHEw2Y$f;j_92Vljt#%~-tpZ6+VA&L(6Vy1Zr>JN*q0B`kH$&S0rycE(G7 zY@gYu?=0C{)<^fx9N6ye5_ICJyN~x_JLjAUb`#+~;c6fD<--1)pSh)j^Dc(BbcOS& z{V{vI{|HckmEDnI_)f(h_Ic$(x0y7C>~mw($~!@%Om)Ad$cJXB>dx|%+=1whD?f=# zIWE*(krEqs^gTszRo7O>)OB!GdmSF?1zI6*)r4$E=1dS(QFIeenod~EhdDjgVLis# z3%EbmsP!AxMkTojK*p#8Fl5w{o%7-@Ov0D!80Ip(4c=~e2fQ=kbs)M`C)FvS8|R5s zU6Ihzg7$TcrR&Z~0GD#P%Nz4}fauon}`mc@**$eyHp?Z*|&Z(pg^H}OsO zb1_UP(recEW=r-3`_h`&Y9PR;2JHw>*CDC)Zgot29^lAc@! zqP+#gD==rG<5wG%d<3S?7SB}a+t78VQOTey*g_Za4Z3PXIcg7k)h!}xi$f=qGhU+E zO{f~fQ~2J;(1gAkKnoPKD}o7T-{7XLCohx zm8To1{O}KXHV@+9NS+4dZ{Q>aJepFx82mmr6)MPNJ}!?2!TU2^1_v^D_4RtDFM@Rr z)`P{HZ|8c3dR`vIC5Qw|<$YSzb2-jU)4Z=Q9J+V)p}e?wE|aEm89#XN7fF z1vsOAOoRe;69ubU^{n;Fu}DGlM+}WN6a|XP)4JmCZ9D6m8Gz)cM#bpx6_|AfK!sQL zN|d8>Q|*xn?v)1pbwx*3z>bs&n=%1-SBdp*cVgkG-tD0NyTYR#Tf05=*?PB!-JdnP zTiA^*5xc$B?)h%n`odqbFB!8QS@~VZD%)l2xO2!S9rZ6}(XTn(!RfB(eab&(A6hy8 zYu!`qjEtqjYbzHvKHW}P#tq?%>m6HBV1qXf+FsrShCPi>)sJ8~^$JLznLef8t^1Pz zQ`Ja9*`Pn4d_~r&n&>t~aU3v@e%Z5tY*q zF*M~V>Q8R4{ng-{?Sfxi4uk(|*1V0+Zbk2NvgVjX-O8FTUW!nYEL}7iXfv)(mp`TN znI8K)q)QU+9r`5I8sDzL(c@?-+WxMh)&8!cZdtt!624S-*nQ?JM0k>9(`J9?J{Os#@uHXC`!=OXc literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/admin/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/admin/__init__.py new file mode 100644 index 0000000..01bd709 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/admin/__init__.py @@ -0,0 +1,165 @@ +# -*- coding: utf-8 -*- +# +# Autocomplete feature for admin panel +# +import operator +from functools import update_wrapper, reduce +from typing import Tuple, Dict, Callable # NOQA + +from django.apps import apps +from django.http import HttpResponse, HttpResponseNotFound +from django.conf import settings +from django.db import models +from django.db.models.query import QuerySet +from django.utils.encoding import smart_str +from django.utils.translation import gettext as _ +from django.utils.text import get_text_list +from django.contrib import admin + +from django_extensions.admin.widgets import ForeignKeySearchInput + + +class ForeignKeyAutocompleteAdminMixin: + """ + Admin class for models using the autocomplete feature. + + There are two additional fields: + - related_search_fields: defines fields of managed model that + have to be represented by autocomplete input, together with + a list of target model fields that are searched for + input string, e.g.: + + related_search_fields = { + 'author': ('first_name', 'email'), + } + + - related_string_functions: contains optional functions which + take target model instance as only argument and return string + representation. By default __unicode__() method of target + object is used. + + And also an optional additional field to set the limit on the + results returned by the autocomplete query. You can set this integer + value in your settings file using FOREIGNKEY_AUTOCOMPLETE_LIMIT or + you can set this per ForeignKeyAutocompleteAdmin basis. If any value + is set the results will not be limited. + """ + + related_search_fields = {} # type: Dict[str, Tuple[str]] + related_string_functions = {} # type: Dict[str, Callable] + autocomplete_limit = getattr(settings, 'FOREIGNKEY_AUTOCOMPLETE_LIMIT', None) + + def get_urls(self): + from django.urls import path + + def wrap(view): + def wrapper(*args, **kwargs): + return self.admin_site.admin_view(view)(*args, **kwargs) + return update_wrapper(wrapper, view) + + return [ + path('foreignkey_autocomplete/', wrap(self.foreignkey_autocomplete), + name='%s_%s_autocomplete' % (self.model._meta.app_label, self.model._meta.model_name)) + ] + super().get_urls() + + def foreignkey_autocomplete(self, request): + """ + Search in the fields of the given related model and returns the + result as a simple string to be used by the jQuery Autocomplete plugin + """ + query = request.GET.get('q', None) + app_label = request.GET.get('app_label', None) + model_name = request.GET.get('model_name', None) + search_fields = request.GET.get('search_fields', None) + object_pk = request.GET.get('object_pk', None) + + try: + to_string_function = self.related_string_functions[model_name] + except KeyError: + to_string_function = lambda x: x.__str__() + + if search_fields and app_label and model_name and (query or object_pk): + def construct_search(field_name): + # use different lookup methods depending on the notation + if field_name.startswith('^'): + return "%s__istartswith" % field_name[1:] + elif field_name.startswith('='): + return "%s__iexact" % field_name[1:] + elif field_name.startswith('@'): + return "%s__search" % field_name[1:] + else: + return "%s__icontains" % field_name + + model = apps.get_model(app_label, model_name) + + queryset = model._default_manager.all() + data = '' + if query: + for bit in query.split(): + or_queries = [models.Q(**{construct_search(smart_str(field_name)): smart_str(bit)}) for field_name in search_fields.split(',')] + other_qs = QuerySet(model) + other_qs.query.select_related = queryset.query.select_related + other_qs = other_qs.filter(reduce(operator.or_, or_queries)) + queryset = queryset & other_qs + + additional_filter = self.get_related_filter(model, request) + if additional_filter: + queryset = queryset.filter(additional_filter) + + if self.autocomplete_limit: + queryset = queryset[:self.autocomplete_limit] + + data = ''.join([str('%s|%s\n') % (to_string_function(f), f.pk) for f in queryset]) + elif object_pk: + try: + obj = queryset.get(pk=object_pk) + except Exception: # FIXME: use stricter exception checking + pass + else: + data = to_string_function(obj) + return HttpResponse(data, content_type='text/plain') + return HttpResponseNotFound() + + def get_related_filter(self, model, request): + """ + Given a model class and current request return an optional Q object + that should be applied as an additional filter for autocomplete query. + If no additional filtering is needed, this method should return + None. + """ + return None + + def get_help_text(self, field_name, model_name): + searchable_fields = self.related_search_fields.get(field_name, None) + if searchable_fields: + help_kwargs = { + 'model_name': model_name, + 'field_list': get_text_list(searchable_fields, _('and')), + } + return _('Use the left field to do %(model_name)s lookups in the fields %(field_list)s.') % help_kwargs + return '' + + def formfield_for_dbfield(self, db_field, **kwargs): + """ + Override the default widget for Foreignkey fields if they are + specified in the related_search_fields class attribute. + """ + if isinstance(db_field, models.ForeignKey) and db_field.name in self.related_search_fields: + help_text = self.get_help_text(db_field.name, db_field.remote_field.model._meta.object_name) + if kwargs.get('help_text'): + help_text = str('%s %s') % (kwargs['help_text'], help_text) + kwargs['widget'] = ForeignKeySearchInput(db_field.remote_field, self.related_search_fields[db_field.name]) + kwargs['help_text'] = help_text + return super().formfield_for_dbfield(db_field, **kwargs) + + +class ForeignKeyAutocompleteAdmin(ForeignKeyAutocompleteAdminMixin, admin.ModelAdmin): + pass + + +class ForeignKeyAutocompleteTabularInline(ForeignKeyAutocompleteAdminMixin, admin.TabularInline): + pass + + +class ForeignKeyAutocompleteStackedInline(ForeignKeyAutocompleteAdminMixin, admin.StackedInline): + pass diff --git a/venv/lib/python3.7/site-packages/django_extensions/admin/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/admin/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d8f166d2188e94dad9c507c5969449d456888502 GIT binary patch literal 6949 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 g>?R literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/admin/__pycache__/filter.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/admin/__pycache__/filter.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a9764c0ed7222193c9b51f4c78986e487aa8d74 GIT binary patch literal 2267 zcma)7OOG2x5bmD$?s_*%c8T%=2_X^<5_TexkPwOji2?`Y3j)LlG@4Aeomr1(obK_G zHM6IUlpDW*!|st^!GGY`S56$ca^kBVd-IS%X{)OrQ`KGlRej~px3@PL+8@9Fon8wW z`;!){=3#OdU4IE7nBXOw@`Q7mJEb#q6W7k&(wq88z}Xi}c*1|mgfIDtn}k>gBE&kB zA=Z(IzGm^pUpS4$++282$WnY&=;lFDHd0}0f2QOtQ!*{6Jm z=o#}^vH}0L&E9ZcmajOM1035TNa}QP2Mj-DZE(h0mh#3qVW)1(Tc>qful2DHSXy@K zVaGpnj>9$-Y!azYgi{5L--ah-7YK%n-Qi;E=Uc~VTIdQ6{Kn$Y1fyC_v&Qt6fJ}bM z)Y$lXK9kBsP_2q4O-e=8h8_)INP*#V7vUoU{9W{^Y>cjrW16?%ogIShOva!?yagbHxIz@nG zrHi`K1M9jwJ5rRSgt{idc#mH~UtC`ksQwC+oRcaVjnwaC^@ zCt}#aV4u~AH?cH(^2to*jTC?ZKuIL2COz#yFuu6C?*274FS$ajvaal6Lav-51r8j+ z&YaFAH@Ps^FWqTeRY0`fdf~rU0LUv)yh|tq4C_A%UB5BfY>K|7*Q8A3%UV>anuHT0^M{z^l017~YP%Su+at@pkYu#VKiFTEQ_I36xC_-I* z?jE5i-X^k7))Ga;)+GJPL)5#_is|kZV|V_Ov8$uvO)6;>h=!83nWiX5^OEMh6bNT! z_r=x%bqPmzE>f1McSz8cW_wwra#@zkLSPSSfvX{M(Vdq|%=+iDs?$Cuc M*Lujap1T|W3+8JRnE(I) literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/admin/__pycache__/widgets.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/admin/__pycache__/widgets.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53c504e92c471466b0c8d720bb12930dbe20b062 GIT binary patch literal 3136 zcmaJ@&5s;M6|d^=`PyAO_Bt5L%w-dX#66ZE3c`zl5CugED}fUsl|ZfDuA15I>5p+$ z&8~OUb6QJCNFZ_NFmvR>zrg>%v9FwRgriTqSG{8|wzEA`)vrF@>-YJq`eZQZ5_tag z&;LYceM0_?gYDx0@pEXZhK>_XbHea#<+QMvMUl31yKtCeXeW0Ik9mf6bH4~!U}!Jz z6kXOew4e8iKIV6F#U- zS-@TH!MMYFe;pH=kYmMGJIvT8m8qihW|oWNma~qp~X-cF|Y!1jFhxgTEyJ!9Udx?i$p&j9#_vo zvwW0LV;vzDywTQQLQ^4h8p3`-p|?zLU(l(&qMBwFcVO1Npc9(XnsV>Y7FgpSE#K!^ zTu!SAFw?ym(;V_0>-WfK-;Dw?FZP=6^$+N&Ytna?S=xNSo09DRevFYPc4 zp?U({7K|7LjV(paZb11(K*U;baF@t=w6IwlX#KqsEA9jUN$yx$PUPC z+_Oq@HFD&@j85ZxAsTxo&KtWr&WzLBZWq^g^Y~cg5!6OxcD@Ib3ZqBBC;Qg&;O$;{ zjVsyKHojeGHZ*k?I&cGth^7~04Gz(EZEtJ@E68(tG;*3jTW772s&Um~4%P%wl$NQE zB8h@7ZISN)E$>0sxUtp}5v&tMNggW&JJF#MZIbt)`w*HkT0w-D_up>C_A3dhj1S5{ zCz{d)ASJcU$t;lll&owMT`1a>Tf3RP@}PIt?uM*LBZ^ zyLG^=4LZTE$+`!-J9S5%BGj$>Ex^^C^%jOr|L(~K@{P81{j8*HA<-@m!zdhW- z!@Nr3Ts;P2%iKVUnY?0mPhatxv+)-QDxYCVzMvmsy)IZY$rMOyP+x^5u`OWxkH{qi^TDhHZ4G zt;O4*IdcIabu6*qSPu{ej>WBc)tQjehXwfobd3kz0R(T{c?`FP#)n~6r6t<|B7!*p zI1NWZ box. + """ + + # Set in subclass to render the widget with a different template + widget_template = None + # Set this to the patch of the search view + search_path = None + + def _media(self): + js_files = [ + static('django_extensions/js/jquery.bgiframe.js'), + static('django_extensions/js/jquery.ajaxQueue.js'), + static('django_extensions/js/jquery.autocomplete.js'), + ] + + return forms.Media( + css={'all': (static('django_extensions/css/jquery.autocomplete.css'), )}, + js=js_files, + ) + media = property(_media) + + def label_for_value(self, value): + key = self.rel.get_related_field().name + obj = self.rel.model._default_manager.get(**{key: value}) + + return Truncator(obj).words(14, truncate='...') + + def __init__(self, rel, search_fields, attrs=None): + self.search_fields = search_fields + super().__init__(rel, site, attrs) + + def render(self, name, value, attrs=None, renderer=None): + if attrs is None: + attrs = {} + opts = self.rel.model._meta + app_label = opts.app_label + model_name = opts.object_name.lower() + related_url = reverse('admin:%s_%s_changelist' % (app_label, model_name)) + if not self.search_path: + self.search_path = urllib.parse.urljoin(related_url, 'foreignkey_autocomplete/') + params = self.url_parameters() + if params: + url = '?' + '&'.join(['%s=%s' % (k, v) for k, v in params.items()]) + else: + url = '' + + if 'class' not in attrs: + attrs['class'] = 'vForeignKeyRawIdAdminField' + # Call the TextInput render method directly to have more control + output = [forms.TextInput.render(self, name, value, attrs)] + + if value: + label = self.label_for_value(value) + else: + label = '' + + context = { + 'url': url, + 'related_url': related_url, + 'search_path': self.search_path, + 'search_fields': ','.join(self.search_fields), + 'app_label': app_label, + 'model_name': model_name, + 'label': label, + 'name': name, + } + output.append(render_to_string(self.widget_template or ( + 'django_extensions/widgets/%s/%s/foreignkey_searchinput.html' % (app_label, model_name), + 'django_extensions/widgets/%s/foreignkey_searchinput.html' % app_label, + 'django_extensions/widgets/foreignkey_searchinput.html', + ), context)) + output.reverse() + + return mark_safe(''.join(output)) diff --git a/venv/lib/python3.7/site-packages/django_extensions/apps.py b/venv/lib/python3.7/site-packages/django_extensions/apps.py new file mode 100644 index 0000000..4c13d33 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/apps.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +from django.apps import AppConfig + + +class DjangoExtensionsConfig(AppConfig): + name = 'django_extensions' + verbose_name = "Django Extensions" diff --git a/venv/lib/python3.7/site-packages/django_extensions/auth/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/auth/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/auth/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d96e27a9a90f2cc2c6a777a33b2baa5a410213ea GIT binary patch literal 193 zcmZ?b<>g`kf=l~9#)Ig`AOZ#$feZ&AE@lA|DGb33nv8xc8Hzx{2;x_kerR!OQL%n@ zQB`GeRY`tYd{Ta1YI1g_zDsIxc1eDLepzCAX|aA;YF?RsPG*vRL1jrsex9+OxqfkG zNvdu^Vsdt3dTOzLN>*ZCdVYLrMM-L2ab|vAv3_D{NrrxWd}dx|NqoFsLFFwDo80`A O(wtN~kQ+V&F#`az0yhx= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/auth/__pycache__/mixins.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/auth/__pycache__/mixins.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb767420cb841cd7856546cd9db69d3c30b8b806 GIT binary patch literal 909 zcmah`J&)5s5S{f$;tNSd2SQMRQeYPpG=NTkpt|TJpmDQuyqm;{vktrK=o00syB~5X z`4#*JO1Csn(o!+A)C_VrOM;{PBWRPqsw>~$(V#bgIJu!l>AYO%R@>Fqr0I_(n!Ea;7qwh1SNHg@Q1G9vA@Gq!zs zt+iCv8Q=tOH=4CMu?Wm3waV||(YXjLVv)Cfc6|K9z0t7KM4YQ^DLHR?oaC)b%KIGY zWo28@A>zAv^nfxl{?0~ZG)YBmjz+`+FY?{L(a=vHwBE*frK~Q-F&P`T#%eOmHQoVq R_-@4LRm Tuple[str, str] + model_class = import_string(full_model_path) + return model_class._meta.app_config.name, model_class.__name__ + + @abstractmethod + def resolve_collisions(self, namespace): # type: (Dict[str, List[str]]) -> Dict[str, str] + pass + + +class LegacyCR(BaseCR): + """ Default collision resolver. Model from last application in alphabetical order is selected. """ + + def resolve_collisions(self, namespace): + result = {} + for name, models in namespace.items(): + result[name] = models[-1] + return result + + +class AppsOrderCR(LegacyCR, metaclass=ABCMeta): + APP_PRIORITIES = None # type: List[str] + + def resolve_collisions(self, namespace): + assert self.APP_PRIORITIES is not None, "You must define APP_PRIORITIES in your resolver class!" + result = {} + for name, models in namespace.items(): + if len(models) > 0: + sorted_models = self._sort_models_depending_on_priorities(models) + result[name] = sorted_models[0][1] + return result + + def _sort_models_depending_on_priorities(self, models): # type: (List[str]) -> List[Tuple[int, str]] + models_with_priorities = [] + for model in models: + try: + app_name, _ = self.get_app_name_and_model(model) + position = self.APP_PRIORITIES.index(app_name) + except (ImportError, ValueError): + position = sys.maxsize + models_with_priorities.append((position, model)) + return sorted(models_with_priorities) + + +class InstalledAppsOrderCR(AppsOrderCR): + """ + Collision resolver which selects first model from INSTALLED_APPS. + You can set your own app priorities list by subclassing him and overwriting APP_PRIORITIES field. + This collision resolver will select model from first app on this list. + If both app's are absent on this list, resolver will choose model from first app in alphabetical order. + """ + + @property + def APP_PRIORITIES(self): + from django.conf import settings + return getattr(settings, 'INSTALLED_APPS', []) + + +class PathBasedCR(LegacyCR, metaclass=ABCMeta): + """ + Abstract resolver which transforms full model name into alias. + To use him you need to overwrite transform_import function + which should have one parameter. It will be full model name. + It should return valid alias as str instance. + """ + + @abstractmethod + def transform_import(self, module_path): # type: (str) -> str + pass + + def resolve_collisions(self, namespace): + base_imports = super(PathBasedCR, self).resolve_collisions(namespace) + for name, models in namespace.items(): + if len(models) <= 1: + continue + for model in models: + new_name = self.transform_import(model) + assert isinstance(new_name, str), "result of transform_import must be str!" + base_imports[new_name] = model + return base_imports + + +class FullPathCR(PathBasedCR): + """ + Collision resolver which transform full model name to alias by changing dots to underscores. + He also removes 'models' part of alias, because all models are in models.py files. + Model from last application in alphabetical order is selected. + """ + + def transform_import(self, module_path): + module, model = module_path.rsplit('.models', 1) + module_path = module + model + return module_path.replace('.', '_') + + +class AppNameCR(PathBasedCR, metaclass=ABCMeta): + """ + Abstract collision resolver which transform pair (app name, model_name) to alias by changing dots to underscores. + You must define MODIFICATION_STRING which should be string to format with two keyword arguments: + app_name and model_name. For example: "{app_name}_{model_name}". + Model from last application in alphabetical order is selected. + """ + + MODIFICATION_STRING = None # type: Optional[str] + + def transform_import(self, module_path): + assert self.MODIFICATION_STRING is not None, "You must define MODIFICATION_STRING in your resolver class!" + app_name, model_name = self.get_app_name_and_model(module_path) + app_name = app_name.replace('.', '_') + return self.MODIFICATION_STRING.format(app_name=app_name, model_name=model_name) + + +class AppNamePrefixCR(AppNameCR): + """ + Collision resolver which transform pair (app name, model_name) to alias "{app_name}_{model_name}". + Model from last application in alphabetical order is selected. + Result is different than FullPathCR, when model has app_label other than current app. + """ + + MODIFICATION_STRING = "{app_name}_{model_name}" + + +class AppNameSuffixCR(AppNameCR): + """ + Collision resolver which transform pair (app name, model_name) to alias "{model_name}_{app_name}" + Model from last application in alphabetical order is selected. + """ + + MODIFICATION_STRING = "{model_name}_{app_name}" + + +class AppNamePrefixCustomOrderCR(AppNamePrefixCR, InstalledAppsOrderCR): + """ + Collision resolver which is mixin of AppNamePrefixCR and InstalledAppsOrderCR. + In case of collisions he sets aliases like AppNamePrefixCR, but sets default model using InstalledAppsOrderCR. + """ + + pass + + +class AppNameSuffixCustomOrderCR(AppNameSuffixCR, InstalledAppsOrderCR): + """ + Collision resolver which is mixin of AppNameSuffixCR and InstalledAppsOrderCR. + In case of collisions he sets aliases like AppNameSuffixCR, but sets default model using InstalledAppsOrderCR. + """ + + pass + + +class FullPathCustomOrderCR(FullPathCR, InstalledAppsOrderCR): + """ + Collision resolver which is mixin of FullPathCR and InstalledAppsOrderCR. + In case of collisions he sets aliases like FullPathCR, but sets default model using InstalledAppsOrderCR. + """ + + pass + + +class AppLabelCR(PathBasedCR, metaclass=ABCMeta): + """ + Abstract collision resolver which transform pair (app_label, model_name) to alias. + You must define MODIFICATION_STRING which should be string to format with two keyword arguments: + app_label and model_name. For example: "{app_label}_{model_name}". + This is different from AppNameCR when the app is nested with several level of namespace: + Gives sites_Site instead of django_contrib_sites_Site + Model from last application in alphabetical order is selected. + """ + + MODIFICATION_STRING = None # type: Optional[str] + + def transform_import(self, module_path): + assert self.MODIFICATION_STRING is not None, "You must define MODIFICATION_STRING in your resolver class!" + model_class = import_string(module_path) + app_label, model_name = model_class._meta.app_label, model_class.__name__ + return self.MODIFICATION_STRING.format(app_label=app_label, model_name=model_name) + + +class AppLabelPrefixCR(AppLabelCR): + """ + Collision resolver which transform pair (app_label, model_name) to alias "{app_label}_{model_name}". + Model from last application in alphabetical order is selected. + """ + + MODIFICATION_STRING = "{app_label}_{model_name}" + + +class AppLabelSuffixCR(AppLabelCR): + """ + Collision resolver which transform pair (app_label, model_name) to alias "{model_name}_{app_label}". + Model from last application in alphabetical order is selected. + """ + + MODIFICATION_STRING = "{model_name}_{app_label}" + + +class CollisionResolvingRunner: + def __init__(self): + pass + + def run_collision_resolver(self, models_to_import): + # type: (Dict[str, List[str]]) -> Dict[str, List[Tuple[str, str]]] + dictionary_of_names = self._get_dictionary_of_names(models_to_import) # type: Dict[str, str] + return self._get_dictionary_of_modules(dictionary_of_names) + + @classmethod + def _get_dictionary_of_names(cls, models_to_import): # type: (Dict[str, List[str]]) -> (Dict[str, str]) + from django.conf import settings + collision_resolver_class = import_string(getattr( + settings, 'SHELL_PLUS_MODEL_IMPORTS_RESOLVER', + 'django_extensions.collision_resolvers.LegacyCR' + )) + + cls._assert_is_collision_resolver_class_correct(collision_resolver_class) + result = collision_resolver_class().resolve_collisions(models_to_import) + cls._assert_is_collision_resolver_result_correct(result) + + return result + + @classmethod + def _assert_is_collision_resolver_result_correct(cls, result): + assert isinstance(result, dict), "Result of resolve_collisions function must be a dict!" + for key, value in result.items(): + assert isinstance(key, str), "key in collision resolver result should be str not %s" % key + assert isinstance(value, str), "value in collision resolver result should be str not %s" % value + + @classmethod + def _assert_is_collision_resolver_class_correct(cls, collision_resolver_class): + assert inspect.isclass(collision_resolver_class) and issubclass( + collision_resolver_class, BaseCR), "SHELL_PLUS_MODEL_IMPORTS_RESOLVER " \ + "must be subclass of BaseCR!" + assert len(inspect.getfullargspec(collision_resolver_class.resolve_collisions).args) == 2, \ + "resolve_collisions function must take one argument!" + + @classmethod + def _get_dictionary_of_modules(cls, dictionary_of_names): + # type: (Dict[str, str]) -> Dict[str, List[Tuple[str, str]]] + dictionary_of_modules = {} # type: Dict[str, List[Tuple[str, str]]] + for alias, model in dictionary_of_names.items(): + module_path, model_name = model.rsplit('.', 1) + dictionary_of_modules.setdefault(module_path, []) + dictionary_of_modules[module_path].append((model_name, alias)) + return dictionary_of_modules diff --git a/venv/lib/python3.7/site-packages/django_extensions/compat.py b/venv/lib/python3.7/site-packages/django_extensions/compat.py new file mode 100644 index 0000000..bb8ca1c --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/compat.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +from io import BytesIO + +import csv +import codecs +import importlib + +from django.conf import settings + + +# +# Django compatibility +# +def load_tag_library(libname): + """ + Load a templatetag library on multiple Django versions. + + Returns None if the library isn't loaded. + """ + from django.template.backends.django import get_installed_libraries + from django.template.library import InvalidTemplateLibrary + try: + lib = get_installed_libraries()[libname] + lib = importlib.import_module(lib).register + return lib + except (InvalidTemplateLibrary, KeyError): + return None + + +def get_template_setting(template_key, default=None): + """ Read template settings """ + templates_var = getattr(settings, 'TEMPLATES', None) + if templates_var: + for tdict in templates_var: + if template_key in tdict: + return tdict[template_key] + return default + + +class UnicodeWriter: + """ + CSV writer which will write rows to CSV file "f", + which is encoded in the given encoding. + We are using this custom UnicodeWriter for python versions 2.x + """ + + def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds): + self.queue = BytesIO() + self.writer = csv.writer(self.queue, dialect=dialect, **kwds) + self.stream = f + self.encoder = codecs.getincrementalencoder(encoding)() + + def writerow(self, row): + self.writer.writerow([s.encode("utf-8") for s in row]) + # Fetch UTF-8 output from the queue ... + data = self.queue.getvalue() + data = data.decode("utf-8") + # ... and reencode it into the target encoding + data = self.encoder.encode(data) + # write to the target stream + self.stream.write(data) + # empty queue + self.queue.truncate(0) + + def writerows(self, rows): + for row in rows: + self.writerow(row) diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/__init__.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/__init__.py.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/forms.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/forms.py.tmpl new file mode 100644 index 0000000..c3927a7 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/forms.py.tmpl @@ -0,0 +1,3 @@ +from django import forms + +# place form definition here diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/migrations/__init__.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/migrations/__init__.py.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/models.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/models.py.tmpl new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/models.py.tmpl @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/urls.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/urls.py.tmpl new file mode 100644 index 0000000..f9407a3 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/urls.py.tmpl @@ -0,0 +1,3 @@ +from django.urls import include, path + +# place app url patterns here diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/views.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/views.py.tmpl new file mode 100644 index 0000000..60f00ef --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/conf/app_template/views.py.tmpl @@ -0,0 +1 @@ +# Create your views here. diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/command_template/management/__init__.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/command_template/management/__init__.py.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/command_template/management/commands/__init__.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/command_template/management/commands/__init__.py.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/command_template/management/commands/sample.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/command_template/management/commands/sample.py.tmpl new file mode 100644 index 0000000..b82b95d --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/conf/command_template/management/commands/sample.py.tmpl @@ -0,0 +1,11 @@ +from django.core.management.base import {{ base_command }} + + +class Command({{ base_command }}): + help = "My shiny new management command." + + def add_arguments(self, parser): + parser.add_argument('sample', nargs='+') + + def handle(self, *args, **options): + raise NotImplementedError() diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/__init__.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/__init__.py.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/daily/__init__.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/daily/__init__.py.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/hourly/__init__.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/hourly/__init__.py.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/monthly/__init__.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/monthly/__init__.py.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/sample.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/sample.py.tmpl new file mode 100644 index 0000000..b1ae62c --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/sample.py.tmpl @@ -0,0 +1,9 @@ +from django_extensions.management.jobs import BaseJob + + +class Job(BaseJob): + help = "My sample job." + + def execute(self): + # executing empty sample job + pass diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/weekly/__init__.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/weekly/__init__.py.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/yearly/__init__.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/jobs_template/jobs/yearly/__init__.py.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/template_tags_template/templatetags/__init__.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/template_tags_template/templatetags/__init__.py.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/conf/template_tags_template/templatetags/sample.py.tmpl b/venv/lib/python3.7/site-packages/django_extensions/conf/template_tags_template/templatetags/sample.py.tmpl new file mode 100644 index 0000000..4bd3b15 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/conf/template_tags_template/templatetags/sample.py.tmpl @@ -0,0 +1,3 @@ +from django import template + +register = template.Library() diff --git a/venv/lib/python3.7/site-packages/django_extensions/db/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/db/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/db/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e397a7b131d01b835bc4cdf6471642feb247bc10 GIT binary patch literal 191 zcmZ?b<>g`kf=l~9#)Ig`AOZ#$feZ&AE@lA|DGb33nv8xc8Hzx{2;x_UerR!OQL%n@ zQB`GeRY`tYd{Ta1YI1g_zDsIxc1eDLepzCAX|aA;YF?RsPG*vRL1jrsex9+OxqfkG zNvdu^Vsdt3dTOzLN>*ZCdVYLrMM-L2ab|uVP$Wq|K0Y%qvm`!Vub}c4hfQvNN@-52 L9moZrftUdRI!87m literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/db/__pycache__/models.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/db/__pycache__/models.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3d7aa612bbb32383afd7c532333927514c0764b GIT binary patch literal 5378 zcmb_gOK;oQ73ND6B}?)n_B5{stUH~F+C)N8paqOUk<^)oQN(@N(*o>*rgX1t+7zj| zq?|}F(1imGx=7KVknGxDQS>i#$?dGN?6#ZsJC~#^+OpdemBDNB+}Anhe&=<6)@;@l z{Qmyef4JYY6y+QGD1HWBp5Tf9jD{&p4V0nks4Bf{fi~0~UB2sqF|0VId^dvX&~mI{ z&8ZFRPF+<#S6GFauM}o-^?2!AcN(BnnFWfKQ<|XESRIr)Z(>9X-%G54?*>LJAFqJ6 z3R;u3Kx=`v2Ffi^me~p@EBQL>Y;{j*ue}4eN?T3MVZ?Y4<4q5v7x>pW2~UNAoV%;y11H?{@$5?f{lJT3Tk641j=aPkiRjd4Jho#V z3?2`?&^zSJ-t3d)oNd}($mB|!m;<4Sgf?JtN0QTOJ~Fk60ev+WT*Ln=o+Ui-Lo{dV z8(=0;&(J~v`djTxakWH0SB{MVdjBYq1Tpp9ba^~t;J__b-EUV?eH4w-D$dMH5+P{W zv=Wa;T%<91-{fqL?LHEm;i@19trjvM@L<6@Mg}i^_ zcc1b2B#B1dQ}1vbcTahE+70|(cQi?kqVPwZpLAnC;g3gN{{-5JyX@Et4 zulu{ukL9|dH{`CH)?HHEIH322>wY!%f~?1BLVbXH!sEp4O;W3Xhq#4R<{DxnHE8|Y zc$1=7s-cQI_-Z%A295rJns1>=tFFtUzUvB;zEoG#sEZC?awk
4#PMEX1kFn+dc zTNP_Goc0wK8d@PH(Ja%@8frsp7?NJnS_S=2Xy7w6^IGG^afO>?WlU$rYt5;GVu4Zt z#U$H$txGGjSPfQIBP(NdXn85cVI=_vB>KW1k@Y{9W;V>tY(d|9+gd_9kZIYlykeWO zT~*|mcmIN1z;S)(y>tT}9wtZW(%hVVV7}4|yznG7!f_Cklrw|W$|dD6jcjasccGvi zI&;9uxOB#XaBy*6*_%8qg2cyoVlsFugUD`s>GJ%$G@phzwe2HMNM9=M5%GZ}?!%rk z;&+Hht1jH`+vuPtCX`qeLt9hVH9?e;^s`viK~EVPnfuLwVZzns@dzNOvMO|ArFW!m zC=^@9y2IH_#R`5s;?MLGv3kWoy@qr(5 z``{oS?G}R%4(u04e*cJ=2<;bs5ZFCV>tD?ELwjp9*^=&g>!1{P4~Ut3Nh}VpFXeJc zEUYZ!Pc9U3vBx3QwMz{mfp{l4m`yxCDB_ku>r3RdRi|0nq6DM=WJC|H1(#IwrGlsI_!s#;rW1=Q1M|d6v7dFT+?qkX%QG zFWV0Rfv}I6hm=}4m2vEchd6IiqUfSYb(i(7K_nF|$mjrd z7}ReuxH#v{vW&SxI`hLz2qid6K^k~DQ{E_Vl{e~J1wyFP^I422o7hb{&CWr3M38c(7On#nQX&>Oza3Y5IDzr$p+Pv{R9I zS%zf^qLvJwA`|`MKcOibK21Av37D_@0fC9p1FAqHS|&B!%wAEBvc+E;r{fa z6V69AAC8hq<~Tyz9}YS5QMqN|PToGiXKZ3=@m(}&?T7~>m+mvBA6}a7hcZ<|6+1V% zbZWCahoauqQ-kJ=>8-N9WP$^PQm~q~9v9-fRJT(-dI@Ka6$!=#Jl)Nu#P6|Ox!#<4 zEgfC-P=zgX6-o)>R-&H6f4NGc;U+;pQ_r;7O@fL-CT*5j6SRV$ghH03P$4<;)SxQ^ zv5Hq1nk+?S=#v!=?RSnx20TSIRZG3140!`_>ypeu7CnzJReYZsDtDY#mTnpyBJM3T}_LJ{DJ zseY#d%1{lxuC}ywmHtevWk@60ZErZW?5?B3dKsG=`S&=XR64<3)D(9pQl-xAa-Zqc<{~KYFC;R{a literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/db/fields/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/db/fields/__init__.py new file mode 100644 index 0000000..e320dfd --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/db/fields/__init__.py @@ -0,0 +1,593 @@ +# -*- coding: utf-8 -*- +""" +Django Extensions additional model fields + +Some fields might require additional dependencies to be installed. +""" + +import re +import string + +try: + import uuid + HAS_UUID = True +except ImportError: + HAS_UUID = False + +try: + import shortuuid + HAS_SHORT_UUID = True +except ImportError: + HAS_SHORT_UUID = False + +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured +from django.db.models import DateTimeField, CharField, SlugField, Q, UniqueConstraint +from django.db.models.constants import LOOKUP_SEP +from django.template.defaultfilters import slugify +from django.utils.crypto import get_random_string +from django.utils.encoding import force_str + + +MAX_UNIQUE_QUERY_ATTEMPTS = getattr(settings, 'EXTENSIONS_MAX_UNIQUE_QUERY_ATTEMPTS', 100) + + +class UniqueFieldMixin: + + def check_is_bool(self, attrname): + if not isinstance(getattr(self, attrname), bool): + raise ValueError("'{}' argument must be True or False".format(attrname)) + + @staticmethod + def _get_fields(model_cls): + return [ + (f, f.model if f.model != model_cls else None) for f in model_cls._meta.get_fields() + if not f.is_relation or f.one_to_one or (f.many_to_one and f.related_model) + ] + + def get_queryset(self, model_cls, slug_field): + for field, model in self._get_fields(model_cls): + if model and field == slug_field: + return model._default_manager.all() + return model_cls._default_manager.all() + + def find_unique(self, model_instance, field, iterator, *args): + # exclude the current model instance from the queryset used in finding + # next valid hash + queryset = self.get_queryset(model_instance.__class__, field) + if model_instance.pk: + queryset = queryset.exclude(pk=model_instance.pk) + + # form a kwarg dict used to implement any unique_together constraints + kwargs = {} + for params in model_instance._meta.unique_together: + if self.attname in params: + for param in params: + kwargs[param] = getattr(model_instance, param, None) + + # for support django 2.2+ + query = Q() + constraints = getattr(model_instance._meta, 'constraints', None) + if constraints: + unique_constraints = filter( + lambda c: isinstance(c, UniqueConstraint), constraints + ) + for unique_constraint in unique_constraints: + if self.attname in unique_constraint.fields: + condition = { + field: getattr(model_instance, field, None) + for field in unique_constraint.fields + if field != self.attname + } + query &= Q(**condition) + + new = next(iterator) + kwargs[self.attname] = new + while not new or queryset.filter(query, **kwargs): + new = next(iterator) + kwargs[self.attname] = new + setattr(model_instance, self.attname, new) + return new + + +class AutoSlugField(UniqueFieldMixin, SlugField): + """ + AutoSlugField + + By default, sets editable=False, blank=True. + + Required arguments: + + populate_from + Specifies which field, list of fields, or model method + the slug will be populated from. + + populate_from can traverse a ForeignKey relationship + by using Django ORM syntax: + populate_from = 'related_model__field' + + Optional arguments: + + separator + Defines the used separator (default: '-') + + overwrite + If set to True, overwrites the slug on every save (default: False) + + slugify_function + Defines the function which will be used to "slugify" a content + (default: :py:func:`~django.template.defaultfilters.slugify` ) + + It is possible to provide custom "slugify" function with + the ``slugify_function`` function in a model class. + + ``slugify_function`` function in a model class takes priority over + ``slugify_function`` given as an argument to :py:class:`~AutoSlugField`. + + Example + + .. code-block:: python + + # models.py + + from django.db import models + + from django_extensions.db.fields import AutoSlugField + + + class MyModel(models.Model): + def slugify_function(self, content): + return content.replace('_', '-').lower() + + title = models.CharField(max_length=42) + slug = AutoSlugField(populate_from='title') + + Inspired by SmileyChris' Unique Slugify snippet: + http://www.djangosnippets.org/snippets/690/ + """ + + def __init__(self, *args, **kwargs): + kwargs.setdefault('blank', True) + kwargs.setdefault('editable', False) + + populate_from = kwargs.pop('populate_from', None) + if populate_from is None: + raise ValueError("missing 'populate_from' argument") + else: + self._populate_from = populate_from + + if not callable(populate_from): + if not isinstance(populate_from, (list, tuple)): + populate_from = (populate_from, ) + + if not all(isinstance(e, str) for e in populate_from): + raise TypeError("'populate_from' must be str or list[str] or tuple[str], found `%s`" % populate_from) + + self.slugify_function = kwargs.pop('slugify_function', slugify) + self.separator = kwargs.pop('separator', '-') + self.overwrite = kwargs.pop('overwrite', False) + self.check_is_bool('overwrite') + self.overwrite_on_add = kwargs.pop('overwrite_on_add', True) + self.check_is_bool('overwrite_on_add') + self.allow_duplicates = kwargs.pop('allow_duplicates', False) + self.check_is_bool('allow_duplicates') + self.max_unique_query_attempts = kwargs.pop('max_unique_query_attempts', MAX_UNIQUE_QUERY_ATTEMPTS) + super().__init__(*args, **kwargs) + + def _slug_strip(self, value): + """ + Clean up a slug by removing slug separator characters that occur at + the beginning or end of a slug. + + If an alternate separator is used, it will also replace any instances + of the default '-' separator with the new separator. + """ + re_sep = '(?:-|%s)' % re.escape(self.separator) + value = re.sub('%s+' % re_sep, self.separator, value) + return re.sub(r'^%s+|%s+$' % (re_sep, re_sep), '', value) + + @staticmethod + def slugify_func(content, slugify_function): + if content: + return slugify_function(content) + return '' + + def slug_generator(self, original_slug, start): + yield original_slug + for i in range(start, self.max_unique_query_attempts): + slug = original_slug + end = '%s%s' % (self.separator, i) + end_len = len(end) + if self.slug_len and len(slug) + end_len > self.slug_len: + slug = slug[:self.slug_len - end_len] + slug = self._slug_strip(slug) + slug = '%s%s' % (slug, end) + yield slug + raise RuntimeError('max slug attempts for %s exceeded (%s)' % (original_slug, self.max_unique_query_attempts)) + + def create_slug(self, model_instance, add): + slug = getattr(model_instance, self.attname) + use_existing_slug = False + if slug and not self.overwrite: + # Existing slug and not configured to overwrite - Short-circuit + # here to prevent slug generation when not required. + use_existing_slug = True + + if self.overwrite_on_add and add: + use_existing_slug = False + + if use_existing_slug: + return slug + + # get fields to populate from and slug field to set + populate_from = self._populate_from + if not isinstance(populate_from, (list, tuple)): + populate_from = (populate_from, ) + + slug_field = model_instance._meta.get_field(self.attname) + slugify_function = getattr(model_instance, 'slugify_function', self.slugify_function) + + # slugify the original field content and set next step to 2 + slug_for_field = lambda lookup_value: self.slugify_func( + self.get_slug_fields(model_instance, lookup_value), + slugify_function=slugify_function + ) + slug = self.separator.join(map(slug_for_field, populate_from)) + start = 2 + + # strip slug depending on max_length attribute of the slug field + # and clean-up + self.slug_len = slug_field.max_length + if self.slug_len: + slug = slug[:self.slug_len] + slug = self._slug_strip(slug) + original_slug = slug + + if self.allow_duplicates: + setattr(model_instance, self.attname, slug) + return slug + + return self.find_unique( + model_instance, slug_field, self.slug_generator(original_slug, start)) + + def get_slug_fields(self, model_instance, lookup_value): + if callable(lookup_value): + # A function has been provided + return "%s" % lookup_value(model_instance) + + lookup_value_path = lookup_value.split(LOOKUP_SEP) + attr = model_instance + for elem in lookup_value_path: + try: + attr = getattr(attr, elem) + except AttributeError: + raise AttributeError( + "value {} in AutoSlugField's 'populate_from' argument {} returned an error - {} has no attribute {}".format( + elem, lookup_value, attr, elem)) + + if callable(attr): + return "%s" % attr() + + return attr + + def pre_save(self, model_instance, add): + value = force_str(self.create_slug(model_instance, add)) + return value + + def get_internal_type(self): + return "SlugField" + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + kwargs['populate_from'] = self._populate_from + if not self.separator == '-': + kwargs['separator'] = self.separator + if self.overwrite is not False: + kwargs['overwrite'] = True + if self.allow_duplicates is not False: + kwargs['allow_duplicates'] = True + return name, path, args, kwargs + + +class RandomCharField(UniqueFieldMixin, CharField): + """ + RandomCharField + + By default, sets editable=False, blank=True, unique=False. + + Required arguments: + + length + Specifies the length of the field + + Optional arguments: + + unique + If set to True, duplicate entries are not allowed (default: False) + + lowercase + If set to True, lowercase the alpha characters (default: False) + + uppercase + If set to True, uppercase the alpha characters (default: False) + + include_alpha + If set to True, include alpha characters (default: True) + + include_digits + If set to True, include digit characters (default: True) + + include_punctuation + If set to True, include punctuation characters (default: False) + """ + + def __init__(self, *args, **kwargs): + kwargs.setdefault('blank', True) + kwargs.setdefault('editable', False) + + self.length = kwargs.pop('length', None) + if self.length is None: + raise ValueError("missing 'length' argument") + kwargs['max_length'] = self.length + + self.lowercase = kwargs.pop('lowercase', False) + self.check_is_bool('lowercase') + self.uppercase = kwargs.pop('uppercase', False) + self.check_is_bool('uppercase') + if self.uppercase and self.lowercase: + raise ValueError("the 'lowercase' and 'uppercase' arguments are mutually exclusive") + self.include_digits = kwargs.pop('include_digits', True) + self.check_is_bool('include_digits') + self.include_alpha = kwargs.pop('include_alpha', True) + self.check_is_bool('include_alpha') + self.include_punctuation = kwargs.pop('include_punctuation', False) + self.check_is_bool('include_punctuation') + self.max_unique_query_attempts = kwargs.pop('max_unique_query_attempts', MAX_UNIQUE_QUERY_ATTEMPTS) + + # Set unique=False unless it's been set manually. + if 'unique' not in kwargs: + kwargs['unique'] = False + + super().__init__(*args, **kwargs) + + def random_char_generator(self, chars): + for i in range(self.max_unique_query_attempts): + yield ''.join(get_random_string(self.length, chars)) + raise RuntimeError('max random character attempts exceeded (%s)' % self.max_unique_query_attempts) + + def in_unique_together(self, model_instance): + for params in model_instance._meta.unique_together: + if self.attname in params: + return True + return False + + def pre_save(self, model_instance, add): + if not add and getattr(model_instance, self.attname) != '': + return getattr(model_instance, self.attname) + + population = '' + if self.include_alpha: + if self.lowercase: + population += string.ascii_lowercase + elif self.uppercase: + population += string.ascii_uppercase + else: + population += string.ascii_letters + + if self.include_digits: + population += string.digits + + if self.include_punctuation: + population += string.punctuation + + random_chars = self.random_char_generator(population) + if not self.unique and not self.in_unique_together(model_instance): + new = next(random_chars) + setattr(model_instance, self.attname, new) + return new + + return self.find_unique( + model_instance, + model_instance._meta.get_field(self.attname), + random_chars, + ) + + def internal_type(self): + return "CharField" + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + kwargs['length'] = self.length + del kwargs['max_length'] + if self.lowercase is True: + kwargs['lowercase'] = self.lowercase + if self.uppercase is True: + kwargs['uppercase'] = self.uppercase + if self.include_alpha is False: + kwargs['include_alpha'] = self.include_alpha + if self.include_digits is False: + kwargs['include_digits'] = self.include_digits + if self.include_punctuation is True: + kwargs['include_punctuation'] = self.include_punctuation + if self.unique is True: + kwargs['unique'] = self.unique + return name, path, args, kwargs + + +class CreationDateTimeField(DateTimeField): + """ + CreationDateTimeField + + By default, sets editable=False, blank=True, auto_now_add=True + """ + + def __init__(self, *args, **kwargs): + kwargs.setdefault('editable', False) + kwargs.setdefault('blank', True) + kwargs.setdefault('auto_now_add', True) + DateTimeField.__init__(self, *args, **kwargs) + + def get_internal_type(self): + return "DateTimeField" + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + if self.editable is not False: + kwargs['editable'] = True + if self.blank is not True: + kwargs['blank'] = False + if self.auto_now_add is not False: + kwargs['auto_now_add'] = True + return name, path, args, kwargs + + +class ModificationDateTimeField(CreationDateTimeField): + """ + ModificationDateTimeField + + By default, sets editable=False, blank=True, auto_now=True + + Sets value to now every time the object is saved. + """ + + def __init__(self, *args, **kwargs): + kwargs.setdefault('auto_now', True) + DateTimeField.__init__(self, *args, **kwargs) + + def get_internal_type(self): + return "DateTimeField" + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + if self.auto_now is not False: + kwargs['auto_now'] = True + return name, path, args, kwargs + + def pre_save(self, model_instance, add): + if not getattr(model_instance, 'update_modified', True): + return getattr(model_instance, self.attname) + return super().pre_save(model_instance, add) + + +class UUIDVersionError(Exception): + pass + + +class UUIDFieldMixin: + """ + UUIDFieldMixin + + By default uses UUID version 4 (randomly generated UUID). + + The field support all uuid versions which are natively supported by the uuid python module, except version 2. + For more information see: http://docs.python.org/lib/module-uuid.html + """ + + DEFAULT_MAX_LENGTH = 36 + + def __init__(self, verbose_name=None, name=None, auto=True, version=4, + node=None, clock_seq=None, namespace=None, uuid_name=None, *args, + **kwargs): + if not HAS_UUID: + raise ImproperlyConfigured("'uuid' module is required for UUIDField. (Do you have Python 2.5 or higher installed ?)") + + kwargs.setdefault('max_length', self.DEFAULT_MAX_LENGTH) + + if auto: + self.empty_strings_allowed = False + kwargs['blank'] = True + kwargs.setdefault('editable', False) + + self.auto = auto + self.version = version + self.node = node + self.clock_seq = clock_seq + self.namespace = namespace + self.uuid_name = uuid_name or name + + super().__init__(verbose_name=verbose_name, *args, **kwargs) + + def create_uuid(self): + if not self.version or self.version == 4: + return uuid.uuid4() + elif self.version == 1: + return uuid.uuid1(self.node, self.clock_seq) + elif self.version == 2: + raise UUIDVersionError("UUID version 2 is not supported.") + elif self.version == 3: + return uuid.uuid3(self.namespace, self.uuid_name) + elif self.version == 5: + return uuid.uuid5(self.namespace, self.uuid_name) + else: + raise UUIDVersionError("UUID version %s is not valid." % self.version) + + def pre_save(self, model_instance, add): + value = super().pre_save(model_instance, add) + + if self.auto and add and value is None: + value = force_str(self.create_uuid()) + setattr(model_instance, self.attname, value) + return value + else: + if self.auto and not value: + value = force_str(self.create_uuid()) + setattr(model_instance, self.attname, value) + + return value + + def formfield(self, **kwargs): + if self.auto: + return None + return super().formfield(**kwargs) + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + + if kwargs.get('max_length', None) == self.DEFAULT_MAX_LENGTH: + del kwargs['max_length'] + if self.auto is not True: + kwargs['auto'] = self.auto + if self.version != 4: + kwargs['version'] = self.version + if self.node is not None: + kwargs['node'] = self.node + if self.clock_seq is not None: + kwargs['clock_seq'] = self.clock_seq + if self.namespace is not None: + kwargs['namespace'] = self.namespace + if self.uuid_name is not None: + kwargs['uuid_name'] = self.name + + return name, path, args, kwargs + + +class ShortUUIDField(UUIDFieldMixin, CharField): + """ + ShortUUIDFied + + Generates concise (22 characters instead of 36), unambiguous, URL-safe UUIDs. + + Based on `shortuuid`: https://github.com/stochastic-technologies/shortuuid + """ + + DEFAULT_MAX_LENGTH = 22 + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if not HAS_SHORT_UUID: + raise ImproperlyConfigured("'shortuuid' module is required for ShortUUIDField. (Do you have Python 2.5 or higher installed ?)") + kwargs.setdefault('max_length', self.DEFAULT_MAX_LENGTH) + + def create_uuid(self): + if not self.version or self.version == 4: + return shortuuid.uuid() + elif self.version == 1: + return shortuuid.uuid() + elif self.version == 2: + raise UUIDVersionError("UUID version 2 is not supported.") + elif self.version == 3: + raise UUIDVersionError("UUID version 3 is not supported.") + elif self.version == 5: + return shortuuid.uuid(name=self.namespace) + else: + raise UUIDVersionError("UUID version %s is not valid." % self.version) diff --git a/venv/lib/python3.7/site-packages/django_extensions/db/fields/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/db/fields/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1bbf2d0b6fe263cf27c355947bdfa34eb48c8f3c GIT binary patch literal 17643 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/db/fields/__pycache__/json.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/db/fields/__pycache__/json.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e840fb7dd423ebe08109628f77f11e843f1771ee GIT binary patch literal 3611 zcmdT{O^+i-8Ls}Yr``6<&Q1~~gaDOg6UK?K5eOkr7Ok?I5W!{^u>%TLq*mKio@u+? zZK}#MJ5F0dnw4@3{{YP#`4#*Jj(z3Ckt-*jx7r`$$>zchOI6)fUG>)c@x0Gl{&06U zWcdB#@BfZEO~(F7gVoQ+%R@9hLMK>{2}ii8({u3jQg`C@Jcs7|)SuLPHN4kE{RQjQ z#f}K@-1!v~4H3RzB9y_U*K1(h6fKNfGQ_xv@vhjzcu&?wEzIl+_Ze&7iQjP;3xECW z>CwlDOa+f;CZEJ68N_LN!L?LLoF;Rr`6Snd|MtS1<{39qO*A(-r+r++Chmlfl#C75 z#r*iA&yM-fN;^-?DQ1Km#+V?1FZA5x z!>FHUaxhN1kEI@)eA+#WPiDG%CbP3{n)JI<8=9YVe%95Akw2WqgK>N!b+_``4Zn0n zzgzjGyL5Y56SK)wze1{#Qp`~S`j^{67&hCMls*Y6YiS+}4NE)&ACeVSw?l8V?RB)( z0W=<~^1)^ml^^MorrAlw%|99Js?^84dtVCH|e0s91oa-DM}r|PiH z3Aa-4{skwS2%7vnNmHKB%yecdz$TeCG8O=$m9PYL1vrDv7SNm@pC+20$3SKB+{_fP zZ6%%OYW%j{xaA z9*QT4{=W-_+J(tCyki|h9(x~cD+pxW%^;{dv~!=jyVM;}_l>@$jCu!c<7=AP^0kKv z`svTmy$tqWvLR?+)LsNVP`=n9(zkPgXkczfgrbSLK(xdzo(=nLPu#(`@Jr^iUK44v zUpCfMHvfwS?|RIE@|d5<3|v0|9X~e}cbn7L@C>BBRR_AWY*Q50f_UB^$$`-*81W>P zTBjGF_fO*lwc<3%PA>RlhVs#uI7uLPm+L#*X+*vtR6Zqt9HJ}SD-=EBT)PFR-~(pd zkvH-Sc%*Rtin*^G6ha33+@o@5S!9qX-ib7&PvR^xSNavy^p6mcGas1ECBBzT$ipotgKzQnO`^y7xS+1F#pi_L%e@QcGFx9bH6k7 z!X>sW=tknrA3VylGl}}1&lJ~20YA%|!|KKn4{-zG=aN&!;fbm42j*1r#~&V*ti4l) zi6)khvw*?pQ}pI?$R=6`K&f z(a=%ko3>w}jt=gH@;Ow}bO9^FL7w5tLU*`ZJ}r0YLKlgCrTQPSbH%!^Z27Yj=#06Zb7 zYzm10Aq!^UNlO{EB_+~bqV%V+IaP0BrM2wqkfK_7f~ERT*wLw>vU(!xpn zs)&&+kQ9Mb5$~(_sG|eQ-6e?)WSXvsj4-^?$Chr&%r2Uy!c2FXz;A`Y-BvB|f~KOc z?Y*j0H}KwjYxz%NfH-&7)lBIQU1ROFyw_O&*{CwkCLqOa!y)QE4T(Z*KH6h$#GjN@ eq+J<&P+iu3Nf#}vq7T++IV~^n1Ajl<5C02-*hGW? literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/db/fields/json.py b/venv/lib/python3.7/site-packages/django_extensions/db/fields/json.py new file mode 100644 index 0000000..15dc74c --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/db/fields/json.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +""" +JSONField automatically serializes most Python terms to JSON data. +Creates a TEXT field with a default value of "{}". See test_json.py for +more information. + + from django.db import models + from django_extensions.db.fields import json + + class LOL(models.Model): + extra = json.JSONField() +""" +import json + +from django.core.serializers.json import DjangoJSONEncoder +from django.db import models + + +def dumps(value): + return DjangoJSONEncoder().encode(value) + + +def loads(txt): + return json.loads(txt) + + +class JSONDict(dict): + """ + Hack so repr() called by dumpdata will output JSON instead of + Python formatted data. This way fixtures will work! + """ + + def __repr__(self): + return dumps(self) + + +class JSONList(list): + """ + Hack so repr() called by dumpdata will output JSON instead of + Python formatted data. This way fixtures will work! + """ + + def __repr__(self): + return dumps(self) + + +class JSONField(models.TextField): + """ + JSONField is a generic textfield that neatly serializes/unserializes + JSON objects seamlessly. Main thingy must be a dict object. + """ + + def __init__(self, *args, **kwargs): + kwargs['default'] = kwargs.get('default', dict) + models.TextField.__init__(self, *args, **kwargs) + + def get_default(self): + if self.has_default(): + default = self.default + + if callable(default): + default = default() + + return self.to_python(default) + return super().get_default() + + def to_python(self, value): + """Convert our string value to JSON after we load it from the DB""" + if value is None or value == '': + return {} + + if isinstance(value, str): + res = loads(value) + else: + res = value + + if isinstance(res, dict): + return JSONDict(**res) + elif isinstance(res, list): + return JSONList(res) + + return res + + def get_prep_value(self, value): + if not isinstance(value, str): + return dumps(value) + return super(models.TextField, self).get_prep_value(value) + + def from_db_value(self, value, expression, connection): # type: ignore + return self.to_python(value) + + def get_db_prep_save(self, value, connection, **kwargs): + """Convert our JSON object to a string before we save""" + if value is None and self.null: + return None + # default values come in as strings; only non-strings should be + # run through `dumps` + if not isinstance(value, str): + value = dumps(value) + + return value + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + if self.default == '{}': + del kwargs['default'] + return name, path, args, kwargs diff --git a/venv/lib/python3.7/site-packages/django_extensions/db/models.py b/venv/lib/python3.7/site-packages/django_extensions/db/models.py new file mode 100644 index 0000000..d4c7d9b --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/db/models.py @@ -0,0 +1,134 @@ +# -*- coding: utf-8 -*- +from django.db import models +from django.utils.timezone import now +from django.utils.translation import gettext_lazy as _ + +from django_extensions.db.fields import AutoSlugField, CreationDateTimeField, ModificationDateTimeField + + +class TimeStampedModel(models.Model): + """ + TimeStampedModel + + An abstract base class model that provides self-managed "created" and + "modified" fields. + """ + + created = CreationDateTimeField(_('created')) + modified = ModificationDateTimeField(_('modified')) + + def save(self, **kwargs): + self.update_modified = kwargs.pop('update_modified', getattr(self, 'update_modified', True)) + super().save(**kwargs) + + class Meta: + get_latest_by = 'modified' + abstract = True + + +class TitleDescriptionModel(models.Model): + """ + TitleDescriptionModel + + An abstract base class model that provides title and description fields. + """ + + title = models.CharField(_('title'), max_length=255) + description = models.TextField(_('description'), blank=True, null=True) + + class Meta: + abstract = True + + +class TitleSlugDescriptionModel(TitleDescriptionModel): + """ + TitleSlugDescriptionModel + + An abstract base class model that provides title and description fields + and a self-managed "slug" field that populates from the title. + + .. note :: + If you want to use custom "slugify" function, you could + define ``slugify_function`` which then will be used + in :py:class:`AutoSlugField` to slugify ``populate_from`` field. + + See :py:class:`AutoSlugField` for more details. + """ + + slug = AutoSlugField(_('slug'), populate_from='title') + + class Meta: + abstract = True + + +class ActivatorQuerySet(models.query.QuerySet): + """ + ActivatorQuerySet + + Query set that returns statused results + """ + + def active(self): + """ Return active query set """ + return self.filter(status=ActivatorModel.ACTIVE_STATUS) + + def inactive(self): + """ Return inactive query set """ + return self.filter(status=ActivatorModel.INACTIVE_STATUS) + + +class ActivatorModelManager(models.Manager): + """ + ActivatorModelManager + + Manager to return instances of ActivatorModel: SomeModel.objects.active() / .inactive() + """ + + def get_queryset(self): + """ Use ActivatorQuerySet for all results """ + return ActivatorQuerySet(model=self.model, using=self._db) + + def active(self): + """ + Return active instances of ActivatorModel: + + SomeModel.objects.active(), proxy to ActivatorQuerySet.active + """ + return self.get_queryset().active() + + def inactive(self): + """ + Return inactive instances of ActivatorModel: + + SomeModel.objects.inactive(), proxy to ActivatorQuerySet.inactive + """ + return self.get_queryset().inactive() + + +class ActivatorModel(models.Model): + """ + ActivatorModel + + An abstract base class model that provides activate and deactivate fields. + """ + + INACTIVE_STATUS = 0 + ACTIVE_STATUS = 1 + + STATUS_CHOICES = ( + (INACTIVE_STATUS, _('Inactive')), + (ACTIVE_STATUS, _('Active')), + ) + status = models.IntegerField(_('status'), choices=STATUS_CHOICES, default=ACTIVE_STATUS) + activate_date = models.DateTimeField(blank=True, null=True, help_text=_('keep empty for an immediate activation')) + deactivate_date = models.DateTimeField(blank=True, null=True, help_text=_('keep empty for indefinite activation')) + objects = ActivatorModelManager() + + class Meta: + ordering = ('status', '-activate_date',) + abstract = True + + def save(self, *args, **kwargs): + if not self.activate_date: + self.activate_date = now() + super().save(*args, **kwargs) diff --git a/venv/lib/python3.7/site-packages/django_extensions/import_subclasses.py b/venv/lib/python3.7/site-packages/django_extensions/import_subclasses.py new file mode 100644 index 0000000..4e6140c --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/import_subclasses.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +from importlib import import_module +from inspect import ( + getmembers, + isclass, +) +from pkgutil import walk_packages +from typing import ( # NOQA + Dict, + List, + Tuple, + Union, +) + +from django.conf import settings +from django.utils.module_loading import import_string + + +class SubclassesFinder: + def __init__(self, base_classes_from_settings): + self.base_classes = [] + for element in base_classes_from_settings: + if isinstance(element, str): + element = import_string(element) + self.base_classes.append(element) + + def _should_be_imported(self, candidate_to_import): # type: (Tuple[str, type]) -> bool + for base_class in self.base_classes: + if issubclass(candidate_to_import[1], base_class): + return True + return False + + def collect_subclasses(self): # type: () -> Dict[str, List[Tuple[str, str]]] + """ + Collect all subclasses of user-defined base classes from project. + :return: Dictionary from module name to list of tuples. + First element of tuple is model name and second is alias. + Currently we set alias equal to model name, + but in future functionality of aliasing subclasses can be added. + """ + result = {} # type: Dict[str, List[Tuple[str, str]]] + for loader, module_name, is_pkg in walk_packages(path=[settings.BASE_DIR]): + subclasses_from_module = self._collect_classes_from_module(module_name) + if subclasses_from_module: + result[module_name] = subclasses_from_module + return result + + def _collect_classes_from_module(self, module_name): # type: (str) -> List[Tuple[str, str]] + for excluded_module in getattr(settings, 'SHELL_PLUS_SUBCLASSES_IMPORT_MODULES_BLACKLIST', []): + if module_name.startswith(excluded_module): + return [] + imported_module = import_module(module_name) + classes_to_import = getmembers( + imported_module, lambda element: isclass(element) and element.__module__ == imported_module.__name__ + ) + classes_to_import = list(filter(self._should_be_imported, classes_to_import)) + return [(name, name) for name, _ in classes_to_import] diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/jobs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/jobs/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9e50845e8486c7bcfc840664f3829ad9d1f6232 GIT binary patch literal 193 zcmZ?b<>g`kf=l~9#)Ig`AOZ#$feZ&AE@lA|DGb33nv8xc8Hzx{2;x_kerR!OQL%n@ zQB`GeRY`tYd{Ta1YI1g_zDsIxc1eDLepzCAX|aA;YF?RsPG*vRL1jrsex9+OxqfkG zNvdu^Vsdt3dTOzLN>*ZCdVYLrMM-L2ab|vAv3^#5Qn7w~d}dx|NqoFsLFFwDo80`A O(wtN~kQ+V&F#`aye>V*P literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db84f85ab6c20ee10a826b60daae40aeb6a9b8f9 GIT binary patch literal 199 zcmYL@u?oU47=%-B5TOs^VE@6vMMT8eMVv$0{?;@#3H{Sz`bIv5@8Ia_6NsCW$siuw zcgIb)Nz(}ny5C+r<}>1_B$Rb9jRH!xXVYYNWo?}Q_*gg)wgjpjJPpnqd2TcoO2QUN zIb)$0RY%aH?xB%6Snp0o&$9)PbU3r3P@+PDvKG2B94`(vNuvpBlZRQz#slY4OUHR; R{bRg5o3d+g6`#C=*%uX8IaL4v literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__pycache__/cache_cleanup.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__pycache__/cache_cleanup.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..41998f31e83fbe429eea3e989a8bf124a8aeb483 GIT binary patch literal 983 zcmZWn!EVz)5Z$#M$8r-82vziEE~q|WA3)+#A=;#(0x6dYAz2`6&CQ<5k> zwcV6Iv@ZErf$bNhm@s1nwzKzQSeUfi17vK# zKLvxK3RzJEqaFZjH7-0{ZTC#EXqOJ-JA|enzNu!IG|~f6N1!y)nBogZ z_7|@-K5?$xYt%B@eX!sAa5(5^-9E5o__1BZ?WR2;ifApR0VRD(bR!zV-RbNXzk*}9}3QjX_@w! znrbmi&&YVL(lf@-(yAP$v!$L0{xW%;Drn@zj1*HcW-6s8gpWne7MgK8%M{iD!e)2U zO$Rp{l+2b*n=M!|*X%L$pgN!s4)GKG00+2(S6eWFi@|``p zi%6DO43_Nd*?(Y@nsA`OY;9t2OY@EW;$9<$aA~?}g1rrjH*N4#0LpVZxZ`x(e?9UE AdjJ3c literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__pycache__/daily_cleanup.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/__pycache__/daily_cleanup.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2a04f4aa0b9fce05503c0ee153df3c93660aa0b5 GIT binary patch literal 796 zcmZWmv5wO~5Z$$Xm&lih_C&Qv6u7`HC}ElPH`;O^aGATO2mPR+MTZ4ZU!UB7y750Q(TN#kC1#2sl_9ja5lXDU0nVq6By-*-3G*xI zho+@AU>y7Tq!e|{OWk0ZOoAb@P%nMz8!?yo<4>P`uwZPqF^9c9bb84Pt)Sdg*&OVq z(`~jDtKMc?P}{7oimcstYpq_SFEd+p@Vph}1_9aZIGe++1Lf(>@In}N=R8_|I%?YP zhY{?c>^pdb7_5Uz=!71wkf8LGSs;~T&Xs6@^C9NE(Xy|dKjHjiFX~e!T0`BMF?R3^ zJuo8|a}-Zd{g5$@0v}l<(JXP&P$$!w(e=MhN3*(OE3m>$1^cgo}7{5AVd+lC+ IP!vqUzYZeR&j0`b literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/cache_cleanup.py b/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/cache_cleanup.py new file mode 100644 index 0000000..cb92a82 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/cache_cleanup.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +""" +Daily cleanup job. + +Can be run as a cronjob to clean out old data from the database (only expired +sessions at the moment). +""" + +from django.conf import settings +from django.core.cache import caches + +from django_extensions.management.jobs import DailyJob + + +class Job(DailyJob): + help = "Cache (db) cleanup Job" + + def execute(self): + if hasattr(settings, 'CACHES'): + for cache_name, cache_options in settings.CACHES.items(): + if cache_options['BACKEND'].endswith("DatabaseCache"): + cache = caches[cache_name] + cache.clear() + return diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/daily_cleanup.py b/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/daily_cleanup.py new file mode 100644 index 0000000..ee08d3a --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/jobs/daily/daily_cleanup.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +""" +Daily cleanup job. + +Can be run as a cronjob to clean out old data from the database (only expired +sessions at the moment). +""" + +from django_extensions.management.jobs import DailyJob + + +class Job(DailyJob): + help = "Django Daily Cleanup Job" + + def execute(self): + from django.core import management + management.call_command("clearsessions") diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/hourly/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/jobs/hourly/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/hourly/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/jobs/hourly/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42897d924523e6e2fcefc8d8a349a2a8e8f9de67 GIT binary patch literal 200 zcmYL@Jqp4=6ofZmAwmvfVP0WjBO+pLBi2iPp2;S0U(DMCH#hPW-oet=6NsIayM;I~ z-wadDCJZOS>3(}jpHGjU0$0|~JaWjyUQC1CRkVKo<8y`sW6MyrgXO`{Q6{7@trTpL zD?<(Rao#cXsC%eY0*y5V>3OsORt9HHoK|s;3|SfLoFrZhYF4BfN=g_C>e||Zlu9cj TWz^WmczL3%t8wM8yq(1tSX4RY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/minutely/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/jobs/minutely/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/minutely/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/jobs/minutely/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4513315141b60ce1089287a77681b04b0fd45de0 GIT binary patch literal 202 zcmYL@u?oU47=%-B5TOs^VE@6vMMT8eMVv$0{??c_3H{Sz`bIv5@8Ia_6NsCW$siuw zcgIb)Nz(}ny5C+r<}>1_B$Rb9jRH!xXVYYNWo?}Q_z)ZjTLRS%o(5-*JU1E(C1H!C zoUzc0sw3!8_fX3mtam4)=h*^CI-FTiC{ZCnc^0}d94`(vNuvqQCMRg5?i|)0IG0*F T&NJ&D<7H#YuEte7^A2WT)ml2d literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/monthly/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/jobs/monthly/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/jobs/monthly/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/jobs/monthly/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..94c7cbb788f12b0bff8d8ac991081262e3e1f360 GIT binary patch literal 201 zcmYL@Jqp4=6ofZmAwmvfVP0WjBO+pLBi73%c_y2meIaiX+}y}hcn3>cPat+yZVGW= zz8R*PT^P=U*ZuaAV?Iax6!^0B=7~otj$$4huA&|1KRzv-7+Z$29UKpq&N3#0NvUCv zTv}?NS6RoGziGqmW`v$mDT2YF3p+toQqykh;OVvp-EfF(GluHo^sd6$WQxnIIY$t*T zL1M>_6>q_NAlUH&NURXY;Zm{SX#V*u`S*W3b3ScuykS(=Nw-NQ=_cs|Db#1u719?{ zLHbI%M0$9Ev8%*{c!Ss=UL$sh8^ou?%fuJN2c$76VqGC8?1c*6kP~``3U>&^f-f)tUqXXJ5e7O#(G}3N|wB_tQ;Sj1fpJd z$eW=J9pWwOmcUM2uk(0^9;nxo`#allJ&wu9`?!)J{I~B}miBqk<*gJRcax&M{k+@B zqFgx7hgN8(gf}*UqfwqiCoMAA&x*92AEvEVKN}1V$f~QQsE`j)%oE7d&haQ*c|Xq& zm8=iM~9021pbQ3g8%>k literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/da/LC_MESSAGES/django.po b/venv/lib/python3.7/site-packages/django_extensions/locale/da/LC_MESSAGES/django.po new file mode 100644 index 0000000..42e323e --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/locale/da/LC_MESSAGES/django.po @@ -0,0 +1,79 @@ +# django_extentions in Danish. +# django_extensions på Dansk. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Michael Lind Mortensen , 2009. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-02-02 11:42+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: admin/__init__.py:121 +msgid "and" +msgstr "og" + +#: admin/__init__.py:123 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"Brug feltet til venstre til at lave %(model_name)s lookups i felterne %" +"(field_list)s." + +#: db/models.py:15 +msgid "created" +msgstr "skabt" + +#: db/models.py:16 +msgid "modified" +msgstr "ændret" + +#: db/models.py:26 +msgid "title" +msgstr "titel" + +#: db/models.py:27 +msgid "slug" +msgstr "slug" + +#: db/models.py:28 +msgid "description" +msgstr "beskrivelse" + +#: db/models.py:50 +msgid "Inactive" +msgstr "" + +#: db/models.py:51 +msgid "Active" +msgstr "" + +#: db/models.py:53 +msgid "status" +msgstr "" + +#: db/models.py:56 +msgid "keep empty for an immediate activation" +msgstr "" + +#: db/models.py:58 +msgid "keep empty for indefinite activation" +msgstr "" + +#: management/commands/show_urls.py:34 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "Lookup" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/de/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/de/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..6367477a60131e171dced2207a9dd526008a3235 GIT binary patch literal 1227 zcmZvaPmj|^7{;fC76`ORaNq*cdnl+Y@RF=RLgtS!8!tpSn{ARsY7eX?@f&A|Gh@w+ z5pd@l05@)^x2nBXs(L|OIdQBw@hy62pYd+RQZe%Q=dqr7-^ZTk{fUFm1;%mA)0odN zPhlSW0ym5~cmY)4*We5AF!*wB{WI9d`WNs3_&0b6{0BS=9{N&r{vGfj zI0r-BCHNKS!OPhD1U!TFZzvkxzXe0xcYFK`+`;+-h)Z-)EY!UN9s_>>L*M)03iuQ} z0{#l(62IdX`u+)q`fotAZ9IPihIiqg>>r{2e*^X!Ki`6(Ug#O>hniuucG28}KXKMk zZrG7Fo@76 zJk-byo&A1kaxQnYT=I&evXMJdx{)_Z2T}8|Q!3|I+^Uc|7gNj9b1rgrQ>!Ykj1~*# zig;Q1$22pRq$agoa;_kx#*h4*OzE6wN~=#ru%*y77p|-e;k@*<6JGg}#g;YUTcchc z-DB&}Ii{^-{cdtQrF-dc)EjKJhFlrzqrNLt9^I-77mZC!t*ya0S`W^#DeA&kOl$2< zCu*4;(NLu(_|R+2T?bnJA=62JO9&QGi_zk`DkpVcBS;j z#}Q@WP+lU{Z+>2`y|A1xSXyDv8b}|o3 zYsy(S8$vEW%?{k|Cn3WtD;7baDtx8(u-S25?-rGtqYMcTPme, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-02-02 11:42+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: admin/__init__.py:121 +msgid "and" +msgstr "und" + +#: admin/__init__.py:123 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"Das linke Feld benutzen, um %(model_name)s Abfragen in den Feldern %" +"(field_list)s durchführen." + +#: db/models.py:15 +msgid "created" +msgstr "erstellt" + +#: db/models.py:16 +msgid "modified" +msgstr "geändert" + +#: db/models.py:26 +msgid "title" +msgstr "Titel" + +#: db/models.py:27 +msgid "slug" +msgstr "Slug" + +#: db/models.py:28 +msgid "description" +msgstr "Beschreibung" + +#: db/models.py:50 +msgid "Inactive" +msgstr "Inaktiv" + +#: db/models.py:51 +msgid "Active" +msgstr "Aktiv" + +#: db/models.py:53 +msgid "status" +msgstr "Status" + +#: db/models.py:56 +msgid "keep empty for an immediate activation" +msgstr "Leer lassen für sofortige Aktivierung" + +#: db/models.py:58 +msgid "keep empty for indefinite activation" +msgstr "Leer lassen für unbefristete Aktivierung" + +#: management/commands/show_urls.py:34 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s ist kein urlpattern Objekt" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "Abfrage" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/el/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/el/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..de23560b7e65bd11cb60ed170e0a0721bc4b953a GIT binary patch literal 1581 zcmaiz&2C#o6vqcBw3rr9yFfxn93)aTDmU1HMReO#NlQ`%*$`C@%SIF5u`})U%;nCw zqO9oWDjOsUE4Hx7hc3kgmqvbrxo^-H=o26o^grW}q@{vU#=ki;=i`5l<44C2-D6m9 zV84U?9rjz;M_<4P)++b`D8X02@4+MBkGu9yU<39B_!9URco_T}d<{JOB4a1P6X5$` z4Ep$G@DR8P`n+B6Wzd2dV!sBPupcAoQE&#%Z-Nc*ICvS{0KWu%{JRK#8$1d6_gU~f z*aYXnA9mj#fhS=933|U{2=@62MA@ME7>MUE6JT$7-Ty4e3w^#0LPE&#D(JQNRT&|C z`nj+%Lx~oKl(xjPOz@nnrWHY)dU=|0YelX|uUru=%Vt|vUK4CV@zJ5K_0?X+mW&{~ zDkv3gOKmCA#OFvfjh*W1M5N1#cg47&G`Jg*D!2zv1E+9UPNlKqW`c2*uvRX(6$wj( zY2`ArQY&^S!xv)8GubK;6*w<{6}M+$oQ^W3CLL|ZEPv=d}WR85#kdmUyhw>`tG zw5ec=x%RzA3rX~a$PFsTlw9Geqa*Q^70Tb3$|aHM+(r%4kx6vE*D+C3$5dJTycu2a z+Tj#^0%b8xR%^AWI*C83)#8sQPgiTzDjcIr;+piyp5s@IKbksS#j4b~u~9SU%B0-t zJf=^%Qqs^_C<13vAu-?ysoMG+oK>gCJ0fZd-i@g~``N{%*^6^@wqBn}<%G^V=PHeb z#@v2mwTWuwf>vk?Rjy}{YtiI~S<0n4L#|d7XDnOezbenVvjDqvP}`Mej{hZM?$9$dLQh_1zAYcU|GO+>Yy) zw{aQ}js@Y#-vxVPbW^w;cnsWw@b=ILyWxR6%&aO, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: django-extensions\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-02-02 11:42+0100\n" +"PO-Revision-Date: 2011-02-02 10:38+0000\n" +"Last-Translator: Jannis \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: el\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: admin/__init__.py:121 +msgid "and" +msgstr "και" + +#: admin/__init__.py:123 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"Χρησιμοποίησε το αριστερό πεδίο για να κάνεις αναζήτηση του %(model_name)s " +"με βάσει τα πεδία %(field_list)s." + +#: db/models.py:15 +msgid "created" +msgstr "δημιουργήθηκε" + +#: db/models.py:16 +msgid "modified" +msgstr "τροποποιήθηκε" + +#: db/models.py:26 +msgid "title" +msgstr "τίτλος" + +#: db/models.py:27 +msgid "slug" +msgstr "μίνι-όνομα" + +#: db/models.py:28 +msgid "description" +msgstr "περιγραφή" + +#: db/models.py:50 +msgid "Inactive" +msgstr "ανενεργό" + +#: db/models.py:51 +msgid "Active" +msgstr "Ενεργό" + +#: db/models.py:53 +msgid "status" +msgstr "κατάσταση" + +#: db/models.py:56 +msgid "keep empty for an immediate activation" +msgstr "αφήστε άδειο για άμεση ενεργοποίηση" + +#: db/models.py:58 +msgid "keep empty for indefinite activation" +msgstr "αφήστε άδειο για αόριστη ενεργοποίηση" + +#: management/commands/show_urls.py:34 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s δεν φαίνεται να είναι ένα αντικείμενο urlpattern" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "Αναζήτηση" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/en/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..4ed8824d31092b07af760f84f33aad2e54a619d0 GIT binary patch literal 367 zcmYL^K~KUk7=|@^+R?Lz9=zd)8_@(S5-KaW*luJD61`QZvj$tz6{A1Izvpl9TVmu* zpY+hDU*G$wCN{Gs($-OO}ZdOVg6i=R;I& zy;HS@N~?ED1k0z3w(>xT(Z+P0uZNM$B;S83>BiC6*`O`H@wLUWL4Sse?M4}ULsqZK eH#*!dstNS>UfbnGd*F8E*2dP9^q), YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-02-10 20:37+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: admin/__init__.py:142 +msgid "and" +msgstr "" + +#: admin/__init__.py:144 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" + +#: admin/filter.py:24 admin/filter.py:53 +msgid "Yes" +msgstr "" + +#: admin/filter.py:25 admin/filter.py:54 +msgid "No" +msgstr "" + +#: admin/filter.py:32 +msgid "All" +msgstr "" + +#: db/models.py:18 +msgid "created" +msgstr "" + +#: db/models.py:19 +msgid "modified" +msgstr "" + +#: db/models.py:38 +msgid "title" +msgstr "" + +#: db/models.py:39 +msgid "description" +msgstr "" + +#: db/models.py:60 +msgid "slug" +msgstr "" + +#: db/models.py:121 mongodb/models.py:76 +msgid "Inactive" +msgstr "" + +#: db/models.py:122 mongodb/models.py:77 +msgid "Active" +msgstr "" + +#: db/models.py:124 +msgid "status" +msgstr "" + +#: db/models.py:125 mongodb/models.py:80 +msgid "keep empty for an immediate activation" +msgstr "" + +#: db/models.py:126 mongodb/models.py:81 +msgid "keep empty for indefinite activation" +msgstr "" + +#: mongodb/fields/__init__.py:22 +#, python-format +msgid "String (up to %(max_length)s)" +msgstr "" + +#: validators.py:14 +msgid "Control Characters like new lines or tabs are not allowed." +msgstr "" + +#: validators.py:48 +msgid "Leading and Trailing whitespaces are not allowed." +msgstr "" + +#: validators.py:74 +msgid "Only a hex string is allowed." +msgstr "" + +#: validators.py:75 +#, python-format +msgid "Invalid length. Must be %(length)d characters." +msgstr "" + +#: validators.py:76 +#, python-format +msgid "Ensure that there are more than %(min)s characters." +msgstr "" + +#: validators.py:77 +#, python-format +msgid "Ensure that there are no more than %(max)s characters." +msgstr "" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/es/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..8ff3f06505ed1a813b53b4ce90f7a41f80d2b2eb GIT binary patch literal 1260 zcmZvaPmdHu7{*IP&=D}fgBK6)!8H=-VFoZEEfSjD1}4tzY-VR5dT>+Q{mx9W-BnFh z^~U9Ms0S0T-bhTmdEGl#!ewv98()9}Jk>Mfy2dwM{i{kp@1N>CM;A~3BoH5AeTwxX z)+bo!-oXno2d{t%JOlm=z7PJoJpTp`aDE293%&-=f^WbN!Lz4?_#FHg{0xl2kiP?- z2IpX?TY~R_9{duyPr;D)JBo(yFTjv@v^@U}PH}z(LM|pK7IcrmbKv)28{7l0gTH_+ z@HvP_yu>T$kCyxk40XcH=dr>p;h+3FLjP4@yyl)4z)&yr`~WM|3=w**0wW5s<|sGp zNE=VGs#sd`hIW}G)wZal_iQzp-N&4Hkz`)&v*>BL*z}Frt1B^aOn%N(@YK^(agm1_ zxuLZ$N|ST3qh-mL92Je+kRe=&rRQAa>@uq=uZ$LZ%oTB2 z`2(67OHz|6OU@O9)XXFQPo{LvQ>E2O5yn#JnhRIdGvU1SwG&?Xg2k3K;jU3Hj~=ph z=p55lvi?nSKc$E1XuCJuY>l`w)<*+3Q+af^p1EjjVrp#-$I*J297)jz=8EZBr`wG> z*YHrc8{fEoxzp`*AdE)5uR`&q?%OmOMT23qk_WRys&}{X5CV#wgw1z746K)pEwsm}MDLKiRxL2_xU?_wN*{ZS3rJYtS2{ z$Cv81JFRu2J!|whs4%SOANgTG7p{R3j(xN+kXaeXh`Y7Rq!kmd3WYo_D3fIc@4!rw)YB)mVw=lQ zSJGT&sJnakr+ZR!E*-IkrQ9Orzdi~jPTH?64jNzOW@W2P9sZ$3DZ@WN<$akQK5Om( w?`yd, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-02-02 11:43+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: admin/__init__.py:121 +msgid "and" +msgstr "y" + +#: admin/__init__.py:123 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"Utilice el campo de la izquierda para hacer búsquedas en los campos %" +"(field_list)s de %(model_name)s." + +#: db/models.py:15 +msgid "created" +msgstr "creado" + +#: db/models.py:16 +msgid "modified" +msgstr "modificado" + +#: db/models.py:26 +msgid "title" +msgstr "titulo" + +#: db/models.py:27 +msgid "slug" +msgstr "slug" + +#: db/models.py:28 +msgid "description" +msgstr "descripción" + +#: db/models.py:50 +msgid "Inactive" +msgstr "Inactivo" + +#: db/models.py:51 +msgid "Active" +msgstr "Activo" + +#: db/models.py:53 +msgid "status" +msgstr "estado" + +#: db/models.py:56 +msgid "keep empty for an immediate activation" +msgstr "mantener vacío para una activación inmediata" + +#: db/models.py:58 +msgid "keep empty for indefinite activation" +msgstr "deje vacío para mantener la activación indefinida" + +#: management/commands/show_urls.py:34 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "% s no parece ser un objeto urlpattern" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "Buscar" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/fr/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..bc4e1cd7c3416b1264193e62b7fe6e494248a863 GIT binary patch literal 743 zcmZvZzi$&U6vtg?`Ek&N4T-^G0aQ8Mr5z%-i5f~;1tkzwS9WvfI~-l?lkKbE4`F9u zi5QWXV9LZlz=DLte*haJUndb25>Ni#$3NbCe!lnp*5(@mi=aDD1#Ls0pkP0tE6^|K z8uS~w3~g)>auwVHZ-CoiIKK^Uf_K3XcMseGTcCmV*8A@+t>WK<7~}&!!T%!|@_hzx zf?vRp?<*Mcd|UGeh*ZnELtO9)7HY!LvX-z8F~P1wp>ER8ygHX;sKsg`bWSoWg_k+W zrOT|Uy)v52Os)!rO;bku)(a@Ic? z(1X$Fuu?5!%U(1djt3VHOImSsWHg?ITVB^F*W-~7>q;oSPqUZ8I_bM-=`rhE_=Rc; zY1u$$_>H>cwDUswzqfN**l1EUR#fcR*qP&0*UP2rw)g33+P$x7k0uWyvhI{xwyYr1 eqhX8rV*YQxl#_JvmQGD$S3O(I(X`MqE6E=Q1-A(R literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/fr/LC_MESSAGES/django.po b/venv/lib/python3.7/site-packages/django_extensions/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000..0e9afbe --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,81 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# mathiasuk, 2014 +# mathiasuk, 2014 +# stevandoh , 2013 +msgid "" +msgstr "" +"Project-Id-Version: django-extensions\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-02-02 11:42+0100\n" +"PO-Revision-Date: 2014-01-11 11:14+0000\n" +"Last-Translator: mathiasuk\n" +"Language-Team: French (http://www.transifex.com/projects/p/django-extensions/language/fr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: admin/__init__.py:121 +msgid "and" +msgstr "et" + +#: admin/__init__.py:123 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields " +"%(field_list)s." +msgstr "Utilisez le champ de gauche pour faire des recheres de %(model_name)s dans les champs %(field_list)s." + +#: db/models.py:15 +msgid "created" +msgstr "créé" + +#: db/models.py:16 +msgid "modified" +msgstr "mis à jour" + +#: db/models.py:26 +msgid "title" +msgstr "titre" + +#: db/models.py:27 +msgid "slug" +msgstr "slug" + +#: db/models.py:28 +msgid "description" +msgstr "description" + +#: db/models.py:50 +msgid "Inactive" +msgstr "Inactif" + +#: db/models.py:51 +msgid "Active" +msgstr "Actif" + +#: db/models.py:53 +msgid "status" +msgstr "état" + +#: db/models.py:56 +msgid "keep empty for an immediate activation" +msgstr "laisser vide pour activation immédiate" + +#: db/models.py:58 +msgid "keep empty for indefinite activation" +msgstr "laisser vide pour activation indéterminée" + +#: management/commands/show_urls.py:34 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s ne semble pas etre un object urlpattern" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "Recherche" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/hu/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/hu/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..2f98573ee24df46945ece336df0b4ad3a4b4c3e2 GIT binary patch literal 1242 zcmZvav5y-?6vhV%-Tub%%(V7!9$ zI@Xt1m$5EAgAHQ_z6C1qdGKrSBKY0e{d=&B`wBb<{s~?H{{~+KFFY&6o8W8U8(`3fTZF5H!#Hg4qgKP00-b-Ag1UeS*Uje2Hgk@b#w44 z_{G`#Pavjvge~YEpWS}}QFfiHwCxBkwT!H_R_dI2kV4WqHadJq1@ z6-Sw2N7{IjRmIYhH#B0BG`B@1y=SY*j6UJ97xCDu1&fZBn?q_$KCi@~WAZbmf+wCP zii<4d$P8V%TAGZDV=YU*=BQZ99Vxw*uayp>_2IZs&R=soLh4M6Elbat$k>gos=P8< zE}*(E%_f9VpBE}5Khu4b#Qmt-i}qrA&}(-)*FWy_ib)=smrYqV#L8YdOZdj8bET@_O4TQr_Y>)5}4IJ_6#e4-0pCTycbkMRrj zv`sfh$~Q#)&GdwHeY&Jv(ahk2#?o98e|^ zOI<%iA4wX?!W5Y-6qUUE`E$R?p0j1=@VwPxTg|kIQ6ttO, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-02-02 11:43+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: admin/__init__.py:121 +msgid "and" +msgstr "és" + +#: admin/__init__.py:123 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"Használd a baloldali mezőt hogy keress a %(model_name)s %(field_list)s. " +"mezőiben" + +#: db/models.py:15 +msgid "created" +msgstr "létrehozva" + +#: db/models.py:16 +msgid "modified" +msgstr "módosítva" + +#: db/models.py:26 +msgid "title" +msgstr "Cím" + +#: db/models.py:27 +msgid "slug" +msgstr "Slug" + +#: db/models.py:28 +msgid "description" +msgstr "Leírás" + +#: db/models.py:50 +msgid "Inactive" +msgstr "Inaktív" + +#: db/models.py:51 +msgid "Active" +msgstr "Aktív" + +#: db/models.py:53 +msgid "status" +msgstr "Állapot" + +#: db/models.py:56 +msgid "keep empty for an immediate activation" +msgstr "Üresen hagyni azonnali aktiváláshoz" + +#: db/models.py:58 +msgid "keep empty for indefinite activation" +msgstr "Üresen hagyni korlátlan aktiváláshoz" + +#: management/commands/show_urls.py:34 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "Úgy néz ki hogy %s nem egy urlpattern objektum" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "Lekérdezés" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/id/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/id/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..e90a0a7769be77c4185fb9827712ae6d7133dffa GIT binary patch literal 1508 zcmZ{i&u<(x6vqvOUqkuPA|Vb1nL|;dYPOrSYNAO~Wr1xPv74@%O(i6x$UFAVI^(fN zV>={VIC0{_g?|GHfjDrYHzYW5;Y5%86&(1!-A%S>#nU{0Z0r3TzsHxBzGINLp_idQ zLEnS+p2Gt96?_SN1ik?N2HpVw0B?cpdB$D=*1#6H1>$243&m;X{1)uv{5?o<{+*K! zFXOxfz6M?ZDc-x_68Hf~`9B0-1XJ)+s$qWq3PyDQHFyR52D}FT08*U4!Rz2ZAlbcx zg@c#D_rXo@A^16nlGu+RLbIPi%KHoWD)?xA{vAXp_UHWk7l@BN#)7g~0wtjsm!NOb z0rCcv`XspkrChH=DK-h^qPQgVA1*>E?y0;r-%wAdLT|=8dC*6Sb&O$M>tmyMn23Ny zVJo1Oo84J{$JDt;o?XI)%LV|&?^gw*(Go9ELzbBeVLvc2!3&$bF zX7_|W5vM~+^Lj!tq}E?*i#iv>IziWkcxGC+BhsUv5u(A-tC2Ed!b^?Dq7AX+wX!+d rgbgPB$pNl~6sLaAjICgZ$D|%b5ol;j46WC=h$AsMH?W6MM#KICtaOA> literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/id/LC_MESSAGES/django.po b/venv/lib/python3.7/site-packages/django_extensions/locale/id/LC_MESSAGES/django.po new file mode 100644 index 0000000..afd7519 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/locale/id/LC_MESSAGES/django.po @@ -0,0 +1,98 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: django-extensions\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-07-27 22:25+0700\n" +"PO-Revision-Date: 2020-07-28 10:48+0700\n" +"Last-Translator: Sutrisno Efendi \n" +"Language-Team: LANGUAGE \n\n" +"Language: id\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: admin/__init__.py:139 +msgid "and" +msgstr "dan" + +#: admin/__init__.py:141 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"Gunakan bidang sebelah kiri untuk pencarian %(model_name)s pada bidang %(field_list)s." + +#: admin/filter.py:24 admin/filter.py:53 +msgid "Yes" +msgstr "Ya" + +#: admin/filter.py:25 admin/filter.py:54 +msgid "No" +msgstr "Tidak" + +#: admin/filter.py:32 +msgid "All" +msgstr "Semua" + +#: db/models.py:18 +msgid "created" +msgstr "dibuat" + +#: db/models.py:19 +msgid "modified" +msgstr "diubah" + +#: db/models.py:37 +msgid "title" +msgstr "judul" + +#: db/models.py:38 +msgid "description" +msgstr "deskripsi" + +#: db/models.py:59 +msgid "slug" +msgstr "slug" + +#: db/models.py:120 mongodb/models.py:76 +msgid "Inactive" +msgstr "Nonaktif" + +#: db/models.py:121 mongodb/models.py:77 +msgid "Active" +msgstr "Aktif" + +#: db/models.py:123 +msgid "status" +msgstr "status" + +#: mongodb/fields/__init__.py:22 +#, python-format +msgid "String (up to %(max_length)s)" +msgstr "String (hingga %(max_length)s)" + +#: validators.py:74 +msgid "Only a hex string is allowed." +msgstr "Hanya string hex yang diizinkan." + +#: validators.py:75 +#, python-format +msgid "Invalid length. Must be %(length)d characters." +msgstr "Panjang tidak valid. Harus %(length)d karakter." + +#: validators.py:76 +#, python-format +msgid "Ensure that there are more than %(min)s characters." +msgstr "Pastikan lebih dari %(min)s karakter." + +#: validators.py:77 +#, python-format +msgid "Ensure that there are no more than %(max)s characters." +msgstr "Pastikan tidak lebih dari %(max)s karakter." diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/it/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..c7fa82971b769f7fc126b8bef6d9f0d9e721d052 GIT binary patch literal 1247 zcmZvbPjA#l7{-S}3tiG8l>-+J@1d!PQm4BVq{xIQZer+)-E6ekMFJs3v-Z2*A@+z}Q8-aob<|MA(S9|YDl#7)Ha zh#QE73pioTz%M}segwV%uYff9=wa(BXAk_zoKZ^{~Zi@e}bX@Um$~TK*+^Y6brg%VCb8Hw?G3ffj@#R z@Fj>tyuvB;dku!X-@s5OC6Rkc?}i+$#r zxT^gjO^qd~NmUi+3PNh;k^d)CI_Ig<>bwYJDRj++E9Zr9Ui!HcUip&6jy2&~qi!BO zX6w*7rk!N-QSvaQ$LVmlJJ@awxi;2EeOIVF`et6ZXk=n)?F>fIW|$mF(H7>4>2|x* ziQ2buP^S~$`FgqCX}2MahJ2tx@e|#XG#N(yL9~_7w}ZIfU4A;)PFp?cd^ECByHa{% zV|p;|^=Lckr?i&#lWuP#+1eVWySwX<>S8Vnjz%o2n0m?f!*LjSt=HQq)rzsjdaK{< zr)Lk7)umMW9%VCW9sB#^(SvC9Oc!REvW-%m;T7s4rqzk^ zEwM`6Dx_GW6Ly$bBcmJ+yFD}9Ggib9xgJ$MaLIIm9fpF7<*N!qa%q#RZ=Fa z+Q5YlAJ2Kztl82uY}!T-ziC#DOugqJg6F7lUirQUSMYZ><}xSVI>I+#QA(GoQ2StR lFl=bm3@4lIe~c#23)O#xr*4zt*kT#J+nLEs@R%u$_#4cjM;rhE literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/it/LC_MESSAGES/django.po b/venv/lib/python3.7/site-packages/django_extensions/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000..14af204 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,77 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-02-02 11:43+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: admin/__init__.py:121 +msgid "and" +msgstr "e" + +#: admin/__init__.py:123 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"Utilizzare il campo a sinistra per fare ricerche nei campi %(field_list)s " +"del modello %(model_name)s." + +#: db/models.py:15 +msgid "created" +msgstr "creato" + +#: db/models.py:16 +msgid "modified" +msgstr "modificato" + +#: db/models.py:26 +msgid "title" +msgstr "titolo" + +#: db/models.py:27 +msgid "slug" +msgstr "slug" + +#: db/models.py:28 +msgid "description" +msgstr "descrizione" + +#: db/models.py:50 +msgid "Inactive" +msgstr "Inattivo" + +#: db/models.py:51 +msgid "Active" +msgstr "Attivo" + +#: db/models.py:53 +msgid "status" +msgstr "stato" + +#: db/models.py:56 +msgid "keep empty for an immediate activation" +msgstr "lasciare vuoto per attivazione immediata" + +#: db/models.py:58 +msgid "keep empty for indefinite activation" +msgstr "lasciare vuoti per attivazione indefinita" + +#: management/commands/show_urls.py:34 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "% s non sembra essere un oggetto urlPattern" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "Ricerca" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/ja/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/ja/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..95b488d8cfefb148f58a0efc5ea6ea9a1f526061 GIT binary patch literal 1397 zcmb7?&2QX97{&)E6qfR#a_EJ_94MkHPIn7P)e@?@iCb3Pk7%>0fJ@}8XLpBsZOb!T zQBK%fqNYUn@q9K5m_FMtKa-+_;Szk@r$Kfx!#oevZ8 zBKREm0+(%TZG~=NOUXiy`V;T6sw8Gr^3#muJbPo2 z_x)3?fQ$)7WrIW$)(H4Na*Xm8ac-}$wGn7Svq14oiLAE^rTfD&6SF&G7J1r8U<13 zj&ZbA7e>X;($q+)Vhm~LNHT`uD@zZiGZ`a&5Esp4vai0fKb=XZAvDVDG}py9b#Gf{ z*(j8ZVUxaD$`*3_-zgQXRNfZSsD!pBTwD5KmL40+=V{R_Sai@Tn7RBBb9lIHjgB6M z)T_7bIx{NFZf0rTEFK@zmIw3sBQ78C!}{S=Ay=>-Y$`L5P7V26~w!vK-%^~@x}GEd;Lo{RCHNI z3+s0vp3$y9h>41BkoC2>-nr@C, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-02-02 11:43+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: admin/__init__.py:121 +msgid "and" +msgstr "と" + +#: admin/__init__.py:123 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"%(field_list)s フィールドの内容から %(model_name)s を検索するには左のフィール" +"ドを使用して下さい。" + +#: db/models.py:15 +msgid "created" +msgstr "作成日時" + +#: db/models.py:16 +msgid "modified" +msgstr "変更日時" + +#: db/models.py:26 +msgid "title" +msgstr "タイトル" + +#: db/models.py:27 +msgid "slug" +msgstr "スラグ" + +#: db/models.py:28 +msgid "description" +msgstr "説明" + +#: db/models.py:50 +msgid "Inactive" +msgstr "非アクティブ" + +#: db/models.py:51 +msgid "Active" +msgstr "アクティブ" + +#: db/models.py:53 +msgid "status" +msgstr "ステータス" + +#: db/models.py:56 +msgid "keep empty for an immediate activation" +msgstr "すぐに有効化する場合は空白のままにして下さい" + +#: db/models.py:58 +msgid "keep empty for indefinite activation" +msgstr "無期限に有効化しておく場合は空白のままにして下さい" + +#: management/commands/show_urls.py:34 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s は urlpattern オブジェクトではないようです" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "検索" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/pl/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..321b54fb30a301733cc65a53faa47f88fffcbe7b GIT binary patch literal 2002 zcmZ{k%WoS+9LERR@-Xl65C=d%L4y*=8mbl)nY7eRO>3}|D340bfiT{kY{uT5S$1Z# zSqlj%Q02fC4yYII+~_qNpmq~y!*~Jn zCCpzjU&j3G0W27Qf|KB1;6vam4>DE*$G|h-C*Zr_*We@I9k2@i4xR>&9UJMr13J6Y zyIcX=c;5u^W4Ez94E_Q>2L1-V4&DV%fhUfS?7sox$If7J@l1gy!1uuy5n}^9h4+uK z>Fj+0x;VZ9&w@XKF5bVv3OE5HQ{Y+f92kSn?)O+;1AhQt1^)nN!GAzknkz8=DEJ`= zmuv|f1FwOuE}w%>fH!x)|Fp~7AWX13ptJJ~rW=oAK9Bjdd%<`L)78_BXE9NR(w?i0 z8&EIveiC$XJcsG*x>(#m`O9$b{j5g3V}UQytOFI#0O|0Yj1O2~r}*gMu{;E4*Wfr`UCtqe$l>sIrDK8TRZt zw^#%ook*-ldy2-!W2q(#`TM5-Pe`Y2A$Kjo1F1sdDxjs5OJo#MzAmjW3HOoQf0Alx-OCa-r=kL7TNj&TZ0fWmg!eLE z9Bqwfi7PPj=niHm)cFF|Ju!lOhV7R8R`)Kt!vG#{vmPr7J^HmExtOfwl5s zHIl|om?}f)%ufZkB4B|qekv0ywPHOX5)yG@3tGbwaYZtYMIa$aWwH2CVp0WSO)3=N zpiry>39kV&Q5G^|xy=l-(nf;Kr`lZ?uNin(aXH|*M)UQVkLs5jbhWXt*qocKEQmy> z)@z$k2HwRiG~SY~QDuJ4TM!%4>3EkAR*kMT>I+_b&bw5nD|5AW^UamH*+!+sjrDLk z%0%4iv_>l(87hejxF~(e(>_geWs6U{T3rZZ9Aeei@p-7JFyo={mIRM$)T+;3UUpGU zw^|n>S=DKHzS3^C8~5TqU46Ua?z>R%S0o6?icR}g5^<^CEANdF_T2K)2j0{@ITzQO zNWF&gQ6&}DXsRP^#WfpZq^`gP)Ey~$R>WkBBs$oHRTt`}oDqBuOu4I>t9DF-T!<}7EIbMAjQF6Gm-(Y=MzjZS|O38&7 zbGl!xY_NT`StKz)8xwu}9&$GdE)hXQha^1?VjgYD6`!<|Ms{)5n+nJepoHmx$rGMnqP zuW^t%k%lF@uhAqqCHVIdrRlPMI(N2pKq>EMM@hNU81>&sG~npoU{rkWcO~n?bFn6S R_zY)z-Kdx?Y&P6t{{pl*L)ZWS literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/pl/LC_MESSAGES/django.po b/venv/lib/python3.7/site-packages/django_extensions/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000..9dd07d4 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,109 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-02-02 11:43+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Zbigniew Siciarz \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: admin/__init__.py:121 +msgid "and" +msgstr "i" + +#: admin/__init__.py:123 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"Użyj pola po lewej, by wyszukać pola %(field_list)s w modelu %(model_name)s." + +#: db/models.py:15 +msgid "created" +msgstr "utworzony" + +#: db/models.py:16 +msgid "modified" +msgstr "zmodyfikowany" + +#: db/models.py:26 +msgid "title" +msgstr "tytuł" + +#: db/models.py:27 +msgid "slug" +msgstr "slug" + +#: db/models.py:28 +msgid "description" +msgstr "opis" + +#: db/models.py:50 +msgid "Inactive" +msgstr "Nieaktywny" + +#: db/models.py:51 +msgid "Active" +msgstr "Aktywny" + +#: db/models.py:53 +msgid "status" +msgstr "stan" + +#: db/models.py:56 +msgid "keep empty for an immediate activation" +msgstr "pozostaw puste, by aktywować od razu" + +#: db/models.py:58 +msgid "keep empty for indefinite activation" +msgstr "pozostaw puste, by nie definiować daty deaktywacji" + +#: mongodb/fields/__init__.py:22 +#, python-format +msgid "String (up to %(max_length)s)" +msgstr "String (do %(max_length)s znaków)" + +#: management/commands/show_urls.py:34 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s nie jest obiektem typu urlpattern" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "Szukaj" + +#: validators.py:14 +msgid "Control Characters like new lines or tabs are not allowed." +msgstr "Znaki nowej linii i tabulatory nie są dozwolone." + +#: validators.py:48 +msgid "Leading and Trailing whitespaces are not allowed." +msgstr "Białe znaki na początku i końcu wiersza nie są dozwolone." + +#: validators.py:74 +msgid "Only a hex string is allowed." +msgstr "Tylko wartość hex jest dozwolona." + +#: validators.py:75 +#, python-format +msgid "Invalid length. Must be %(length)d characters." +msgstr "Niewłaściwa długość. Musi być %(length)d znaków." + +#: validators.py:76 +#, python-format +msgid "Ensure that there are more than %(min)s characters." +msgstr "Upewnij się, że jest więcej niż %(min)s znaków." + +#: validators.py:77 +#, python-format +msgid "Ensure that there are no more than %(max)s characters." +msgstr "Upewnij się, że nie ma więcej niż %(max)s znaków." diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/pt/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/pt/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..7f9a633edef85317e55941a9980ce13b04824d37 GIT binary patch literal 1262 zcmaKryKWRQ6o$<;umq5xprJTLxI{2vHUWeNh*&}rMQkn#o3xQLb9Un}V-L1xmE<{q z22mkF#Y>O}pr?S2f{GFe3HUup6c7k&&VKgn?{kj5|9(7k_?f^sjW~~Zia3WDJb(|3 zHSj8^z@y-E@EG`Vcl{ci#riFH2>cEXfIq<#;J`s4E`n#lAus{M{uS^rxCVy21$YGX z;57DbftRp;hos^C7ck`gy1V`cu44TIgj`4@3wcs7)LjRMz&?bZ8Efg#@@;y5DY3?tOq8)#983yw0wjEFIVQixlylcpS8<+&9GRgDmkX0| zzM^Hp!;bP=?nvocUMn3$^<*Vi&JVj0A$2BF%hGcuGIps|rB_Ca$IK;hQTk2l8cR}> zDhkdNgjDw<|0Pp8h%+ECzxir>Cv#zJI=zi66QO6|ISeWlb6QOf#iXNb^ghu0LGm1y?P_vm_ zAG;Da;~2tdk^3qn-`B+vq|F;NI-0~cqj(Iuwsbz~SgBnuy|D>R;m5%J7<#1gzN93NT}VKn_dcsxYKUm%hianz46BE%4?E_J4&Tl>1u9omQ{b&5;Xy@YP9D&Gjk(%Y{L zmC|y`{@L54SK~~Z7}uamf9^Bnv(T*Fk9_4`Ck!ifjbLr d2jAhZQz#vZ?D#DW)7o(i%VF-f-})*y;un^HQNREI literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/pt/LC_MESSAGES/django.po b/venv/lib/python3.7/site-packages/django_extensions/locale/pt/LC_MESSAGES/django.po new file mode 100644 index 0000000..eb6c68b --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/locale/pt/LC_MESSAGES/django.po @@ -0,0 +1,77 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-02-02 11:43+0100\n" +"PO-Revision-Date: 2010-11-15 22:06-0300\n" +"Last-Translator: Fernando Silva \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: admin/__init__.py:121 +msgid "and" +msgstr "e" + +#: admin/__init__.py:123 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"Use o campo esquerdo para fazer com que o modelo %(model_name)s procure nos " +"campos %(field_list)s." + +#: db/models.py:15 +msgid "created" +msgstr "criado" + +#: db/models.py:16 +msgid "modified" +msgstr "modificado" + +#: db/models.py:26 +msgid "title" +msgstr "título" + +#: db/models.py:27 +msgid "slug" +msgstr "slug" + +#: db/models.py:28 +msgid "description" +msgstr "descrição" + +#: db/models.py:50 +msgid "Inactive" +msgstr "Inativo" + +#: db/models.py:51 +msgid "Active" +msgstr "Ativo" + +#: db/models.py:53 +msgid "status" +msgstr "estado" + +#: db/models.py:56 +msgid "keep empty for an immediate activation" +msgstr "deixe vazio para ativação imediata" + +#: db/models.py:58 +msgid "keep empty for indefinite activation" +msgstr "deixe vazio para ativação por tempo indeterminado" + +#: management/commands/show_urls.py:34 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s não parece ser um objeto urlpattern" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "Busca" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/pt_BR/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/pt_BR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..0282342d4fe7a803a66894a66c40beae1453a01c GIT binary patch literal 1310 zcmaKqL2nc{6vs`Q7P`Y<+^$9{+2k&x)Ey;SYrvyl=CsL zV{i`q8cg{gf**hkev3UjhwGO}n)1B{)B8WcFTlS+1-6j{a`6mIdA`!sc) zq$ORJtTcqwR4d;l(^m0RTm7b}bV}n?C4#975u%KB5K%|NV(i^FoX2cUWe?Z~oZP4J zV0dS6dxajXY}{YFcek~{mGd!M4~16Qt-1)=#Pz8)zBkE+sd8+}zCvAnTIlu`v+lL5 zw@3>M{VUh9?qatKVYb1$Iwk*K-AIO*O}wuMw-ee>;)HWS7vumEFZy5IA*H{}T F{slr`UKjuX literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/pt_BR/LC_MESSAGES/django.po b/venv/lib/python3.7/site-packages/django_extensions/locale/pt_BR/LC_MESSAGES/django.po new file mode 100644 index 0000000..5928e28 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/locale/pt_BR/LC_MESSAGES/django.po @@ -0,0 +1,79 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Claudemiro Alves Feitosa Neto , 2013. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-09-13 22:49-0300\n" +"PO-Revision-Date: 2013-09-13 22:49-0300\n" +"Last-Translator: Claudemiro Alves Feitosa \n" +"Language-Team: LANGUAGE \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: admin/__init__.py:128 +msgid "and" +msgstr "e" + +#: admin/__init__.py:130 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "Use o campo da esquerda para fazer com que o modelo %(model_name)s procure nos " +"campos %(field_list)s" + +#: db/models.py:22 mongodb/models.py:17 +msgid "created" +msgstr "criado" + +#: db/models.py:23 mongodb/models.py:18 +msgid "modified" +msgstr "modificado" + +#: db/models.py:36 mongodb/models.py:29 +msgid "title" +msgstr "título" + +#: db/models.py:37 mongodb/models.py:30 +msgid "slug" +msgstr "slug" + +#: db/models.py:38 mongodb/models.py:31 +msgid "description" +msgstr "descrição" + +#: db/models.py:63 mongodb/models.py:55 +msgid "Inactive" +msgstr "Inativo" + +#: db/models.py:64 mongodb/models.py:56 +msgid "Active" +msgstr "Ativo" + +#: db/models.py:66 mongodb/models.py:58 +msgid "status" +msgstr "status" + +#: db/models.py:67 mongodb/models.py:59 +msgid "keep empty for an immediate activation" +msgstr "deixe vazio para uma ativação imediata" + +#: db/models.py:68 mongodb/models.py:60 +msgid "keep empty for indefinite activation" +msgstr "deixe vazio para ativação por tempo indeterminado" + +#: mongodb/fields/__init__.py:24 +#, python-format +msgid "String (up to %(max_length)s)" +msgstr "Cadeia de Caracteres (até %(max_length)s)" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "Busca" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/ro/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/ro/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..00626a0d2b3b73aa10f15b57e2b0938610174fb2 GIT binary patch literal 1352 zcmaizPj3`A7{*=7ziug&=z&9fcn?jQEuAo%RBAM2Q$k2k(56jc(?c(jGxP4m!DEkX z4=NS6{R%A-2c(KaZ|#@JBEg9>7rqFG_VH}^E2LWM`PrVw@B7;O%=2@{{}5=OqJM$@ zJNkL_GaulAwhw*-D)1zD4?GP%IGXehi*ECd4fG8TcibfpPyX zcpTgZW84Zn0S53-?EMY=3iHn)itB4&jJpZO{Xc;R;4fgz`v{D>C*VimQ*aJ^27V15 z!^^myfLIdWfl z6_!028%WkQOGm-d9+RZT=~{-s&XC-cJgD0&HjSJP2G-tcYO&*)!akGcQJ|4x zUBnoLrJ1?P7OZ!Tthnn*w{lO)wDMNzA!-M^TKUlR^Fo?Jhp;~Gtw(bAp@ud-+4Y-d|HPU>XCy2@u{ z>UQe;i_NHE?L^0#hHB}U z{A3*cMoo06!oT*0XQyU;=~b~d88-oY#D>+@^W*z4M1J_NsvAu>1o?3I(3FyDT!m}k zejXuSBPov?Cu66m;CBsu_>VaX;*^eW-*)oj`)cZBakcd^BmFAjW6_hbmsDE)DqZ}Z k;)&GM(UbB22@PviDHs>hshe{d#LZ~uo9#J=aC0O61Nn?+$N&HU literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/ro/LC_MESSAGES/django.po b/venv/lib/python3.7/site-packages/django_extensions/locale/ro/LC_MESSAGES/django.po new file mode 100644 index 0000000..8f4180e --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/locale/ro/LC_MESSAGES/django.po @@ -0,0 +1,80 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: django-extensions\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-02-02 11:43+0100\n" +"PO-Revision-Date: 2011-02-02 10:38+0000\n" +"Last-Translator: Jannis \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ro\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " +"20)) ? 1 : 2)\n" + +#: admin/__init__.py:121 +msgid "and" +msgstr "și" + +#: admin/__init__.py:123 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"Folosește câmpul din stânga pentru a efectua căutări de %(model_name)s în " +"câmpurile %(field_list)s." + +#: db/models.py:15 +msgid "created" +msgstr "creat" + +#: db/models.py:16 +msgid "modified" +msgstr "modificat" + +#: db/models.py:26 +msgid "title" +msgstr "Titlu" + +#: db/models.py:27 +msgid "slug" +msgstr "Slug" + +#: db/models.py:28 +msgid "description" +msgstr "Descriere" + +#: db/models.py:50 +msgid "Inactive" +msgstr "Inactiv" + +#: db/models.py:51 +msgid "Active" +msgstr "Activ" + +#: db/models.py:53 +msgid "status" +msgstr "Stare" + +#: db/models.py:56 +msgid "keep empty for an immediate activation" +msgstr "A se lăsa gol pentru activare imediată" + +#: db/models.py:58 +msgid "keep empty for indefinite activation" +msgstr "A se lăsa gol pentru activare nelimitată" + +#: management/commands/show_urls.py:34 +#, python-format +msgid "%s does not appear to be a urlpattern object" +msgstr "%s nu pare să fie un obiect urlpattern" + +#: templates/django_extensions/widgets/foreignkey_searchinput.html:4 +msgid "Lookup" +msgstr "Căutare" diff --git a/venv/lib/python3.7/site-packages/django_extensions/locale/ru/LC_MESSAGES/django.mo b/venv/lib/python3.7/site-packages/django_extensions/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..cf0f7454fcbca125bc479125adaf90b7aab1a79f GIT binary patch literal 2009 zcma)6OK%%h6uv-9!IV;(9Rlef(I^&7m@%nT+_ z=YIk30sjV`0Nw(b?Oy<0;FrJ*@Fa{Vv2Y+M^cBeR841Lw?=6r`vvQsy6}oY2}DvUFS!DXGQ&FPiH+a>n)DgQRlcxXA2? z$g7q_q-<4xDw`fQ0(~gSu9?mlOkY#3j zGH;q#se&CTV=}b;$g@=tW@&J$P@s|g@BsA=4CjXm=kxvj;{y{DXF>H#Rl6jONokj} zRLGB9n95%OuTVJex!pln+UH~`tfq#Ch6na*w7Sg{-zVuK;X(z<73zJv;@Pf$hKjgh zkyN><$wA}vK97aX$j}(@i|D9d%F^kJu1bx0)zJ2g!5}P0S@J8%Yn1CbL(Ofj%RgzE zxtv9voy1%7^_*qVIWh@!yr0cw9v$`OdU%_7n7x)sSFbi*z%kSCvEY+Qr-Z(vx8fze zq1SX>H-!EyUetA=ztVg0N4f^YjB>otTI^k?X@4&bV^YU8+$C}s{nQnmw4e;}!i7xCYloA{YKm^A>pVEkxiX4V0q1rKzsf`*>OJ zBo)TDn{(MoX2aUKU>, 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: django-extensions\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-05-30 14:51-0500\n" +"PO-Revision-Date: 2011-02-02 10:42+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + +#: admin/__init__.py:142 +msgid "and" +msgstr "и" + +#: admin/__init__.py:144 +#, python-format +msgid "" +"Use the left field to do %(model_name)s lookups in the fields %(field_list)s." +msgstr "" +"Используйте левое поле, чтобы сделать поиск %(model_name)s в полях " +"%(field_list)s." + +#: admin/filter.py:24 admin/filter.py:53 +msgid "Yes" +msgstr "Да" + +#: admin/filter.py:25 admin/filter.py:54 +msgid "No" +msgstr "Нет" + +#: admin/filter.py:32 +msgid "All" +msgstr "Все" + +#: db/models.py:18 +msgid "created" +msgstr "создан" + +#: db/models.py:19 +msgid "modified" +msgstr "изменён" + +#: db/models.py:38 +msgid "title" +msgstr "заголовок" + +#: db/models.py:39 +msgid "description" +msgstr "описание" + +#: db/models.py:60 +msgid "slug" +msgstr "название-метка (Для URL)" + +#: db/models.py:121 mongodb/models.py:76 +msgid "Inactive" +msgstr "Неактивен" + +#: db/models.py:122 mongodb/models.py:77 +msgid "Active" +msgstr "Активен" + +#: db/models.py:124 +msgid "status" +msgstr "статус" + +#: db/models.py:125 mongodb/models.py:80 +msgid "keep empty for an immediate activation" +msgstr "оставьте пустым для немедленной активации" + +#: db/models.py:126 mongodb/models.py:81 +msgid "keep empty for indefinite activation" +msgstr "оставьте пустым для бессрочной активности" + +#: mongodb/fields/__init__.py:22 +#, python-format +msgid "String (up to %(max_length)s)" +msgstr "Строка (Не длиннее: %(max_length)s)" + +#: validators.py:14 +msgid "Control Characters like new lines or tabs are not allowed." +msgstr "" +"Управляющие символы, такие как символ новой строки и символ табуляции " +"недопустимы." + +#: validators.py:48 +#, fuzzy +#| msgid "Leading and Trailing whitespace is not allowed." +msgid "Leading and Trailing whitespaces are not allowed." +msgstr "Пробел в начале или в конце недопустим." + +#: validators.py:74 +msgid "Only a hex string is allowed." +msgstr "Допустимо использование только шестнадцатеричных строк." + +#: validators.py:75 +#, fuzzy, python-format +#| msgid "Invalid length must be %(length)d characters." +msgid "Invalid length. Must be %(length)d characters." +msgstr "Недопустимая длина, должно быть %(length)d символов." + +#: validators.py:76 +#, fuzzy, python-format +#| msgid "Ensure that there are more then %(min)s characters." +msgid "Ensure that there are more than %(min)s characters." +msgstr "Убедитесь, что длина строки больше %(min)s символов." + +#: validators.py:77 +#, fuzzy, python-format +#| msgid "Ensure that there are no more then %(max)s characters." +msgid "Ensure that there are no more than %(max)s characters." +msgstr "Убедитесь, что длина строки не больше %(max)s символов." + +#~ msgid "Lookup" +#~ msgstr "Поиск" diff --git a/venv/lib/python3.7/site-packages/django_extensions/logging/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/logging/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/logging/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/logging/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6da154e3ddec855d37fe4ecd79b8de9a85e85b51 GIT binary patch literal 196 zcmYL@u?oU47=%-B5TOs^VE@6vMMT8eMVv$0{>GR#3H{Sz`$j&6@8Ia_6NsCW$siuw zcgIb)Nz(}ny5C+r<}>1_B$Rb9jRH!xXVYYNWlfy__|$M9YzTBS^fY*T-mRZv*PVCdb*CJ6-D!`~IuzIlyvN^r-S&(OeX}PKdkV1 zfsCF5$p^p~Vz@#{x8nqZ>{QO&Oz+Fg?t`z!$LX}s~aXzeqqJ>_fv8gGIvnmG5+I$%8=z)rQh zp*qmCaJG2e)4dJo0fjB1fcm;GKe7;ZcN1!=`sVl@2YN;&SE{TF3E0cCe9Du(lNYB4>Cxfa!_$M4 zbbNSZH>U3K-G4QLkJ{XX2YM3}TxCiL69Rb4rOXO0?9fba z$}d@2aH$dsXX!kvuZ#=GxKO7dWt|InCbBR@m2*Cf43WH=7+>(b5v&c{#z=^*#P|!r zC*`FH0bZ-F5k;m8GYD87rSvx7q%Is_AZ2Y85ya~t2m ztG)kxg;D3|82$-O(>j~;G&NzG&KtI@ERNFj{W7b%6LB9xwe^0%zP36SSPw|rDN)?Y wLtoqm$prrtV1j8Tr%-!0N`KtGpZ4k(?rb-O^=atSE{kW@r?mf+Vu~a0Z+n6)sQ>@~ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/logging/filters.py b/venv/lib/python3.7/site-packages/django_extensions/logging/filters.py new file mode 100644 index 0000000..7356d70 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/logging/filters.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +import time +import logging +from hashlib import md5 + +# also see: https://djangosnippets.org/snippets/2242/ + + +class RateLimiterFilter(logging.Filter): + def filter(self, record): + from django.conf import settings + from django.core.cache import cache + + # Rate is specified as 1 messages logged per N seconds. (aka cache timeout) + rate = getattr(settings, 'RATE_LIMITER_FILTER_RATE', 10) + prefix = getattr(settings, 'RATE_LIMITER_FILTER_PREFIX', 'ratelimiterfilter') + + subject = record.getMessage() + cache_key = "%s:%s" % (prefix, md5(subject).hexdigest()) + cache_count_key = "%s:count" % cache_key + + result = cache.get_many([cache_key, cache_count_key]) + value = result.get(cache_key) + cntr = result.get(cache_count_key) + + if not cntr: + cntr = 1 + cache.set(cache_count_key, cntr, rate + 60) + + if value: + cache.incr(cache_count_key) + return False + + record.msg = "[%sx] %s" % (cntr, record.msg) + cache.set(cache_key, time.time(), rate) + return True diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b1166d651327b5a817d0eb46b9c8a5066ea0c1da GIT binary patch literal 199 zcmYL@F$%&!5Jfj&AwmvfVWzOK5fQPr5$k1>jB(v$cFAml$&EaPcd)ee1Y&39rVu~; z_dkD{*~IZg1l?~hIplM|Pf;lAU>*hJVlSrA?kehG{^R4|z*sYwy6?F6_9#CUQ zWaF)aRuv6Hi_}7?Q*fO>S(+ycVC`|{RAy9x4Eb46VI^KX5^GBgm7;K|kUU7KNqZ?1 S*FDC|%H~aptKpM(u=oNS#5sZh literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/base.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/base.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ccf23b0c18e3acb935b8e01dfbced1ed02a2058a GIT binary patch literal 1862 zcma)7O>g8x5bd@-ADJXtl-&aY3AF^0ccNe;aX^X!A`2lPMTr!GSiD;GI_?_Bi9cq$ z+fimnIFOb01Xr$b3!#pm$X!21-X3N#E8$&TP zfCN;Kz!EgDUy=b8mat!R1Lq}iNYKJ?PPJk{lRUl=E&KyPdJM-VQ{`clhDxzwz;3uO zeH3bz7O`To%$ZIyU?62771ITKHb?N8SEC&itWR3x8AGK48MUaGBydu;Y>rWk|I~$6w*6H5m}NA3#spbnj%e-Y~+4;J7|CXI;aVJ z1nH1{$lL=^dXl(1#WD^82J8qcm%>8@>0phmhBC&qS67RnHYDc&%^n#hNOtQig4(4w zLEOv*N(Q-sOmd?b%5Eyw;7gX|Oo7(;N_oT44S9CvOveRW}Qhl!qcq^1B^srxZ>h#r^Kq{{G&+yEa3@c$nc1l2k(- z=ZP!fd6`Jy0uIZV55iP|`}7t2>XI4s=CqYMNtK7|OeihMB(I=6I< z#1l@l%GHGDPWPPx)s8nLd@`fht5W)Zf(>Oc3}d`K82K|J(QGaz^jtm{)7my>M4LWg zT9;{T_wZ2%IE_{`xg^K*oSs`hQcAui`G!NZb<&f&lw8=9jNj7sv2$+g*3a!QeEj5Rm+X;rmwAg|mn!`Jkv;cztEq z?^G>S4nbBOID@FvP%T{FhpIiP3i_H(Q`u^yWE&Y{7jw)ds~mI3s!nsmDhj4=a$X-4 z&VMEUrv6t7%j%!V@kotzG2n+q4$(>Ce+ueE7eoIvj7#O8LVoI}$)P_S>7ycl-}}H< ziH3KFVRVAcO8K{Xjz8@=zUeu55#<7Md(X&P|8Y=@uF%)$>va6a&aIZ~HR<--RhRQT z%z*Q%$9YzWGBx%R=g-S9ZN79k7e&N*9im!pQj8!?@!fq4Sx{MNxy4Dh1 Hvby$v#zXA^ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/color.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/color.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f8c6ccfe8159b391d854cc692c7596d543a2957 GIT binary patch literal 1013 zcmY*X&1w`u5bmD;?4Jp0@Ck%DxN}hOB4Xl35RwfdC5}H8DN(SAX5pRbSP1x7#AHetiF(eRc`?iN?R>fbs&idIG=* zqXj8xN-642;goLbg6=Z!6G=VhvjC*eLKcAx*xDNsw|>D*5>w-kL?I+7EzMCAtJ$$uqyrZpyq4Bo&cL&BjJlHkC-u~clcgM6FnGLu0c1#2j ztHqwgM@>|TCP5P_u5+!W%`A3|Z}T>u6a~K_QDP194gmIEMF50Gv_;pc^cBkw}G@*Y6yO3vc0r7G>I zSzQaMRc2dk+Ez5|Nf%GI%6!UK4rE5IAs|t*jnF~pBJ>cD#hA(s)UT(sA^1M{(62TD zkl={+?6=;a6Htj~p#SM+Gmia{ki360h)vR+RdA*!g|b=N{@S literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/debug_cursor.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/debug_cursor.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..590500d4127579e26aa03249490c0366fd57c796 GIT binary patch literal 3427 zcmbtXPj4H?6`$FE++8jyN}?1gv128v-4JLgi2p^Rh;oOR|B3J z>V3mCBu@)-ebY5%Uk|Om?b;XxD#64cILMP+TPG&5p5Y_xIs|W_iv1mELX8Sei>)}~ z!6EPak>3d@a7-3(-itVqx&2%{HDROX0df)i~K+&faA=LmYPOP(ru z+L226@Li%46e=*I5)GWm{Z1KYt4y&f(P5{tjiMzDac$406oYgThUfZcC{jKZJw-~j zrc(bl{H2ttKUd`2n5?kHiW8-m>zN=`mAmqS*F`YaKudX|<*%8ROv5@lM#uPAIaZIg zWBu4T&b3YAkis*Q6poa!!L6P>&aER-Bs0$tnMsT!cchKY;ZH$(Da`ksv4ug$*gm|L zSZnBu@;IMZNq!mi3W=TMZ=)A@|JF7F{jY=m;-38iQ}^7@v6WeonB4Mgg2oP?>6OUr zo(`+NlJT1hXZv$w2cyIROA27gJSl@EWw4|GmJ~tqn;?0fm)nYz{>Q0wXCmDJX@5zI ziR0Oc1^sUim!z$wah_1Yf340Q;@83ybvQMFJU+@upTSn8p%Dyf3 zLTWBFMhiEYx3PJ@(e$=HdgwJbKW^MzZPvSgR}mV`!yIroRyVimUcIsU;luh`6V4r> z?mvN66t_f!ZbX8Jdw$sML;-P2oE}6ip9db}RAlyO`J$A2k2fE!HoaeOuWqhyNd+69 ztv{+anp@`zGKBPkEjIkuy=t3NR+h;`FBO`C`5f`xsdM= z3uE-FejM!uLvP^o)~?q&pe&{&*g5DtrTzfwvU)p=TYktssBVB~{G)?_4!5(ZN8Q72 z^n28TsL4m5Oaa!CZa;W`xvr05`3$WE%p1Ln?$KI7hmO}u>(?bOIlB{kYH?fcxdcDtQj$h=+d8X>Hu z%$@B7+>?E8XXr(KKS*^*PM@V(FYZRE#i`#4cKp^}>SR(NQ(;swQjG;+o94j0)EM~G z?=#neISLTn58PsA3wZCzagO>=JqSz1OpP$^0HCLH1Cbbl>4{VkK}gNPu+xVMVK6)C zd6`}gJC-l=yuGJB?J&3-_Cv6O1?l2>Z?bW^;=Imyf=U-z`ew3q~}MS7-G+Z zh=C8Rmfcvwjhd{8Np(~QLn^M?_n@&`KoB;uf=h~n%UHvXqTwPm4R|(oR8w+IJX-%h zE3G<73%FFJ>lH0EJ$crim)f4!kI6w8K;Q8oar{tZf#*q6v-Kuj0AuN*Ag>9sB*?NL zuM6^qAlC#Dk)_vxq>EQq{ZC+y!Ig_lOy7dne?gJJ$~(}Q17r$C;;TRz-T7fb$m-=H z=rk%SeG}x;8-lC|BCUN%q}{JcyDx9Q4;#)6e;fMnsgZ{d6v!Bnx2&RkC(um7Jxpn$ zz+c(72e0m1%y@?e;+he)lbN|DPl!?##Wd7aXjx-;iBTAe`5{FE^*WR}`5`|fNrp#5&-hxa5*L7``$H+R`R*UGA` zN_OZwV1PRZa$13RvCLAde%J~I5>AY4d7AsAz9~Ke-Rsl+RRL;2L|Ao@#R6c1-UOLc z6P{Vk;UJJ6Rc2gkid0z<$XpjS;o6V`?Ewwi-9z`r)xZPBwf%#TGnw%2ym#3xDl#f_ zXkMV!|9Iriyv#INw-Ds1&7Md#_qzA;M6Zx9PVk4;vMh%i-;o7hxrEpl85*3FbsE z8_^nQs}!jCaG~&r1*PH;#6JZ0sKZ#SNQ2+n{ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/email_notifications.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/email_notifications.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..897438f1dd80c307fd18d55ab141422a19c606e2 GIT binary patch literal 4809 zcmaJ_O>Y~=8Qw2`iqw}s5(7m$Xe-M!WYS3irx4O0vMn_#Vmgo%*jW@^Eq8{}O3Ph( zW+|Ht)k9?GU5=T7)ydg8)whCtr(hR! z?avy`(fn(T=2_vww2M^V*J_0~;HEWedQucDj{WdRpkER!q)x~61AHtzbOn19bvkZH zJxM)&%uz>th7QxD6t+Qi+oT3HUu(AYoz~W=MRTuf)cbcWy zMaZ$3e7G(5Yeuo(_B}WDqj0pRtK~JVOz>=xDN%^%wYZFVt=%VVVNHUphlGP>x$E(C~W&jJ+6ibc+d!%nHFOE$=2?dPV?!(?#}L`t%KdC&3!_BFCOW8 zmH~U^%1t&mQ)5V*&RhQ{@~zrk&dXb?#_Dld4G0cZO+m# za$MT+L%DLt4FsD{1Gn{9%k@s*OEw8ACtznR0P+1f{Mv{bNB98*4y0z(zB76|pIwz% z#)U^8GyXpF)a$8FN!82eEmqUh=c#|Z?L6JUMPSm+Ornu(H&cdbyRAZhG&9*zT6TsG z)G4W)nb1vaJE2bLd^n?R>cFaO@ zz>|Vv#u?99R+&SLxxJHBMk%=|=O(kdn9fqE-@t7)rxF}N zew045K|Y!pc7vC0e@d(wzZ%K)mCM}@iy0?fByprR2tiNW@F-eO^SG)%cWSAsJ!4dC z9%WCB71UUfmeMh*q0E$u1 zrnE7WrNv-vAH`*)r)kXy(vJ8zi`Hval6O_vNeYy;-ChtU7G(nMF$=nbmGSoMmB&Bi75Jj#@}r*2;x!|&1Pj_pzUy+q_`fv11m*nlZR2Zv ziN+}(^u-{K+D;1@+&lFfkC`})qi*BOJ?e?Z84J%Ef!}I$`|)uU{-OR!L-;Yf*F|PQ zp%9JKG!E({3kB+;XiQ2-V~)D&-F{M?mQZ{wEe2GhX?k8a)L${{4Q_A0qx{!rn9TTr z1R(Mizd}RxOW6HNA8L*s8yDK8DZc=L4A|Wq{PF1-?nFfm3+ zl2_z;JuVbR%FtQ1=b^+Y07)=10p<$Y^|#_n5@aWngzy8EYSnop7*r($qg!dRed))? z%0(s_Q^GS8yfEX#8FzgF00?lEi856t7GR^D1BC6$D3c@Aj4F4tmg6!mk^+0hyk5+b z()Kvglfn^;-8kmS2U5BegUlqRnmKVekrc+-()kBqIpuS=@Trn!1s$zq=&SmoeqD#} zrFF15g>E0EIJiENr@8Y+`kkk|6`e)N0Iy;P??T*B{j|g%NGCkeFO8w@Ygfj(^-O!Q z2`4n+gde9)=xgWJHyC}cg_i6O4e__3b!o_4eT9B(!6kE-d1_th7doOBmlQRR%npt@ z%oZ+-v~Z=<;w|kwujWd$Jj~yeI~Ilp|51(Mf&qR%4(f5~vV5ie)jThrm(I(ydbto+ zE~~@x6|%$m!mvOWhYL5gPqg#GGwk;F^7C}RC7fgt94qmX;f|i(>M%Df3@gKw&oz4e%Ahx7%~IE~n}eS+ zkD4k1Gv#I~ruLYtEPo&qB>CGIU9v%`G zp+-(wUq%!I5+z+8ogtM9U=UZ}f(1UA*rTF1RsEax>I_eXK)Lj&!P@pKUtT&lMi_^z zE6P4e5yU#_M3mK&!U)a{)*dT_fCw9xp*aP)p6K;A|HG4563+~NzsKZFN}eutXnCyz zG#e#+0QxntZdU-qvXI^M+ZFJO*?nJ(_Vi7EObDIy~|eh4ga4Z9?z?3_snV;whk;+DPoczb8->n{(SoxP_| z93@C%1wN2VUa6bf`7|GLS$t}XD(%=yGp6+^|4{9KV%v&P-{zvZY)GoSURG3PeQKxnqgbirD$87s*GjyBAN~;}97*xh)YU$dj++Xj7XfAPXZ|1E|7aNi literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/jobs.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/jobs.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..223a0094ab045ffdb6cdbfa6463d5400cf0b6b1f GIT binary patch literal 5844 zcmb_gO>7&-72cWs;c`h)w5-TKv7L=$#by#qX;L(8VF*rQyQ$+aN$teWA`VM)MiND8 zNzJTeky!Q+xj+vM&=x)PRw=jk*xuWodn$U|Yfs6oSEEJxy;8TttcsQoGpID=weg2)y;a)d1$*vu6i z3U;%?8%-@C)$sIsEF{b&MTnh;Lh6=k8*|OopD+`xZp=jcOW?~}>{IL!tMU4LCt%m(^4EwV$8@M?I!@B{y(lf*dQdQLoS%t~m-E*2Cnk9>yn^ zw=q;tqp(QjCi5 zA|_oNo}j6i)6Qo!sgCvMU=s?9$VPuwc^%Q+et;9hJ^~ms;0$vGqtqoTD1@UTCg+kw z1yo7jnT^U}iv(kALDxOZ8^`}?=5r2XR1p0qfduM0`flubDIJye;4}mr46Y{D3ftzU z1SGDwf}KM2lHcY%sR7HB`dFu+7U+N5OKtLC*k>B{DF7_)|e&KJqqyoqFi``KU1HCqe3_1%R%<`QxON`ex3ZQ4y`h zMV>kxPyHz=3ok9^9*|5>4`$e-0I`*&!AeEA9baW@pM%GjM5k8AR$qdKPvz@evDQAn z3)$Cx2H7V&!7rG?&5nK_q3s@C^u>rXLaM@WISBFmNG9tl4x6E9x6GwR4Z>AKR6AY@ zdyD1_OGcPM^(1K?c?9lrrV4cHH z0`nYTUVxlHL02}v3PO;NNx4W53P_95&9SRvd;7U9Dd zuARsb1=H#sYV}QP!L+*DUXC_qd@*&@Uxg2Ju+^`C00jZ$5WxxSH4AM)>Wk7$Ugzo$ zX&{2MD9SU|ZoinIaS2O zLvMEW@@#wmV+$b(xtyk#Vi^ausS$%gaF0I))qV)*TZ0>6VQxT(R(~D?$DooidB_F}FMiqx<0jGN^Al$5xLbi+)@pnwy!o(d@2Eop10MO{?T}@}{V$ zmwOKz^!+3%o9cKwQOQutvMHpBJh&NhU*xXPQ97!O2Q@Ulw4u91TizpRu`!W3U3_rL z4?ORKo%$x&4fcKLHyEP{kSxGz6)(V+&#)PQFlzYaZB^h8ew^TUx7A}I;8=ZvxnxkX zY5hjct>3tF<4*1AJW;)cPF16V+&A-*0cCSVz7m!4Z-sN%nl|Z4-J*eX{#Q4tps#Y~ zvynPZHTqtn=&OaIuLp|m@QUuyif*&!Aed*e*NMDN1!V<;nMTM1&P=GO%ni@Kk{<*Y hNIrAPqK%py!yVgqs!qkPqTK)a6Mi9>!0(b@`VZ(S(7gZv literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/modelviz.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/modelviz.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4da9d1b7ccdeba8f20e0b0458e0fc7d02b92ef8d GIT binary patch literal 13049 zcmb7LTWllOd7c>#$st8uR;$%syk3vjtMzidOWBU&q^_*2ZF%k3vFyZ~*kR%@Bc72& ziX3v!jCLiOiruW6rfrhCFAb0ysPx#kJ{3h#v<6!AsVL9_MS*Fb+P(xR3KZ=_;irDz zKSPS*%63a(&Yatv%YXm>bM*Y=WYNIy@BiXIYwIr<#=o*K_)Q{n15fxbNR&}El&P$i zSvBQtRV{gEsu{d9ExVnqW=;07Te)_=nr}N*r(LKP+Qn*7>a(qhcBxvDe6BUwo~ll@ zr>oQLnd*$xZF=er_{VUtk8LS`7 zQje%hc)QAa(mzDC!zUH7>l>I99B`+|4J zSID_bUQ%7tg!y9Umf!BOcbsc=JmqWjF91AszZOPPXnT6A7JBPGS{$z)HSVBy zFY`p@i8%MhZnTN<%-*8_pL@p(+}Ar{bjSAtcj->0ljd)1w7o{FQtz~vd#~RQt<5Ov zKC`$u1Qz-&F25Q1>t4`tU#YmyMUkf!z?ydSk}`q1xZJzaY5-52?P2rXyLT%c2_!U+PjOj2VTABw}Qsjjiz@u=!Er3w6)xO`nAT^mfvz;+YaiR;0Dlj5ONQM zb_l!(JpE|hYlT~W2(qfEEkN@z0=pX>H0xj(7vZyjld59@@}gU0rnYBZ;Z_s&)&b;MNU73 z#4v6A&ET0c=S}@EYU->W{4&Vgz!QFq#5bTDjYKa(t7KG0*?8OPag|ef=$))`Q~@
    + + */ +/* + * Queued Ajax requests. + * A new Ajax request won't be started until the previous queued + * request has finished. + */ + +/* + * Synced Ajax requests. + * The Ajax request will happen as soon as you call this method, but + * the callbacks (success/error/complete) won't fire until all previous + * synced requests have been completed. + */ + + +(function(jQuery) { + + var ajax = jQuery.ajax; + + var pendingRequests = {}; + + var synced = []; + var syncedData = []; + + jQuery.ajax = function(settings) { + // create settings for compatibility with ajaxSetup + settings = jQuery.extend(settings, jQuery.extend({}, jQuery.ajaxSettings, settings)); + + var port = settings.port; + + switch(settings.mode) { + case "abort": + if ( pendingRequests[port] ) { + pendingRequests[port].abort(); + } + return pendingRequests[port] = ajax.apply(this, arguments); + case "queue": + var _old = settings.complete; + settings.complete = function(){ + if ( _old ) + _old.apply( this, arguments ); + jQuery([ajax]).dequeue("ajax" + port );; + }; + + jQuery([ ajax ]).queue("ajax" + port, function(){ + ajax( settings ); + }); + return; + case "sync": + var pos = synced.length; + + synced[ pos ] = { + error: settings.error, + success: settings.success, + complete: settings.complete, + done: false + }; + + syncedData[ pos ] = { + error: [], + success: [], + complete: [] + }; + + settings.error = function(){ syncedData[ pos ].error = arguments; }; + settings.success = function(){ syncedData[ pos ].success = arguments; }; + settings.complete = function(){ + syncedData[ pos ].complete = arguments; + synced[ pos ].done = true; + + if ( pos == 0 || !synced[ pos-1 ] ) + for ( var i = pos; i < synced.length && synced[i].done; i++ ) { + if ( synced[i].error ) synced[i].error.apply( jQuery, syncedData[i].error ); + if ( synced[i].success ) synced[i].success.apply( jQuery, syncedData[i].success ); + if ( synced[i].complete ) synced[i].complete.apply( jQuery, syncedData[i].complete ); + + synced[i] = null; + syncedData[i] = null; + } + }; + } + return ajax.apply(this, arguments); + }; + +})((typeof window.jQuery == 'undefined' && typeof window.django != 'undefined') + ? django.jQuery + : jQuery +); diff --git a/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.autocomplete.js b/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.autocomplete.js new file mode 100644 index 0000000..77c1db6 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.autocomplete.js @@ -0,0 +1,1152 @@ +/** + * @fileOverview jquery-autocomplete, the jQuery Autocompleter + * @author Dylan Verheul + * @version 2.4.4 + * @requires jQuery 1.6+ + * @license MIT | GPL | Apache 2.0, see LICENSE.txt + * @see https://github.com/dyve/jquery-autocomplete + */ +(function($) { + "use strict"; + + /** + * jQuery autocomplete plugin + * @param {object|string} options + * @returns (object} jQuery object + */ + $.fn.autocomplete = function(options) { + var url; + if (arguments.length > 1) { + url = options; + options = arguments[1]; + options.url = url; + } else if (typeof options === 'string') { + url = options; + options = { url: url }; + } + var opts = $.extend({}, $.fn.autocomplete.defaults, options); + return this.each(function() { + var $this = $(this); + $this.data('autocompleter', new $.Autocompleter( + $this, + $.meta ? $.extend({}, opts, $this.data()) : opts + )); + }); + }; + + /** + * Store default options + * @type {object} + */ + $.fn.autocomplete.defaults = { + inputClass: 'acInput', + loadingClass: 'acLoading', + resultsClass: 'acResults', + selectClass: 'acSelect', + queryParamName: 'q', + extraParams: {}, + remoteDataType: false, + lineSeparator: '\n', + cellSeparator: '|', + minChars: 2, + maxItemsToShow: 10, + delay: 400, + useCache: true, + maxCacheLength: 10, + matchSubset: true, + matchCase: false, + matchInside: true, + mustMatch: false, + selectFirst: false, + selectOnly: false, + showResult: null, + preventDefaultReturn: 1, + preventDefaultTab: 0, + autoFill: false, + filterResults: true, + filter: true, + sortResults: true, + sortFunction: null, + onItemSelect: null, + onNoMatch: null, + onFinish: null, + matchStringConverter: null, + beforeUseConverter: null, + autoWidth: 'min-width', + useDelimiter: false, + delimiterChar: ',', + delimiterKeyCode: 188, + processData: null, + onError: null, + enabled: true + }; + + /** + * Sanitize result + * @param {Object} result + * @returns {Object} object with members value (String) and data (Object) + * @private + */ + var sanitizeResult = function(result) { + var value, data; + var type = typeof result; + if (type === 'string') { + value = result; + data = {}; + } else if ($.isArray(result)) { + value = result[0]; + data = result.slice(1); + } else if (type === 'object') { + value = result.value; + data = result.data; + } + value = String(value); + if (typeof data !== 'object') { + data = {}; + } + return { + value: value, + data: data + }; + }; + + /** + * Sanitize integer + * @param {mixed} value + * @param {Object} options + * @returns {Number} integer + * @private + */ + var sanitizeInteger = function(value, stdValue, options) { + var num = parseInt(value, 10); + options = options || {}; + if (isNaN(num) || (options.min && num < options.min)) { + num = stdValue; + } + return num; + }; + + /** + * Create partial url for a name/value pair + */ + var makeUrlParam = function(name, value) { + return [name, encodeURIComponent(value)].join('='); + }; + + /** + * Build an url + * @param {string} url Base url + * @param {object} [params] Dictionary of parameters + */ + var makeUrl = function(url, params) { + var urlAppend = []; + $.each(params, function(index, value) { + urlAppend.push(makeUrlParam(index, value)); + }); + if (urlAppend.length) { + url += url.indexOf('?') === -1 ? '?' : '&'; + url += urlAppend.join('&'); + } + return url; + }; + + /** + * Default sort filter + * @param {object} a + * @param {object} b + * @param {boolean} matchCase + * @returns {number} + */ + var sortValueAlpha = function(a, b, matchCase) { + a = String(a.value); + b = String(b.value); + if (!matchCase) { + a = a.toLowerCase(); + b = b.toLowerCase(); + } + if (a > b) { + return 1; + } + if (a < b) { + return -1; + } + return 0; + }; + + /** + * Parse data received in text format + * @param {string} text Plain text input + * @param {string} lineSeparator String that separates lines + * @param {string} cellSeparator String that separates cells + * @returns {array} Array of autocomplete data objects + */ + var plainTextParser = function(text, lineSeparator, cellSeparator) { + var results = []; + var i, j, data, line, value, lines; + // Be nice, fix linebreaks before splitting on lineSeparator + lines = String(text).replace('\r\n', '\n').split(lineSeparator); + for (i = 0; i < lines.length; i++) { + line = lines[i].split(cellSeparator); + data = []; + for (j = 0; j < line.length; j++) { + data.push(decodeURIComponent(line[j])); + } + value = data.shift(); + results.push({ value: value, data: data }); + } + return results; + }; + + /** + * Autocompleter class + * @param {object} $elem jQuery object with one input tag + * @param {object} options Settings + * @constructor + */ + $.Autocompleter = function($elem, options) { + + /** + * Assert parameters + */ + if (!$elem || !($elem instanceof $) || $elem.length !== 1 || $elem.get(0).tagName.toUpperCase() !== 'INPUT') { + throw new Error('Invalid parameter for jquery.Autocompleter, jQuery object with one element with INPUT tag expected.'); + } + + /** + * @constant Link to this instance + * @type object + * @private + */ + var self = this; + + /** + * @property {object} Options for this instance + * @public + */ + this.options = options; + + /** + * @property object Cached data for this instance + * @private + */ + this.cacheData_ = {}; + + /** + * @property {number} Number of cached data items + * @private + */ + this.cacheLength_ = 0; + + /** + * @property {string} Class name to mark selected item + * @private + */ + this.selectClass_ = 'jquery-autocomplete-selected-item'; + + /** + * @property {number} Handler to activation timeout + * @private + */ + this.keyTimeout_ = null; + + /** + * @property {number} Handler to finish timeout + * @private + */ + this.finishTimeout_ = null; + + /** + * @property {number} Last key pressed in the input field (store for behavior) + * @private + */ + this.lastKeyPressed_ = null; + + /** + * @property {string} Last value processed by the autocompleter + * @private + */ + this.lastProcessedValue_ = null; + + /** + * @property {string} Last value selected by the user + * @private + */ + this.lastSelectedValue_ = null; + + /** + * @property {boolean} Is this autocompleter active (showing results)? + * @see showResults + * @private + */ + this.active_ = false; + + /** + * @property {boolean} Is this autocompleter allowed to finish on blur? + * @private + */ + this.finishOnBlur_ = true; + + /** + * Sanitize options + */ + this.options.minChars = sanitizeInteger(this.options.minChars, $.fn.autocomplete.defaults.minChars, { min: 0 }); + this.options.maxItemsToShow = sanitizeInteger(this.options.maxItemsToShow, $.fn.autocomplete.defaults.maxItemsToShow, { min: 0 }); + this.options.maxCacheLength = sanitizeInteger(this.options.maxCacheLength, $.fn.autocomplete.defaults.maxCacheLength, { min: 1 }); + this.options.delay = sanitizeInteger(this.options.delay, $.fn.autocomplete.defaults.delay, { min: 0 }); + if (this.options.preventDefaultReturn != 2) { + this.options.preventDefaultReturn = this.options.preventDefaultReturn ? 1 : 0; + } + if (this.options.preventDefaultTab != 2) { + this.options.preventDefaultTab = this.options.preventDefaultTab ? 1 : 0; + } + + /** + * Init DOM elements repository + */ + this.dom = {}; + + /** + * Store the input element we're attached to in the repository + */ + this.dom.$elem = $elem; + + /** + * Switch off the native autocomplete and add the input class + */ + this.dom.$elem.attr('autocomplete', 'off').addClass(this.options.inputClass); + + /** + * Create DOM element to hold results, and force absolute position + */ + this.dom.$results = $('
    ').hide().addClass(this.options.resultsClass).css({ + position: 'absolute' + }); + $('body').append(this.dom.$results); + + /** + * Attach keyboard monitoring to $elem + */ + $elem.keydown(function(e) { + self.lastKeyPressed_ = e.keyCode; + switch(self.lastKeyPressed_) { + + case self.options.delimiterKeyCode: // comma = 188 + if (self.options.useDelimiter && self.active_) { + self.selectCurrent(); + } + break; + + // ignore navigational & special keys + case 35: // end + case 36: // home + case 16: // shift + case 17: // ctrl + case 18: // alt + case 37: // left + case 39: // right + break; + + case 38: // up + e.preventDefault(); + if (self.active_) { + self.focusPrev(); + } else { + self.activate(); + } + return false; + + case 40: // down + e.preventDefault(); + if (self.active_) { + self.focusNext(); + } else { + self.activate(); + } + return false; + + case 9: // tab + if (self.active_) { + self.selectCurrent(); + if (self.options.preventDefaultTab) { + e.preventDefault(); + return false; + } + } + if (self.options.preventDefaultTab === 2) { + e.preventDefault(); + return false; + } + break; + + case 13: // return + if (self.active_) { + self.selectCurrent(); + if (self.options.preventDefaultReturn) { + e.preventDefault(); + return false; + } + } + if (self.options.preventDefaultReturn === 2) { + e.preventDefault(); + return false; + } + break; + + case 27: // escape + if (self.active_) { + e.preventDefault(); + self.deactivate(true); + return false; + } + break; + + default: + self.activate(); + + } + }); + + /** + * Attach paste event listener because paste may occur much later then keydown or even without a keydown at all + */ + $elem.on('paste', function() { + self.activate(); + }); + + /** + * Finish on blur event + * Use a timeout because instant blur gives race conditions + */ + var onBlurFunction = function() { + self.deactivate(true); + } + $elem.blur(function() { + if (self.finishOnBlur_) { + self.finishTimeout_ = setTimeout(onBlurFunction, 200); + } + }); + /** + * Catch a race condition on form submit + */ + $elem.parents('form').on('submit', onBlurFunction); + + }; + + /** + * Position output DOM elements + * @private + */ + $.Autocompleter.prototype.position = function() { + var offset = this.dom.$elem.offset(); + var height = this.dom.$results.outerHeight(); + var totalHeight = $(window).outerHeight(); + var inputBottom = offset.top + this.dom.$elem.outerHeight(); + var bottomIfDown = inputBottom + height; + // Set autocomplete results at the bottom of input + var position = {top: inputBottom, left: offset.left}; + if (bottomIfDown > totalHeight) { + // Try to set autocomplete results at the top of input + var topIfUp = offset.top - height; + if (topIfUp >= 0) { + position.top = topIfUp; + } + } + this.dom.$results.css(position); + }; + + /** + * Read from cache + * @private + */ + $.Autocompleter.prototype.cacheRead = function(filter) { + var filterLength, searchLength, search, maxPos, pos; + if (this.options.useCache) { + filter = String(filter); + filterLength = filter.length; + if (this.options.matchSubset) { + searchLength = 1; + } else { + searchLength = filterLength; + } + while (searchLength <= filterLength) { + if (this.options.matchInside) { + maxPos = filterLength - searchLength; + } else { + maxPos = 0; + } + pos = 0; + while (pos <= maxPos) { + search = filter.substr(0, searchLength); + if (this.cacheData_[search] !== undefined) { + return this.cacheData_[search]; + } + pos++; + } + searchLength++; + } + } + return false; + }; + + /** + * Write to cache + * @private + */ + $.Autocompleter.prototype.cacheWrite = function(filter, data) { + if (this.options.useCache) { + if (this.cacheLength_ >= this.options.maxCacheLength) { + this.cacheFlush(); + } + filter = String(filter); + if (this.cacheData_[filter] !== undefined) { + this.cacheLength_++; + } + this.cacheData_[filter] = data; + return this.cacheData_[filter]; + } + return false; + }; + + /** + * Flush cache + * @public + */ + $.Autocompleter.prototype.cacheFlush = function() { + this.cacheData_ = {}; + this.cacheLength_ = 0; + }; + + /** + * Call hook + * Note that all called hooks are passed the autocompleter object + * @param {string} hook + * @param data + * @returns Result of called hook, false if hook is undefined + */ + $.Autocompleter.prototype.callHook = function(hook, data) { + var f = this.options[hook]; + if (f && $.isFunction(f)) { + return f(data, this); + } + return false; + }; + + /** + * Set timeout to activate autocompleter + */ + $.Autocompleter.prototype.activate = function() { + if (!this.options.enabled) return; + var self = this; + if (this.keyTimeout_) { + clearTimeout(this.keyTimeout_); + } + this.keyTimeout_ = setTimeout(function() { + self.activateNow(); + }, this.options.delay); + }; + + /** + * Activate autocompleter immediately + */ + $.Autocompleter.prototype.activateNow = function() { + var value = this.beforeUseConverter(this.dom.$elem.val()); + if (value !== this.lastProcessedValue_ && value !== this.lastSelectedValue_) { + this.fetchData(value); + } + }; + + /** + * Get autocomplete data for a given value + * @param {string} value Value to base autocompletion on + * @private + */ + $.Autocompleter.prototype.fetchData = function(value) { + var self = this; + var processResults = function(results, filter) { + if (self.options.processData) { + results = self.options.processData(results); + } + self.showResults(self.filterResults(results, filter), filter); + }; + this.lastProcessedValue_ = value; + if (value.length < this.options.minChars) { + processResults([], value); + } else if (this.options.data) { + processResults(this.options.data, value); + } else { + this.fetchRemoteData(value, function(remoteData) { + processResults(remoteData, value); + }); + } + }; + + /** + * Get remote autocomplete data for a given value + * @param {string} filter The filter to base remote data on + * @param {function} callback The function to call after data retrieval + * @private + */ + $.Autocompleter.prototype.fetchRemoteData = function(filter, callback) { + var data = this.cacheRead(filter); + if (data) { + callback(data); + } else { + var self = this; + var dataType = self.options.remoteDataType === 'json' ? 'json' : 'text'; + var ajaxCallback = function(data) { + var parsed = false; + if (data !== false) { + parsed = self.parseRemoteData(data); + self.cacheWrite(filter, parsed); + } + self.dom.$elem.removeClass(self.options.loadingClass); + callback(parsed); + }; + this.dom.$elem.addClass(this.options.loadingClass); + $.ajax({ + url: this.makeUrl(filter), + success: ajaxCallback, + error: function(jqXHR, textStatus, errorThrown) { + if($.isFunction(self.options.onError)) { + self.options.onError(jqXHR, textStatus, errorThrown); + } else { + ajaxCallback(false); + } + }, + dataType: dataType + }); + } + }; + + /** + * Create or update an extra parameter for the remote request + * @param {string} name Parameter name + * @param {string} value Parameter value + * @public + */ + $.Autocompleter.prototype.setExtraParam = function(name, value) { + var index = $.trim(String(name)); + if (index) { + if (!this.options.extraParams) { + this.options.extraParams = {}; + } + if (this.options.extraParams[index] !== value) { + this.options.extraParams[index] = value; + this.cacheFlush(); + } + } + + return this; + }; + + /** + * Build the url for a remote request + * If options.queryParamName === false, append query to url instead of using a GET parameter + * @param {string} param The value parameter to pass to the backend + * @returns {string} The finished url with parameters + */ + $.Autocompleter.prototype.makeUrl = function(param) { + var self = this; + var url = this.options.url; + var params = $.extend({}, this.options.extraParams); + + if (this.options.queryParamName === false) { + url += encodeURIComponent(param); + } else { + params[this.options.queryParamName] = param; + } + + return makeUrl(url, params); + }; + + /** + * Parse data received from server + * @param remoteData Data received from remote server + * @returns {array} Parsed data + */ + $.Autocompleter.prototype.parseRemoteData = function(remoteData) { + var remoteDataType; + var data = remoteData; + if (this.options.remoteDataType === 'json') { + remoteDataType = typeof(remoteData); + switch (remoteDataType) { + case 'object': + data = remoteData; + break; + case 'string': + data = $.parseJSON(remoteData); + break; + default: + throw new Error("Unexpected remote data type: " + remoteDataType); + } + return data; + } + return plainTextParser(data, this.options.lineSeparator, this.options.cellSeparator); + }; + + /** + * Default filter for results + * @param {Object} result + * @param {String} filter + * @returns {boolean} Include this result + * @private + */ + $.Autocompleter.prototype.defaultFilter = function(result, filter) { + if (!result.value) { + return false; + } + if (this.options.filterResults) { + var pattern = this.matchStringConverter(filter); + var testValue = this.matchStringConverter(result.value); + if (!this.options.matchCase) { + pattern = pattern.toLowerCase(); + testValue = testValue.toLowerCase(); + } + var patternIndex = testValue.indexOf(pattern); + if (this.options.matchInside) { + return patternIndex > -1; + } else { + return patternIndex === 0; + } + } + return true; + }; + + /** + * Filter result + * @param {Object} result + * @param {String} filter + * @returns {boolean} Include this result + * @private + */ + $.Autocompleter.prototype.filterResult = function(result, filter) { + // No filter + if (this.options.filter === false) { + return true; + } + // Custom filter + if ($.isFunction(this.options.filter)) { + return this.options.filter(result, filter); + } + // Default filter + return this.defaultFilter(result, filter); + }; + + /** + * Filter results + * @param results + * @param filter + */ + $.Autocompleter.prototype.filterResults = function(results, filter) { + var filtered = []; + var i, result; + + for (i = 0; i < results.length; i++) { + result = sanitizeResult(results[i]); + if (this.filterResult(result, filter)) { + filtered.push(result); + } + } + if (this.options.sortResults) { + filtered = this.sortResults(filtered, filter); + } + if (this.options.maxItemsToShow > 0 && this.options.maxItemsToShow < filtered.length) { + filtered.length = this.options.maxItemsToShow; + } + return filtered; + }; + + /** + * Sort results + * @param results + * @param filter + */ + $.Autocompleter.prototype.sortResults = function(results, filter) { + var self = this; + var sortFunction = this.options.sortFunction; + if (!$.isFunction(sortFunction)) { + sortFunction = function(a, b, f) { + return sortValueAlpha(a, b, self.options.matchCase); + }; + } + results.sort(function(a, b) { + return sortFunction(a, b, filter, self.options); + }); + return results; + }; + + /** + * Convert string before matching + * @param s + * @param a + * @param b + */ + $.Autocompleter.prototype.matchStringConverter = function(s, a, b) { + var converter = this.options.matchStringConverter; + if ($.isFunction(converter)) { + s = converter(s, a, b); + } + return s; + }; + + /** + * Convert string before use + * @param {String} s + */ + $.Autocompleter.prototype.beforeUseConverter = function(s) { + s = this.getValue(s); + var converter = this.options.beforeUseConverter; + if ($.isFunction(converter)) { + s = converter(s); + } + return s; + }; + + /** + * Enable finish on blur event + */ + $.Autocompleter.prototype.enableFinishOnBlur = function() { + this.finishOnBlur_ = true; + }; + + /** + * Disable finish on blur event + */ + $.Autocompleter.prototype.disableFinishOnBlur = function() { + this.finishOnBlur_ = false; + }; + + /** + * Create a results item (LI element) from a result + * @param result + */ + $.Autocompleter.prototype.createItemFromResult = function(result) { + var self = this; + var $li = $('
  • '); + $li.html(this.showResult(result.value, result.data)); + $li.data({value: result.value, data: result.data}) + .click(function() { + self.selectItem($li); + }) + .mousedown(self.disableFinishOnBlur) + .mouseup(self.enableFinishOnBlur) + ; + return $li; + }; + + /** + * Get all items from the results list + * @param result + */ + $.Autocompleter.prototype.getItems = function() { + return $('>ul>li', this.dom.$results); + }; + + /** + * Show all results + * @param results + * @param filter + */ + $.Autocompleter.prototype.showResults = function(results, filter) { + var numResults = results.length; + var self = this; + var $ul = $('
      '); + var i, result, $li, autoWidth, first = false, $first = false; + + if (numResults) { + for (i = 0; i < numResults; i++) { + result = results[i]; + $li = this.createItemFromResult(result); + $ul.append($li); + if (first === false) { + first = String(result.value); + $first = $li; + $li.addClass(this.options.firstItemClass); + } + if (i === numResults - 1) { + $li.addClass(this.options.lastItemClass); + } + } + + this.dom.$results.html($ul).show(); + + // Always recalculate position since window size or + // input element location may have changed. + this.position(); + if (this.options.autoWidth) { + autoWidth = this.dom.$elem.outerWidth() - this.dom.$results.outerWidth() + this.dom.$results.width(); + this.dom.$results.css(this.options.autoWidth, autoWidth); + } + this.getItems().hover( + function() { self.focusItem(this); }, + function() { /* void */ } + ); + if (this.autoFill(first, filter) || this.options.selectFirst || (this.options.selectOnly && numResults === 1)) { + this.focusItem($first); + } + this.active_ = true; + } else { + this.hideResults(); + this.active_ = false; + } + }; + + $.Autocompleter.prototype.showResult = function(value, data) { + if ($.isFunction(this.options.showResult)) { + return this.options.showResult(value, data); + } else { + return $('

      ').text(value).html(); + } + }; + + $.Autocompleter.prototype.autoFill = function(value, filter) { + var lcValue, lcFilter, valueLength, filterLength; + if (this.options.autoFill && this.lastKeyPressed_ !== 8) { + lcValue = String(value).toLowerCase(); + lcFilter = String(filter).toLowerCase(); + valueLength = value.length; + filterLength = filter.length; + if (lcValue.substr(0, filterLength) === lcFilter) { + var d = this.getDelimiterOffsets(); + var pad = d.start ? ' ' : ''; // if there is a preceding delimiter + this.setValue( pad + value ); + var start = filterLength + d.start + pad.length; + var end = valueLength + d.start + pad.length; + this.selectRange(start, end); + return true; + } + } + return false; + }; + + $.Autocompleter.prototype.focusNext = function() { + this.focusMove(+1); + }; + + $.Autocompleter.prototype.focusPrev = function() { + this.focusMove(-1); + }; + + $.Autocompleter.prototype.focusMove = function(modifier) { + var $items = this.getItems(); + modifier = sanitizeInteger(modifier, 0); + if (modifier) { + for (var i = 0; i < $items.length; i++) { + if ($($items[i]).hasClass(this.selectClass_)) { + this.focusItem(i + modifier); + return; + } + } + } + this.focusItem(0); + }; + + $.Autocompleter.prototype.focusItem = function(item) { + var $item, $items = this.getItems(); + if ($items.length) { + $items.removeClass(this.selectClass_).removeClass(this.options.selectClass); + if (typeof item === 'number') { + if (item < 0) { + item = 0; + } else if (item >= $items.length) { + item = $items.length - 1; + } + $item = $($items[item]); + } else { + $item = $(item); + } + if ($item) { + $item.addClass(this.selectClass_).addClass(this.options.selectClass); + } + } + }; + + $.Autocompleter.prototype.selectCurrent = function() { + var $item = $('li.' + this.selectClass_, this.dom.$results); + if ($item.length === 1) { + this.selectItem($item); + } else { + this.deactivate(false); + } + }; + + $.Autocompleter.prototype.selectItem = function($li) { + var value = $li.data('value'); + var data = $li.data('data'); + var displayValue = this.displayValue(value, data); + var processedDisplayValue = this.beforeUseConverter(displayValue); + this.lastProcessedValue_ = processedDisplayValue; + this.lastSelectedValue_ = processedDisplayValue; + var d = this.getDelimiterOffsets(); + var delimiter = this.options.delimiterChar; + var elem = this.dom.$elem; + var extraCaretPos = 0; + if ( this.options.useDelimiter ) { + // if there is a preceding delimiter, add a space after the delimiter + if ( elem.val().substring(d.start-1, d.start) == delimiter && delimiter != ' ' ) { + displayValue = ' ' + displayValue; + } + // if there is not already a delimiter trailing this value, add it + if ( elem.val().substring(d.end, d.end+1) != delimiter && this.lastKeyPressed_ != this.options.delimiterKeyCode ) { + displayValue = displayValue + delimiter; + } else { + // move the cursor after the existing trailing delimiter + extraCaretPos = 1; + } + } + this.setValue(displayValue); + this.setCaret(d.start + displayValue.length + extraCaretPos); + this.callHook('onItemSelect', { value: value, data: data }); + this.deactivate(true); + elem.focus(); + }; + + $.Autocompleter.prototype.displayValue = function(value, data) { + if ($.isFunction(this.options.displayValue)) { + return this.options.displayValue(value, data); + } + return value; + }; + + $.Autocompleter.prototype.hideResults = function() { + this.dom.$results.hide(); + }; + + $.Autocompleter.prototype.deactivate = function(finish) { + if (this.finishTimeout_) { + clearTimeout(this.finishTimeout_); + } + if (this.keyTimeout_) { + clearTimeout(this.keyTimeout_); + } + if (finish) { + if (this.lastProcessedValue_ !== this.lastSelectedValue_) { + if (this.options.mustMatch) { + this.setValue(''); + } + this.callHook('onNoMatch'); + } + if (this.active_) { + this.callHook('onFinish'); + } + this.lastKeyPressed_ = null; + this.lastProcessedValue_ = null; + this.lastSelectedValue_ = null; + this.active_ = false; + } + this.hideResults(); + }; + + $.Autocompleter.prototype.selectRange = function(start, end) { + var input = this.dom.$elem.get(0); + if (input.setSelectionRange) { + input.focus(); + input.setSelectionRange(start, end); + } else if (input.createTextRange) { + var range = input.createTextRange(); + range.collapse(true); + range.moveEnd('character', end); + range.moveStart('character', start); + range.select(); + } + }; + + /** + * Move caret to position + * @param {Number} pos + */ + $.Autocompleter.prototype.setCaret = function(pos) { + this.selectRange(pos, pos); + }; + + /** + * Get caret position + */ + $.Autocompleter.prototype.getCaret = function() { + var $elem = this.dom.$elem; + var elem = $elem[0]; + var val, selection, range, start, end, stored_range; + if (elem.createTextRange) { // IE + selection = document.selection; + if (elem.tagName.toLowerCase() != 'textarea') { + val = $elem.val(); + range = selection.createRange().duplicate(); + range.moveEnd('character', val.length); + if (range.text === '') { + start = val.length; + } else { + start = val.lastIndexOf(range.text); + } + range = selection.createRange().duplicate(); + range.moveStart('character', -val.length); + end = range.text.length; + } else { + range = selection.createRange(); + stored_range = range.duplicate(); + stored_range.moveToElementText(elem); + stored_range.setEndPoint('EndToEnd', range); + start = stored_range.text.length - range.text.length; + end = start + range.text.length; + } + } else { + start = $elem[0].selectionStart; + end = $elem[0].selectionEnd; + } + return { + start: start, + end: end + }; + }; + + /** + * Set the value that is currently being autocompleted + * @param {String} value + */ + $.Autocompleter.prototype.setValue = function(value) { + if ( this.options.useDelimiter ) { + // set the substring between the current delimiters + var val = this.dom.$elem.val(); + var d = this.getDelimiterOffsets(); + var preVal = val.substring(0, d.start); + var postVal = val.substring(d.end); + value = preVal + value + postVal; + } + this.dom.$elem.val(value); + }; + + /** + * Get the value currently being autocompleted + * @param {String} value + */ + $.Autocompleter.prototype.getValue = function(value) { + if ( this.options.useDelimiter ) { + var d = this.getDelimiterOffsets(); + return value.substring(d.start, d.end).trim(); + } else { + return value; + } + }; + + /** + * Get the offsets of the value currently being autocompleted + */ + $.Autocompleter.prototype.getDelimiterOffsets = function() { + var val = this.dom.$elem.val(); + if ( this.options.useDelimiter ) { + var preCaretVal = val.substring(0, this.getCaret().start); + var start = preCaretVal.lastIndexOf(this.options.delimiterChar) + 1; + var postCaretVal = val.substring(this.getCaret().start); + var end = postCaretVal.indexOf(this.options.delimiterChar); + if ( end == -1 ) end = val.length; + end += this.getCaret().start; + } else { + start = 0; + end = val.length; + } + return { + start: start, + end: end + }; + }; + +})((typeof window.jQuery == 'undefined' && typeof window.django != 'undefined')? django.jQuery : jQuery); diff --git a/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.bgiframe.js b/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.bgiframe.js new file mode 100644 index 0000000..5c3735d --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.bgiframe.js @@ -0,0 +1,39 @@ +/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net) + * Licensed under the MIT License (LICENSE.txt). + * + * Version 2.1.2 + */ + +(function($){ + +$.fn.bgiframe = ($.browser.msie && /msie 6\.0/i.test(navigator.userAgent) ? function(s) { + s = $.extend({ + top : 'auto', // auto == .currentStyle.borderTopWidth + left : 'auto', // auto == .currentStyle.borderLeftWidth + width : 'auto', // auto == offsetWidth + height : 'auto', // auto == offsetHeight + opacity : true, + src : 'javascript:false;' + }, s); + var html = '
    • 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 Xw|3Isl|gVnIIB_4wE7zOPn7Tix)Pf% literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/shells.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/shells.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..632728a509f8b80b52a23dcca1033b62eb9e1420 GIT binary patch literal 10369 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 AJpcdz literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/signals.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/__pycache__/signals.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b18c79dacc5979d7090fd1fcb4b7ca8b6c4817b2 GIT binary patch literal 472 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 RBv$0z_M=<9{X4r+|9?|+irfGI literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/base.py b/venv/lib/python3.7/site-packages/django_extensions/management/base.py new file mode 100644 index 0000000..eac0dbc --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/base.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +import sys + +from django.core.management.base import BaseCommand +from logging import getLogger + +logger = getLogger('django.commands') + + +class LoggingBaseCommand(BaseCommand): + """ + A subclass of BaseCommand that logs run time errors to `django.commands`. + To use this, create a management command subclassing LoggingBaseCommand: + + from django_extensions.management.base import LoggingBaseCommand + + class Command(LoggingBaseCommand): + help = 'Test error' + + def handle(self, *args, **options): + raise Exception + + + And then define a logging handler in settings.py: + + LOGGING = { + ... # Other stuff here + + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + }, + }, + 'loggers': { + 'django.commands': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': False, + }, + } + + } + + """ + + def execute(self, *args, **options): + try: + super().execute(*args, **options) + except Exception as e: + logger.error(e, exc_info=sys.exc_info(), extra={'status_code': 500}) + raise diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/color.py b/venv/lib/python3.7/site-packages/django_extensions/management/color.py new file mode 100644 index 0000000..eb26e5e --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/color.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +from django.core.management import color +from django.utils import termcolors + + +def _dummy_style_func(msg): + return msg + + +def no_style(): + style = color.no_style() + for role in ('INFO', 'WARN', 'BOLD', 'URL', 'MODULE', 'MODULE_NAME', 'URL_NAME'): + setattr(style, role, _dummy_style_func) + return style + + +def color_style(): + if color.supports_color(): + style = color.color_style() + style.INFO = termcolors.make_style(fg='green') + style.WARN = termcolors.make_style(fg='yellow') + style.BOLD = termcolors.make_style(opts=('bold',)) + style.URL = termcolors.make_style(fg='green', opts=('bold',)) + style.MODULE = termcolors.make_style(fg='yellow') + style.MODULE_NAME = termcolors.make_style(opts=('bold',)) + style.URL_NAME = termcolors.make_style(fg='red') + else: + style = no_style() + return style diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc360ba826ee2b97f4aeb40db6090a6bee0ce249 GIT binary patch literal 208 zcmYL@F%H5o3`J9k0U`Au4AcVy3qlAnvmoXuZA=MmovKbN(i?FK?!d^(2@o3->45ms zfA;rZyouw92)f^1a+uEnKSg0#2lFUEi@lgeyQ^r1^B*4%2gZh>XnN1Rvqza)!mKc` zMJ}AJp;LLw&>?kDniOj9PL}4$0@yg5)ha7gjtu&&D7O+X4vCE=hDuRrDkKM)twPca XQW`Q&%B1#>@v^eIEpaux^bQtZPux8W literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/admin_generator.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/admin_generator.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f76a0dfa9c2e1472a8b31dbf9f7afdbc145a211 GIT binary patch literal 10309 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 aEtRDzw(~_>rLSbex%|)RL3x3+p8hZJyTwfa literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/compile_pyc.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/compile_pyc.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f932f13e7d66c12d33b10922a8b0aaec89617c5e GIT binary patch literal 1538 zcmZWp&5q+l5bpMWGR|mNw4>!uvXDRoF*XthH~<=EXF*74K#b5z)*|D$JBbt9?dk4h zCy{d@bA)%8Ir0>|12_80X^&hvQEewMh?c6lx~lCefAy8m27^9=_1mw1Ccj$<{h<&0 z1!r^$B7Oix5WxkCyB){4JsYtByHS{>728Bl}s zUm)TT_XZJ{_O@m`Aovmuy%&%LT@10ZW-PB@_XL$PuO?z>sDraq(8sJS(~2m6XFTDY zakw}T`J_sVtP5xQJ^N*XaS9^d0Y#Cn8*0X}NsQPcCb4c%Y*UBW#JNFR9J|ETwJ3L& zVjY4}=LHSwm7KCF7_B7D7@@%!oFW)A9>^&~Ih)Z;hM#8!B+^UoF34jL@d#9dXMiCw zbXJ}3=N2)@=3cCwlao4?)3tF@D_cm$sj^zf>z6gn^6@Irr$DlR(`>;74f0B|p{blS zlR2xDMW~RU=DB;}JuNh=BHS%Ma0<Ja!K{4f%^q)>1+PbXAFWR_MFme6ZSD*?rb z2)YCjojlq#MQB6gnAEE*tXFDqzeMqp21)Y`VIQv_?!XWKb0@<(4ofrE0r?t4`~<3j zj=q96W@Cy+5=o6Q+L~|%tif-A|2=6CYm0xx*ReEj!E=Yt(f40HGdK3e*|^uI(!O;X zm)Lg(_}|}n(rxU<+Zvl*V-aU=@nwT%-ffS#P45`pVT@$|_Mqu$>*|}Q=<1`Vz<0+neBA6h)$$+%m9Jy7kJL0tf|t2zEOw$nda*{Z@O%F@Avi*uzJ7 zeYmGa_rL{=s+S}>QIe>Bl9Y@rfMkjCljLfV7F~q<@Z$KG)2l_!sYt|1NLnV@6zDGa z0|;_WDE_uqdN}SWT_4wjJOB|MC|#OmcvkBj9&$b0{8+0uKmkM|Y`;jLi;-F`!htoLyT$)~y+ Rp*!gTk{)2|<0Hd2{{~Verf&cM literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/create_command.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/create_command.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84c6125f658255dee92ae02ef43c86c9fb3d2b04 GIT binary patch literal 3329 zcma)8Pj4H?6`$E%l1qw|sDG4X2gx>#Yp}J*7A;VqaEv6f(?bIVwH(-4I9M!qhSW;S z-Sy1S7MUe_kc*s>`Xf+45ACPuJ;xxYIku-9i(ZVJ`reSV)EEIuVrFOFym|B9n>X+G zK4>&*1b*NAUVGgIc!s1dq2+)vf(gH z8O&CqEXhP5)i~j8ORojP@RSG7M67t&OSo>xc#wukG~W=Rkmb)_4CHTMzzHf0%2MBE zmhUjzFMUD!lsT;Q-1W=6!pf}joSakN{en2euYyvpt}HZ}^bZ6N6_;M<-8~7@LFR#i z;eZc$s=USN9*YH!R3^rrRALmVk>FlG6P`Ne-XMO;Q!mVOFAay>i&H~|`AvDbuk+!9 z$Xck4Ul$shArGNb%n8j=~09F4IJZ`8is{*ygR#^QCwZT@|8f&uk zFU>81aT|w|^8P+5GqLtlU6P zlJb(-1A5OfxnU`kD0}DoBl8n8`T)P*hW3L}4T()h2&qdU+Ye3hw!F8jY3*87A z3qmm%p^{S9uTCL!9m$ivF6W_;TtH-3gTPoA1b-*r|Ec>4P-XX2OvZAevVPD5E27i5 zdzZ^omF3;1;b0`Y5JOM9N!;t^V|ARRzwZ3DE8!{Z=V5dT(I~sj1ZTj{6i+4iNp>%< zsJrmA?9Q!PdcKp7#X6X>1x>b~BeYH(>Qalk7Jh5CL(6oseK3DzovW6~R{@L30)zDr z(Bv+31)bUol15>l(7shzUqRq90-h_ZYfED74lLv`GC#3qQ+ z4meioN|xj0OW%fvBT&_Ow}UL}$B;4-9>5YSS6zF;oJb^gC$PWT@-F{2(CnI?0GLT~lx(3lP+>`V-qc9C1Ml+!T$(4%J zfizwfB{*Na0iA9vt~}yN0`gwz-=<<4na~VTh7O}kVw}0uu^ij6>g$I7%Gc;#WHP>f z0I33#K|;Xa^qfo`WfhR&Ol~9R_OxW?kR%}2;k;Z}%-tib3g6luX%UM|D^nL{D|=*$ z)H-}?%06*sCAhsZqrlxL$b~&!c|p(qsq9&$Sh=8g$qV|~H;?UUecG6=7IozoE9aE0 z?f@kG*#a4B#hUoq$f+)*(PHhwx}fswqAFo!wmfA)r{wG%wNfTKDFA!V$1CP>MHM#@f0<-dg_Rms#%oSRuVaFERgB{K3 zPO&rFELsQv55dEKB=^aqDP5A!_He_QDb$Qi6ZA zd$Kp%WYGjFG2k;~fQpuc0aX*G+ynLXSu;l?NAjZw#Z{{Ug zWRkR?5Tb{=bnpKCkMBn~!5@CH9YHg%v%s7{56ydk#7NIBUxs-S+P$5G!yXIo{1UeO z2O62Y^*_0ya~qFL(9*jhJKm?+=q8jaxyX7@Sd9U9A%g+#d7~6l zHEp()c?x(c03Z;kL!soeSRHGZr))l|2oCrWL9HU7=!$b)%0-+) zwUOl@%|RFHlBpM=nmHb+IMFV~4&-<)5F2#mvBpG*2@CNvoZf`aufGz5_E4rPa@2#N)FtClzb-fcAe4uJ zVTeHm!=P#3ca4Lxge^uXf96;Ed60>C0QFU|t z0OzjNvaiuCdJRB+i*C>w{8woU;C_|9X-2ES)r5Hs`Z|p3@GnDq6Lwf;)}#VYXx9b4 zNpXPPd(ipU=RwekpqlJl)*c;;u-^fMzUUzkP>yZ(gu8Gu{5f$R1Tg-7YvSQn{ zEzGVbsa}N0r8GlD2U&Qh^+Fkm-taI{~%C8&K?7hJFxgQ07O#;gR#gpu66NQ*P`I7G_}`rsjV z*8)HB!Z@W&c$^3kCOysyU;wKspyG1@RMfTzKq1@)U?WpE4O7pluWnCypjh(T`vXCx zAgBm!VhD7iO-!L@kZy}qGbV+6Uxe&esb@@z!q_*bh0NG5Vzi}UJJV*y#L9GB+R`TW zGj#leFs4>!&Crha3_Ur1Y)nd%@?F(qL$Tg{Y3xi!^tY(b-W7r`eZFzo7S_{>FP|IfrJMT zi*K|&?coJ%v?lu7A(~%}FWp$%?W-8sUDEcJ;(o|I}ONWGYDD;QX3+07G&9MpP9*j%PownD8 zPD#dvrhv9Ju3v|y8bMdUBZnM^T=21eolC?dIvPj2RD=Qf%-N>H2q!m$17+%@gvB9O zJ;v#Tf;;fO&YR97I=lgWH)XT~vtZ;5In=Y`C(bZY?FYEJVMOK~K*<@VO=p+p{1J(p z<;Iq*ztzN;>ci6N5#bBLq)s_gl`qYG8YZd*sSXQm$2{_*fixnL$l}}$S%?QP7i5Vf z!z0U}%J?ETk+g+iwz zOr?ah?zQhSMwv9gDPR(Cz#8jr^(_1H{^(lsG@wikcJ{vdvXBo@wyFpl0Nl!}Przih zsdx~U79VzC&t)NxoLgZ8<_yd;PdSD{(3vwx)OGDV5H!LIEFnj()lEIh!k$|M1PE`Y zjs<$QVDUQuG~L#VsD^6#2C|KJ&^l6U6_w#v0Zd2BXaklFJUY;7dIjiLbsb;@XiQ0K zR9K#i9|O*s0Ni)ySK169=bGmesoC*i?5R29zV{y-`CpCv{@tr@<;6u&>TY;`CG+8- jW<+ky1%LBdqNV~A>U>t+R?7J@02_R=l{b3Ls8#<3<7A_v literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/create_template_tags.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/create_template_tags.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7fc5fde0579777893e06ff0f8b98d9aa2203dc30 GIT binary patch literal 2553 zcmZWry>Ht_6u;xQWJ#72$8pjWAc`h|hDbw$wkVRKt=$hGfIB2b8Y01k=AC3(6iMHm zY)hb)Izg5c$kbT^x^&6E(6w{NTRWv&J9g?jO12zC#C`DHO8IXNcO& zJTU{8I@EoJ0*~VRsO7x@X=tZ~RrSj}-^vDqFr_U+t&&05XXJ>-l7+hoQ*{yd(lCkU z9FhL&^k*(M;x=p;($)k9#ew+(bul%l`OFI}Y6Uj61BWg2pWwiIfh-hMv=z!-s2+z~ zoQ0AJKlHcv!?c(Ak`3|%NWKhv!lyB3k<9qW7m^PnIpoamX55#1%u!|7^4F3gAdwzeS7-OeulfGNL#xzc5dC$ zD#pgGRM`T|VX6t{ktE*bAs-QasA`~DZ-_R0eD48RSlT5se<+q#pZCw-4dFy{wf$|@ z4Tp&oKJY(Xhsa!f|R@NR%@|Fok4Rgj-J*1R`yf+-MR0^=@ z+$%)c5-jN|Cl9$`9CDySNR)&^5b_)P?|J73po&hPk4IuGvo6`qQWo{&&NdT$ndP0s zus0MPxbwpfINr%eaxY6iYJbuZkTtjRFzSarCOWi?BVosqr2=dg9Y``b(KdA!2_-sF z8FzAe8*@kV5pO_X>N-MAm=LaE3ma$8_|hV8+UGqJ-#j=AvJD^U(zypid<+u=7ER0o zf_nu`tiqy3-{3c>DS)Ym6VN&%)Iz=o=2$?&e zy=Y;6K{IJ*xDJrEyfoj#mQh==Ov@7hcp3ZV6e6~7 z>$p<0Kr?er&5l$ zkcNxO%$Q*T)M@2y8b-$-%4*@BfZQjWkBv!nvQn%}S14%WFAKM*-bDv5AEM)b3lBK{ zp45ukv_>6}_8N98)CImj4qh*$Iz??}OzKM=z*DDQVSs*f(kSU((U{>^m|r{3_3r7x z>!LAj(8>(McdJF6R!@w{D(o6`1$ND%Ic*lJ)3q5YVQzJLVTJ(in)7wESyki68dg8pAH@Wa{0{^eEd{!_X@YiRy!X><4Sw`KDl24 zuOmWe5NvF>C9Dc_g^$L`PA21sedcdv!-S?cr4RY(10)V&p)ttcjR9F^R~Z}mHY`Cw5zR6we}9kDM#!LWt{L0 zFq~h~)?52ooa)lk*Z}2b9fe6>nF&jk!;WJC2yGAga4o9BQh;m@T~Aeo47n6XF~Et( zQaazcoIz8Jm~uGu!8lh|mV+3(Y}m>IETzhhl1wn=>1%}&XIxj4a=*X-HRl;uCO8B} zN;u%HwV-|mWxD(WcM*&^0A1HU=oT5&&e*h_m?~EccVP>rmzNaOID>8tomj({!ZD~Q z85HgYUg>z2(8VrgM}gDLiKgfk-j^sbhlfp2suhbnFd+l5&Db!n;&rUY1zatkb!Z3; zya}TT!&p!oB@!CYGHO8QT2iYr567pl58j){tQ|r7ZZBI>TjMp?e-45V-ihjYJ{?_A iUg{k4G?JBC&iSweZST$;WcXRBg)fe+NsA$tXPWU)>d3wi5T(WLd-WkH7ufx%`r*{fj7Z#4p;kg55Px8E70OLkEjQ$8W!P93A`%#!UR(cQ_2Vm>&f5FV>Xpl@H`0kl z6oy_S_M=dOpt{=H^0zyF+*MQ3sjL3BaB1{PSnUy|~2eJXkr+@Q<1xFp)0nfm;!jc((-Z` z`C+>g_sY~H3R9K1=f#il=Yu6_s%rsAIqA)eNCu32A2xB?8=q`&+n3l7(W6|+G=)JiXDJ?Or z;|4)@1TXkEc3=a5AKaUM;K?OJkbNFu3XQlMyIb%ly-OQW%MabylQ>PIUWI2Tw1yT# zV%M#;@4$HSlsq|}QD4#z7l5%>T+SW9*&)jl?)~7m$+CZI0ZN^4yCK!3h9&3sINV}KYEr?q&%sSB*(EBTxem|EO;x~yl zC_Dm9VjLLg$=xf;|ADTERtaypIiwF`aGAJQNpxO%!uol9O(uC>KCb;vd(6JjzF(G9AP*u4^7%s*gjSg~J73Xj+}d~CnCe=I4kX?La{Gf)&o`iS*&*R;L#rk3Q? z>XRcWx3zw0|0|LT^p9@q{c?YzTf+)dNjaHl0*}Y+rWXF#)Z*#g@>3>k21gICpuv}v zcTMzsg7(ay#;e(k1?_+_?NiLTrNy&@IY=;n!1|S>G+0O~G?r8bi}A4ohPmbVcv6Av zlWKI5MxV01GUOcdmw!T=Xum=I!k~uo#lcH_>VOgT{)wan$rt+7Y?MzY)l35L`8)9$ zynFzj@*DC{`?jLK-mi8SK(9a5WjQ`EcqOS4FX;I;^t7O-E-rjWPhFhH4AOHZsW##F zXa=;@Z;{0Rxv6voj-=~UGBwmt7dy~!3K~wuKcM={YJWODnM|W+<|e%6FSP60Ee*R+ z+rJyXn#?@JUf#KmeVFaf#jg!cC3C<@7hfecpf^ivCbJ56UHmhdLA!QLJFX30KhXH> zF7!cfZE%{GvylV%`D@x!eeWwEQG>Ss#mSpXrbvD|qtGbZMMF-b&7K?EIC@40IY3eGD{8sN1ibAJP$PC5y-XsITh7C;_D+txC_)Dhy!!bdY9PeDi^ga|Z~3Ad5}r*&EQE^Z z1Ytjse^8jmUQPLC2<>z&h9;D;W9Znp3#S+}kQ9wHwp;>#VYfv=EO z>$I`$p^B#U-pQj7^lZCL%6!rsQuX#uT85}iCybCI2um?UV1D2VE*<3U zp*_WYxqHYrEnA3tEQhpSt1so^J64H|6Gy+#j$3ZUAZhN?6 z6j8_re!L?}SWM-=De;Lqahj8HH}LGKtCufbU)@}HK3rd2yS#BJE#TIH{Hm4ekxcW# zYayFW3m@IcE*)kB#;Hk%DlK^-k^@{pytI0K{o0k)i|aR>>+6@+Z>71G8#i`n4dJ)b zJY@AmEGWB84fH{XNW>mb&3j1EmKMYdG*XD#>aKI>7sM-sQEhZm4}lSN8klWk*Zim> z4+kVJXydzpJ*CnoCyt!#z=@NXCSIkvMRk7xZgzog3k0Cv4DI>vuZ3F#@m?hSbU9tVM z2@}VVkul_6=Wrj<5mn(Q$C309V=y_^4KZsZX#_~@g|pL{yF$04>xUf*zCL;N_>7N zhZR4C#D5^s=TK-0;40LmEiiQgrZ+WGd}t>P^1<{_J-)x)!bcbS46;lTIv`VFyJc}U z%Tr>Vv&2aBQ8tOpu)!fifPeN_e*%b zvg5QO-U&RkD~^NT2LkfHj-xJP0>2Gu;wlxi(Q45nf+&&5G{qzey2457!uFfRh2mau zQuQy*h;u~qLlmhlJp0A$H;Z}$u+|TMt*F!OOpq-oEbP*djBlyiR2EQ1bNN<%jJvF7 vDL{rJ1s`(Ctu}m=xIpa2&Rog!JO$F?`3#14X?;nmD6fJej6bquqiFsg`wuNk literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/describe_form.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/describe_form.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..520f98781fbff7995e6d24d49a4a9e0f82beb8d1 GIT binary patch literal 2732 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/dumpscript.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/dumpscript.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a0be09b129397d3d1f29c62203d4c043438b19f GIT binary patch literal 21740 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/export_emails.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/export_emails.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31b0c03a8aae611d0430d8460e1b92b7f5e7e0e0 GIT binary patch literal 6019 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 QRQGMEB}!C>JE-pb1@}}bIsgCw literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/generate_password.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/generate_password.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d22e76ece22d01e01493310c3a6ffe356cdb99e1 GIT binary patch literal 1302 zcmZux&yU)@*C&97yEtR_nh0iyE_EOo7eyFS3V(s zxrgnDaPc)x^9!2gz9f>Cq@o$6Z%e-;^VF< zW=fR#;K<#3+kps%if`fqNJb^eJV`TOdKr_xWTzwxAe4a&Pss_*MskE_N8M<%`|9`m zpg;=?CKj=RXK^Epc~)x~+qtlDE>t{)xHTZ-qgrDQF7;Vb5`RB0jPsfJ?h~PAb)454 zJ~gp~Bhi-jEHj=B=inZX{{uLw!~(cRtaZh=$KRYhPQJ;#4NmtT;=F^?Ttl;_Pf#4` zS?WOk#vI`YEI3?62L~mnnVr9-U#<4P+oBnK$;9shCG^a6%q|<~*c{4c;&o#oB}ac- zfwG-nD2q;JpgiirMrg$RC((O&@Y@%u)5@d^y;_=;t&jM$R*)}>^e&i%t(){%%vzHk zgE~&jVwyHfJFnH}$*t5B77iMbFHmNa%APL{zgkeHsFg`kZj87J(v8+8-OvVS#3aqK z+dW^cx#UQ3>=4RmNLN=k+9v4xHkR$^dcI1jP7`=y)B#}w@8RS^_VJ)zlGn=W zVw#B7&XXzLTJG*gPfmC7LDkgS-qX6)+4c9mfTcrevX9PU8t^h~o1ouMJE^iy{?{z$ m^IBV!W`N_WK8K_S))O3kG4S-I)6F=2Ji1T!=m&I6$NoERR%vtq literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/generate_secret_key.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/generate_secret_key.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34558c501cc310e7529f38602e88d29f4b24faba GIT binary patch literal 833 zcmZ`%J&)5s5Z(1h67CYZqk+PrOMzWbK!MQdj^hfXL*k&o&1&PFb9}MazMXX-X)k|< zUqQh?pma+`NlV47lM|5;BhAySXV&k{?3_#{2aN3d*I(irXY7YN+*v@uF*!abP)zZX zRXpX~#a`)Ee(LwJUj|i}hMb)<6{v8-R0#amPX}sn$)>}fbem0icX%QZPV1_YTG8<+ z2P+K4btMooL#G9-C^5kz*RssEm6^MJXFdhTX>#m_bz_TK;}>S`QTF#H z`G8N zL|sdr*8)CU(C8Qv8Zc!l&^Fl(5tDq^|K6zMX4MVm^Z+GHToWDv^VauwGmE#Wi|Mc% z387^LLUad0RJCeL7mtOwX=S;~1al~x^nrn!wlIJKS7@OU*_?Vp<5tNWI&jVJf!jV4 z5{$_EIgWVX1z!J+xYLK*{^G1Q5dZBgp3yQHCpmrepNiHNCH7B|KK^G&`@h;2_7a_v YJ$1cUC$Ss7*!KO>QT95=eC&<=KV%=}5&!@I literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/graph_models.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/graph_models.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db8239c120469d7b8a4a2732fa2ea3677a937270 GIT binary patch literal 9449 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/list_signals.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/list_signals.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6bba8b7304fbd5c8dd29438dc434e6f807acd16d GIT binary patch literal 2541 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 H+SUID)b5;@ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/notes.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/notes.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19810d5a6d9d4b0f7a0456fa68444dc904434de8 GIT binary patch literal 2537 zcmai0&2QYs6`$efetRW5YMi<);lO~`m3IRKMGDohD@CfK)>*lh0t<`;g4&tgrNkwv znOR$6$&(D^)YiT9Q1q~S?5+Pnf&2+Q&b623SoG#o-;gWIO;D7J8NPY%&ExOAdGF0` zG@CU9&)@&{FYnJl{X;D-9|MS=!{B3>2qHK{Zu!P8hP4)I6W!IZ;_0C=F-P>sikR7mv|B2{W$=x&qXUDT<417Ab^4we;8g$SY% z2fDuDbNXpKnfMWb<&6;)o}iN?^ab@6dcbe;U=;b`pj1rP4u13K!!Hl`;k`$9_jWdS zvR`cPf4-G%eDOH@Z2i+;WzW~2^|$+vv;NNBR<^&t-vQmV!$)_!KklUUyWM-84-azn z8YoDYkG>%IM?g@dLg8uzyE@Ta<0~}8L?_0pifdAfn8bR8F0gBVg$(3Yz&%^q3pY}K zcO1WT{4jLFP(AnwFbcrGnJNhlnw zE)7Dtkj9vX32+B0B)~QKG@(p3eL_5+jiwVC2`(G&E<2huI1Pu=N_@sCgJh_B-XQcj z_q@NLH!pf$0GIbpSbEM=5f8niIHH4-ptni+iHMWl3x71_y%#ik(F=p4UUDwRarANb zlO7KQy`T7l6MsZ`j~x5aDE8=?pb=Lm)`Oe`iNe%dBp&a3fSj=)UU)A7G^ikJ_a6?7-lE1+I$nD~NrOUPwUPFSJcau3Q&7F-Pb^%MD=& zOe~b{bo%vklr>=A zA2W3P-fV?5vwA5x`(f4qv@7}YLek2XOUY||n!v77A24I|9P<6w=o#8ar`dCKI)<^K zcu)iF{@cU6ETLU>nD4_h0wag*9ExZL$^_4~KWL{0Y|>FvwR8bdz_Y4<@G5B!in1maTtEi#pEs;~=W zD&H~$h@i9^$_1^Tw#tO>4&q3#;0S=#xbT_aF9R{|V5YqJ7A{$N5c-oN;uom?4GJiA z{x_yl)ipM^pY6JpjrH9v56Ev6vW}MOP(`WP9g9gQF=L9$Y-O?e<(-fDp>yZ{Pq=f3 zr}`bfmRgQ;4;B)2z9%i{fr2uog5tKe`@4JVPo8XTdh1W0?lN_^NgHkvUkE0(m`fw^ z#aJ50aS%!4r5~Qa{gZ@H`e)FOVrWmY%BWAmAfjA0*Za_c*Y~z}`rflGY4M`HNqZPX z1RA>3Cw?Mz4yMg1v^FM}-r2C#-&C7S5C;jXC?pmaB%TUszGU#l&UJQ8aSiBoT-tF` z+zhS(8Nl7<+iQ;mjLXUqT#O!&t_@;EK*x;}XrxMN7WaVEhLLLym4j~k>PGNNU$h~S zIFN=~6_Ew>d?agEir+q7tIVrgfRR6d3F#l;8vG1g!7Z3u_yZU>3R*S17Vv9$8OANF zX>Gis-NF`b!+Hg$t^ZDpPE}SsFY+hU^JLBQCNY_Yif(w`>C_KP2~+=Cq#620G%Q*y zGl9V#DQ5bS4n{BIn%O-xa@OW-5Y^7rsba?SfmJb-*g?sY!vp e@~5PfH&Ab7m>#NJ=WUoOxS}<1qZn{B`hNh(maUxt literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/pipchecker.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/pipchecker.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c02bdc2a24d248ff6d86c5bd65bb2c762867738e GIT binary patch literal 11129 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/reset_db.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/reset_db.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ccbbf188096d88a13203f2dbc2d4b8733fc3e0be GIT binary patch literal 5403 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/reset_schema.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/reset_schema.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30662bae7719a7ab101ee46a7f5578e298371dae GIT binary patch literal 2750 zcmah~&2Qtz73Y^IijutA-DF!QEiiSHY=y2Upgpt*ing+)ZVfo{M$#r-UKpA)vbZ9L z%FNJ?8TnE#kWF*9$zfAik^y|>?PyBd7| z{^z&BkDHqIAKBS{76`wG!V{>l=4)8TMxy&Vv}R(Yrf;T}Z|QQ}N@}U?+e)s1T=(lr zwi739_zfl36E|)8O(i=?D{cF2U3;$K26o?Q*d^wb>F;1;s&$*iKimn47zqX8NGu3i zJ|if~C?z0flzZ+s zpd)SEHOl5bfH}z0G^Ds}ZG;hH8SCn0XE^%9;N{UQ814syqr<@z#+vuefvy7xL`+XP z$d6tePiN03BY09U8b3cAkK~4TCnU|z2tK4^@`d<>Fb)tt4H<=9k%Y1R%#FaGfj~4c zoaP%?_f2g0)>qmb%!sWwj$gwyY`@Wb`zy`T{5lw*Ue-6riw{0iN(m}mddD#3?a; zUE7S+u_N6^n79d};C5b*XCyI0q(%chxieGT&=_!yzi}X(dhMP7SmNO z$|e^XBf&gOI4PSk6@*nLo)sU?NRn_gd>zu$OnS)pcqSi_u7vW-oP$$IcT^{#Y>q;D zftE4FUe_vZc}zx23llENIwtclPef@gNU|!7-lTAPJ(lHgUs+QaO1tV7`{2580cflm z=-s+`Ot~N-mRCt)WRxH{H>TjgF-2SF@m3dw+q>OWJRfIiOckBNJIY9p&*`m6;T;|t zRv>|P@LsrJ?|r^^yTj`mYzK_Q9zX>zn93Jao>AJ{w&H5>-jHRh>J1wn-GjbYE!qPm z)p))F1++tqgOHu(ikoHYewWEm1l+PXN#>=!3K^&!n9vAA3yX=F`81FAx zals3b&4UwAPPB~sL&BFLTlLSv)13FuAO`f4_@uwO5Q~id()(4P$Aa`$VYCcS3GZWN z>;Sk$sH7I}1D9b&0_$(wpZD*x0<_KE28cg|!hZynrnhuU{f=Sjt}bg!Zz;KWdqXYn z{u6nm%YE?4fZTv`42Ay}sx@$6SGzQ!HFkj?OOrhlk{KrWJMcpJx|+K*h4s32ZLiH6 z{nA=nSX(;mNYpWmJkhT7KkIAj+QxO5t*vXqS=QMcW}RvVH{cc+*1+T7Ky+c(-@KDcbG8`nGdf!ujh zaar~|cl}Rc&&S$C`;*$+eK;%-`M?%P!~Eq*D!(xt z%m({|>1bM-r$jIr`&k{TvQ`CT8zNB}in6w15RF+)PT7#~dB(~*`GQ0cGP^GOfgHCW zX7I9}tyCgrl6}67PhvXHe4Efyh>U)FtFeHFDN$DQ>!5{s%u@CgcCdGDt9Rw0_5!kZ zLS)`l$y3uEU~~s~+>(+3j0Rc#x?y(=%YeRa89T71*xB;CI;88APM|Ihg3=9wG{bp9 zKyC%W=Xsb&NYJYX0nVZzP@z>t6ZUfnrM-!9(he|t3$&}VT?ty^WinnohQg(iB@oMK zy`@IM8hyFqCs6rMs?g>|knX&@pvEL^lokBOW(7V`MpUZzo44EOyt3ds--(glHuES$ x`ak{df?UK2_qIfaxLSFHgnsv`N>Vm(ep6}cx6)^L2P)9A(E&Ta4|Zso{|Dm38P5O! literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/runjob.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/runjob.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b2da0a1d750abe42d278e62a83163e0ee7f27f0 GIT binary patch literal 2030 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 V=Db0Ht|`O755V|3U$?6Ee*rhWf(-xw literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/runprofileserver.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/runprofileserver.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2869d9e6a0803d46bd8e4d3661a525abcc4deea1 GIT binary patch literal 8894 zcmb_h+i%=fdM7y?4u>-uONx9~Y}$#O%&s+ZoaR!mvujzBV{IJSvE(GnO+Zj{D2Wn> z93OIQii7_y6#t7Bi0D&Wmny-ZE4nt zcO_=9%5#ZTb`)zAttuNqYsA%e3f34?mZf?v`A36yf;JD=Jl~C6{>0^t_O@Y|_*;%0 z9!I8Q`ri6R{M4n={K#E3vwr4NFWxY-pRF_koIk6jiEtl$% z8^`Dyp*{{AW3PFKkiY8$%y)TRNh`OV$ejyYEkM$0URmHgmWD#NnE~3I;W|yqS47+KR*W%oAt56U{tvgC{e-w>s0_jyJ;K^~PH> zkr%tuZKt{Ath>=nMkd>R7P~Q(?-4v?KQlaRCG<>?l3?arGl2gSua2fUU`=Btlo9sxEPw-uqWjFRAAE z+%Tt@QP(oG3P3b1$6@UFbllQH%Xub{mw1JW6SfhpSf zx>?L1gYTPK){aY5j&bXpo zGfe@UV#F80uT(bb)l9_HX2{&s@FFk3K@XbX5V#p<(F;W!* z@piW$1R`goXesDZ9GrpRO#v%()qzM1Mr@XHHq#7H5SvBx(Fe?r%YYcHCA-guC9M1Mk-k&t zdj)-8$zVeCUtLOdLY{E{O8#E*^8Nn?k>HXP1Bb7}SJ`m=c4ACV2O)R;&|zsMicz)K z96xf?YA15-?1Rf!l5efJP*>)>@XFw7noIXrOms2h4cBx!aX3Bb+o-Fl<}`_4@Q2(e zPD{*Pb2@NUzYSI-BeY_?!Ci;JolHk)onbS%{F~RwM>LYk^fdWXaDw8Ev`kf-s);%i zx7x`&%Wb#mt$A)F_QpK!Hi6f+`E4?=FPU9-W0QK)@g%1ni(EBxQkdSF zdHJ_baJi9`iBv5_1x{*Yyoq_oP4ytO1@umGW z@K!zFi$U)O@%BjMk{ZO@ELKTAMROVGV^R$=o-|)$vJ1d}e0jvW=KdY%Z_Nt}M? z0NiGWyXoklX45!Ga`HMwT~8ws=b?RkCUSL&&hrbmAH7S|y+fyr&PoySoy*e^9Az5^ zvqPSHlva;6(-V)D7wl{&cNXt0EY}rbdQz?Ja4e7TschR#--#mIKH?322SRM)iOB3o z@C8-;-~hn#C~$>Q&s%zdz5s^z0G72xPnEukT0S;8nd|h%(QQVlG*rRlOp-YyqZD0% z`wNvT`O+Q*?UFC=8RD(%DWr-iaNjGDLXEDo!k)y`y<%{EdmJHGkrfZ*Pn11rulSJ^ zTu`N0+cNm7i~s}PH9T!aqHjNt0_9_=FGW7n_N0DszjPo)e;Dhm)Q4NTBmY?Lt4u#D z_0+z)Uxu1594LEbz>KrfULiI%E3C4m@IPnO_Fu4(J#AOom3Nih!mheo+|_nVyZUZ< z*I27C7=Y(`4}QuQGN0T&gWZo(3ZaKo1KiHy4t##>^D6dP+cMDSOukc@jrk{9a8S{& zv_IAbR1edkiCOqGfVzkxM1}kf0vDfp!Ryx(V{YZ)z3JNz7iQl} z%5(RZRvzBJH$68r{=`A@Z^$2wR$)>F$3ScGmiP4SQBhO&RHpO@>odT*0Peg!;7%{c zus_07&{@K}h_~FA`9lVt_9foWXHg*ufM6CgpXI07EHO+oQI+H(=d#Ry0Z#uShRG(* zcBSZ-X#WyzU2uAYm9a_*s}Xm#zP5=-pVBz2_IV-tH9N7VVb)PGD@^%wNWc+(R|gzl zGZ>6JxGkgiN$TAnLm;EDQ=g*_*y+BpUp|mXddMfG9)O3j%O_oCR(C)u3+aqMj=F80R-rOxh~S;8P&LrDM2ne?yR;cr6f_**EF>7kh#7^JIa z<^h{cCm`du3M<|s>37+s}{hQNR|%vZ@W(GEHY4A+Nq)j9df{B;zm{Mwh~jebe4XuXiC!e`M3 zE<>u4ukbrvi3fL%yAgEqpCY5T-Z1Ag*J^+lEFZgJzVh2Wi&q-MLr&Ww4}Td?bQ1+) zYz zQ$>c($jjvBz*J?fK;xz#!ik8!+wg+GapiFd1K=q9-%o|!VZ}$uP+5yx{VBnx4TXI05 zdud+>teDigFoxM02Zd!RgLjK(q@LE*5PItqFlsQ3`g!Rzlto|R{~TAlDinhrk8}&H zyrcYVv{&xx`?YR)paMRS9!eieK@F?_8|FVjYeIFFH%GflJl2KEj>ob+@5qQ|3O!@6 zYgXwRNC+r^$WVgc!szh>7{^bJuE&sGFa~*BnS5%BM=2qXut;fKOXW7XQglX<8->e0jF-PE-&}VC z_gR~N_n&BT5(iaE*#AJbT1ej`^Cqqg_`okc6usP0Jp>FF{7RllVL9V~-&T5aKYN2!(t zJXs#B*z_?d)wqa->Xo#Fw6+HYX4M1>5NAehtx%OG(5B4u zDWR7p<#9OEx}1FQ|1Ld3U=bX6w9hTtv%y`euTen)BQWP1R3l%IZ&E?$nYfU_r9h+6sLR$kEI*`n+eYHYcIieb zN~VlF7lFGsy7)l)_G)g22RBvb6i*uSh`ju;O;Oe01`gH}k{!@u2=F%IxP4=0W-7Wd z70o1PKInM3YC}>(go8Z0uESa4blbsypNiK|ke)cqS~PwTc1#uquV6ZnTyTL)B({Zo zgVSun{l=tNjog$*GPyFSlPPz6N^NW-pr(vUBbgFk7ay3E-Jy~2b1*a990Yi{C3D$y z93nd)?$&UR5OLCVU&5wH^-CE?NnQn))5@Z7jYMA|0cla(t8mKha*7U-iY8j86|#Og zHHDS7PAo61tSm0QyKKLIfBw8g`|ri+7)Gsz4rhyWx5zu~I92IGUAHQCXP51}_g9wjaGy3xC*qKg zsq9*sm<-#+*pS;X?$Mw@R3dz;Wp``*35^ngQz=VBB6mh?OsmLG#JG?VH=cZ!x>3Ny z=TKnlVROrk>*e2k0KehvWy+;IbWQ#eQ$-vF)C+zTwd+tXq*^F`&!ct$(=(_-@jHG{ zLlo=l#)ZpJJqoF%D#laRnZ{0ta#E%%0py_-C@R2e@}zPOJ%xI@^gE9=4#5~sl1&zL zm@6d1N{N*$A6OsfKgRC)PpKeErjr?2akI3>+&)bPTKWZHAfcI(X5QSAe+J*1Yc(vttK|Q~E zc~w9tJIZ%x5CzeEmkKcl4ahWXh5v}^0<)obWMiJwho4Y!Tp%(E2%V~Bw&PFGDI%>R z5zp|eBD;b-3wSXOP7wc8e5ulduj7i@q8v;WKjP)MlGKiK2nOmFW`oF)gUY9N7m(R zz>zEPqr-$W2#l@T;u0c~d-oRR?b!zpmW3V@K8(O5^Yw(oCknwS{bm+vewVy=ac`4x OB<1LAh!e*kVCSE9D*RoA;<$*k7|NW1?QZ5%1{C@sV|84(gT~Yp>UdBHIg-dwEPmwT%sU4+}UKq^-i{%Yvg3v=;XVFMnRS{onp7tD9N(fDR(Q4iY#Y4 zbKPpAsw%&yupG-jR9OB{YaC+*R(z;5=22T>Wz?3P)%@uZs08UnytO&wj);9ZqwWLZD&7lJOOfu6_5)p zMBJ5>6k>(S^oY;(1}Y!t(sUYFf+`zV9L8FkzQNwfJaOC=U zz*8JRTp-U*Y!WHEbY>O8%TM7Q*$c>?T{>&qBH*_DD%!>?zxvH9%l_-N3@_4rB}&Sa zyhsV%<;)sVeuzUjvBS%F1Yu!L%^9-hDTdI|LO<~?k|{$p^r6yLna1>oxrQOjU<;Hp zj>$}xeF%~8Nb9%0g7H=FFrQXv8Mw)Fm^L|Og!0boxQ|f zp0vIa?d}JC4joVcQgFu(c;AT&t~ai~ z7Fw4(!nZoUzen5v^;I9YS)#uMSOD^w%@)B*Y%oUzah5slX1^1}#*WkJg~jD%&rent zaeh(^&s_B-iq1}*c1vdtwPg|JmY0Rw0Y~5nG7mSvqgGPx48Co#WE!#K-?zY0J_rAL z%nEq3yZkX?9=Ld z9Uvd}=lRRiTHxiF0#=hd*0xKNZ|*o)-6gp>RLgcs0eOq#j{yT&2Kfo@a{6Js)3BwK!JY!jp+YlBT@fc#&8XvRhW zyNWNP7?x)BQ}_>wbz}K$sF@D55fNj|S?QJe0JgDOya+bLB`sSbXmVT$Rvh;R$ESES z?QW5s^t|3UlglT4iQUMadS34r0}H2nn@*Q)CB|8Dz${pE2OAE53}rl{ zic_5mjZDfHq)rs`w~4^SfoMp(FehOR>?k?hn0aR@QLkxob-8FQ&q@2lak3sbDFa@mglregMhY}G!6vW-p-;)snnCB^!s`ki@eUFNCQk)+8Z@0Y zP7AV()EL*8YECC>uA=5Ll!qtAXg<3yF;P>bar1bjn)(?4epEbCp1}M=t|s}ewyQtV zMn&YtBVFd1M`*{p`AFSX9?gvkOg*I>=*YEGiuhzKG=`aBepnoqhUH;pSZ(LoDfYs{+yShIp*qxtdRm`lFS64ZlN;uS zbC?lo2fZ@b>no>}&sDyglnzYK*j5fqJlXwQk$zSA(FX^)C==xl)q{ML|6CP+%c`TI zT^dzcWzWFK{ZR$A`|=c4lq0K~PWicdcR$J=m7_dSmEP{q-IOrm*BEJq9Q#W- z_G~h4ggM2p<@)bNS*-u&K>_`%SWDwe=&7?;qrz@wyiR09pjTx6x%L^j1MB=xvJQ5q zW5hpW1&ud?xlxgwJJe8Km-Me59i!dQ-Ujo*JUdTs?6t?*1NDyLZ5T>$e6N7s|EOYC z;ySce_h|eV)SEmDxoec@v@`Sn^|SMTqIlZJi9)}y&d-CXIlN}2u`sovQ&Sp{5@%Bk z<2CA&8!PQNf6w7tJ{+t;oS%R^{|?ReCX#ELoFr1(Y4LG~JW(6I&cqcJUy=nEo?Q1+ zB@Hjhx8QqO9j6`C!xOiqs*sp%ap!IyD9h?CjFCUGu*m5rn@?;a0n0+Pdh>x2kZq+L z>Icf86uFaSu;$=KH zrA^{rm~j@CW-|b6ky$NqN;+!NxaQwO9UPDRL^;H&Lq17@qGF0&@e-z)8mV@h`(0bE z`4c)C+4$teX#lmV`m!3nIff|!GwV3@_d0&7*%9y8pEu0}!H8rTJd$KLP)JDzPnAd( z0KGso7^x^3dm4W&PwNP@$DLm z&(O=hb@Rsc)lX_=ehDilBqIwsfqO#wI5*Z}3HsAE`2sa$F)yj^IO}?%2R$rF--a2) zEwqEo<%CDm@B;LNbTFYdR%w!{^CcbTm!GE8R#QN)lU0_CdW0b<*%x8un|S86@SXo3 z*`J;4Hxpm-t493Ft0VOgeCO2x$509U>QLwJq`h+ER`QDInvTH1 zbQP(6Zmje7>BMW4d>={8oT0a*sBBNj+T0QpWdNCepZZ^>{yHbl;8!V;#GAO0Ao47u zet{l>?oA;@i+=$en$vP>c>Z~$dTRWHG9*1D$)xDT20#IFs13dtWfI9HXF5_pLtOxm zFwhP)UXL{X22(vyEUnd1`yj&mp3WZ(UI-AT!njPNwY5bB^+pP#uK@#0V89;d96zRK#nO*%n z(y&i;WZ1<~mj8mFc$C9F4gOV7f&j`j#;RkaV)prwiL?@wk1AwV$PpT9UZ3oUyhM18 zBOSFDfnsx{x@q?hfO8VZ^iTCMj?ws9VV(aj$Sc7(eCfh@aUpdhU?>MWGY-Ica)1lm zfiLGtA6bp(W>MRA8NZ2{!t;|D5c~y5A|ba&_A&C;Yvke4Dx2V~Tj<_6=6bD8pOIgf zdI_~^tfMb{M2H^@X0PSM#+L7QVjcbrC!ms1jyOLFdp1rA$7A-_bxE9`>?Y2_N0O*a z+vI1E#2M)#@!z3xUX~FAXdy!B^vLPd5tNLJDT0t^(#TI@1pEpH)$(y>ZDZr+hE#0) zJ(^hRISDN5G;M`^o$28c)pwCPPUWY7SwNYr)_Ig+wW4gQRn1gOT6p$(qBdP>5~8EX6dAD+{)rPPo)W1fAqU#XlstJZ zP=G^vgu29x7*v8Zh$(gGcT*kOP9p-bN&GFtSLdaN3+S6_;>c1m`0y(uoeqnW;B0Xhw#D`N&`e z7;7ruOelrYEsWJ!aZ0NQVev_;hgOx9rma#A%j;q0yr`cSQXIq5Dur&XHeB=bBAkOM zl*GpqNA+5))7_-IsWG#f$<8o3QYuMs-xr;RllSo^K;y!SC z1>s3-AePaI^KBQ>N(!5QgxUC1p&Prt>m@e8HCiVl5K%!~#uZYjlc4fXD7k|KLB0z7 zJ__Zff&93benudppiyo2JDu@|1=43yW@9yIjJwgKwJiS;EoDkUek(TDZ*E>+U5m3x z{uci+ttTzkXT&z&9oWg?{{>xAsfDV83~G?ns#?(&WoaI174;REX^>_3o{8KR)CFx` zN_SN?G{gHr6yS%b`olzuLB*zh9!~q*eTdoV`&A}<+qwn@81rJvuTT~UdQdE^3D~zT z0H`ilgx4+@(y_+k@rO9-m;Z~O6cku7Iw~4-WVs=7i0~}}iwN2p(kwJl1;r2>#Bj06 zB{$*1$+N*%0Qt#DG<5Vr=ud_k`5#adg%c}p3^~qZO^%AE#G^KKBO$)dpkV2k!tYS zxd9%HGVX{}yB#1XE5dg#dr5dyMkD=}jBByUs>x`?N^d)eET&=9E&rZVN7#mRa&3Wp zD&StDntZwHy4wi;(dRe-K``hzjr{E&+^{z zw?PHTQH@G+#1wKwqcDA!+P-!y*=m<&k^A+j^d=?Jc9>e&#BGTwF?CePo|r+SkX|Ju zN$15(+`a~C#b-zqSlncF%Rhy?P@cydnG(q#=7J1^rEmlwDglPlG*`)2i>J>m)hbJ5 zf*1&i(MU2hs`wiKIRG6-m=e0+3IWXM4RgQ%(ePf?O6Vi!Q^U&BOpegsGheDG%$j_y zp_m;feB*~m;&S@crR4z4(=RV%JB@>Vbb9_05{lUhavfm_X{Ai*Te7ycnCO?EP`4%} zA5bD~z8s9YByvbX(kLchqUyi{k>JX>hG0dqRO7|84?aUW_320AI{Z6F@=)W=uYF9O z?e}#XRdB-b#@TNiMtV~uM3K%h`9z8Gq;Gigpou{#t;(rsnR_omruXT9@}utf_H(!$ Ox*M756*Fg6^Zy5t;p35AWy?_g8q>N2oU%NMv%Zj z5co%u?^O5n47Jj|2@n!pU3I!1r%u&5bsjbMy1Nq+{(kSr|J~3ZNz#9!LhCPv%w0Uz zwjxPPVsc5+y|=8(qO9nOc!%_mc&oZ9-eEl~-Vr?_-cdb@w^E9g<9b~7`bg*rz(S?2 za#BwUm|E&Cr}R|0NAD^3>b(LMF7=iB^?s3$lm^O!`k=^1OUKGX`jE)SO2^A5^b;Z< zFAbMZ>ZfFB?*dDh$?elS5&jQZmwu+wi_wy$v*mO8In?ad&pehYCsfJQb`t!LWQqQ% z-e*!pc_QsCqjsuvzC5Cjh<zCd*U$lo;h$=}P&k zezkl}zgE7kUoXF}zc1iJr5oiB^bcgo9NL%k4^8FZBX-1WLD1`j`#t zx6M0dlAUCy_Cxwzkw4AOAU|zN2lvdGLs_3SbLeNzocKoJw_jd0FK^#JcyK7qO3yDm zQ}lWLyZ0q_mYw@jV&}~7qU9&%CsfCrza@R6d_MG8Vj4UDrKB&g5jKkVL)5>(#!!FE zOricFdyicNe2K}cQhNL+v;!B@vKv}8ZM6@Cf@N*98Xp1rIKNrg{=yvR5IS5n!;zRRt27E)$Lg^S&^HCR@ZK9 zD{mRa8e4ahAaT7$eQuiE?Y0CJ3Lcp;%DHm2vSaQUwY*)}G75EWRk@(YE(iTg?)<^e zjo-PM7{9Z8E6*6eozU<{rDE;H_1n+b_peM`Yof-pte;PR|5`JxHK>~S8`b8QUtHIy zv1wVI&2QX(_Vj5!voW2So63B2^ZDgx&pR7-G{5n!<{O{0%55}urZYMkXP#dcI2?hb zFQv6nZSK?A#YFmM`VJvot8yDiUrt|e{)a&2*~=^UG}Owi&iJU^#JHo{2buMvt<7A~ z=1gted|5DSD6P(?MJ2-Q>D`R}>{-TmE+F1?N3|-~o@yINQFj8FQmMLYGHrcN%WH*d z#pczLX3-|76wIKjXHSFd)2Ymz=a&e9Ad0woQ+2Vq7gV>D8F0&0fa3=WX-N zN_R6qcrNBKSHzwdU&R>dgsy%#H8rKbxAJIlHMjD;+{*I8qg7*hX<;F^VyxsAmZoQs znO|JP$LWQi$lzCflbP~mOb?kV z3o-ReX zxgj@{uVqp(p&JQQ7Gjt%P{_u^d~=@d;~#ZP3~}K&vNYQhOu6)KuQ%SXH9FzuGS`B z<5z;q)n!lFYM$uO>2^E=PR34Lcpw8kXY6vr%@oPG<%vaJaRq$3g%>1Oa)NhBbabRgTx zAqi>_E5y$M>W1qTU_+!KN$e3SEprXu_=O-Dquf~}kMUSgDkMp9&bQWx~Tm7MP?JZ%`WLZ6iMg+#fj|qZO`zf3U&{!zfo-y+rw>VSHZCm%J~6 zbZ)H1tJo6uo=*=sV7xb3mL9F635Z<-bHnNYXZ0rI9Q^DOegqS9Ej4?f}vLonzUQcL*(Lh7O$BR-@l{^Wn-kJBDa$K7~N$Y0uqA#2ZaW01$--;Jsp#YvvG zZSKaw#07I5%;YA-4lCG(z0N1m0l$dE4dMJrNBMaIj1V9JRwJoSy~>8Jm@iz#Zvh@x zHYy#|kNRif78+VZNF+s(6X3O&l2Ce;K_#NZj!!73JZJWjE)w@Ou<)Yk2+-#V?h z@r`<=U{|Xp%MBCM!lwQXy5qMfA$G$45&*I4$Z@YNDbt_%(GJ17O~hrC#FdRxDY zq$O>c4E0@s>K=mHuIdr74ZwDC7`4wSQks;-Nm|D3h$)Z&3ag` zsFOmzkM)au5Ap+SP~>}&KgNbcz7P51?1aeoBR|Yeiu{0(=Yv?|Q*P8(?3^hmQ{1++ zyjCi1ZrQsgrP^b29S0<7Ug8*qRs^|UBO#cbbJT2s+eo3W1hRv+I_+J0TmJ<+#$&OD zO#7=LZ!2`#&^hxu7W(!!@hxMUeKh5;D>O+p9))3~{hMYj1 zAMZKS**T^Kkn;jE(t;d>Je~r!qoh9DDyhu^4+XGsAC~rEG^A9j>|U`LO9`4ISh1e|Yn zP~$s*-2&|64%ltL?f`bT12)a>u`xEoW?3$v^SbHA>Xr!&`o)boXLJpxfThifBU-bo z8a`p)Laz-J(=3#WNWLJ%iOQhkyHRFt36Eer`2E7Pi*b>f-KILSKQf|2>Pd{XUT5 z4=54nbrX8_7B}+@)|eafvL??8qQTSOH*q>oRcf>t{2N> zs&%_ox7{x9Ee5>ymyhC zn)%W!)NPZsh}7<6u%nX<33pm;=lbeabysT@iAV*IMcdsn(OGMZJq-uA$)Tw;ZG%_K zwCl*+bK{hf@wElrls2C;K5N!s$%(4@QZa7{LFiS_2)b0oF2|1ZW=Tuws`ehV7_pX^ zD|IUBI%^9!Y7StTw+P))bo0iy{L?1Qlp$nG9sBH_C1i#9lYC1SQy&Cd+C$ ztUTm$NB6{99Zkx0%cdql$3Ck72eD0BeY@RcanfAG%$*+zBmw)sMKYM5_Wv8pWF{l@ z2SEd0B_unz!kkY#*pHUCg0qR!w$V0=Q13n53tLd*u{m+bYvToMXriFM!I{TCa1&^D z5!*PO4!2j3e@dIRz1apb0jFn#TjNE(>gN#JlgD@EOuw1Y+8F;BJ zD>Q4XS}!rpB7Dd=t=AZ~mqmNE1{2lf8RBH^sV}iU9_= z$EjRQ{Q*RSaBqm0H>PPP^rJG2L!kq`@E& zd__?!S{l#8KLmM0^3+43Ka&xt)oYoSY;t>jh!H>{9+{lnW9%Fu+GxrAYJpI@=~FXU zi{~I3d<7E_eY^QRYeEyd?g;O9Y#KupKC&Sg~-F^FBZ0l7_`1+@{U0;@1dh|^#y3N z4(UZFq<>xtZxUpTU<)B_vAWbktZL9H{An6&O*l0wBv(a`G`OYFBt+d{%lWuDQ98D2 z#R^VzdO4S8i&lP}_zPUQJikcG6ii5aw3^fA*R;p;tGR{G&U;5P769nG{d5X@c>^3w zo;_#g%~O<);-fPbc+euE55fN+2@aOE>9zS8Rt~+c0)Z zdt~Y0n1qlrHhHyPgB1mnDFjlx=zMPa(Zbq09YF5schwMHpB~WE@a8)=zmQwSp{Wsa zky@T(l6pcMZ(`Jz<$QtUoG_ma{&@p$}#-Is1msZ-fw%nuc)igL$y<=PY<mz!g_hmGEsA#v?-<@ac*pm8VafEB z5N>HEWO!vN6R_j^V8{PY&yH_Itv_tU@WlClv-?^9zWjyEqRlw$@x~LW5&cHCQVnS2 zR>~gO9)xDT!UmdM_AwjQ5QDA%ja<8cFGI~_qpOkJL4CerA8#b>6Z;DC4;p}P$R9|} zWFX4Jlb zbgc5L_In2x?eRwFP-&(bDe__<7?ME$CmW$5cqhM*8>xfzq4W%EWsEj^n!U|FY6*r30C=;Mn|8}*TF{4PUj}{7qgREE3`=%+dxGr8*Xl1K#MY1wG7Wh1X!V)&DI8T# zJdfJgBA><<=burcBhgO>{#`?OgI6CcJvJWZR#&I*=T=>n4j@QaQg`OoT=@!LL?f^> zc~{(6OTO~&QGewB<4-6N&Kue7US{hLiwqJK{!`QWHP6pUC%!mMarPi?0i{@Il7LP? zp%kY#od-xOuvnJNY$+FwF*GeIg zNOneA64yIZ+b*$oQ$B}Q&d6ugI@gxPGUB|4Zc4@-ob|$xCqp~yO3wQuW7Y_58~OvB(y6u`T6Rk!3m4|7x5P`!&KjGJr*ZbS7VazN{ zudYITB*3o3fI^610wq&Vdde*P6=r^i4^S`t{=lSCTL^|CgsKm{J=`gF4EA)jumj@w zfzB5uvSHj6*r4EKSA?Qgetiakg;51413x!BH zp53S~%G&Z*@4{MvpGE9ePmnBaZ3@UB!>g}%kwEkdo^YiF(GzVEr4O_M=|&sK$(8TQ zWj#z(x$eDg;6=ex&%NE|=7`6lKSmSlYa|kQnEre5^ivK_?u0TZ$3h9{QwhQ2^j$#> z(!QXrg$BX(g9?35DhX9c0;<>53mEki!9O|9dqoc4p~EH6CI(rN#GCZJi1I}bg?0~c+B)jnti7kfIM)1={M4E_bE88J{7doW6k39t)as)bL7&`N9UuTA< z&Tqn74wB1$@ks53My0d6A)O&vvvZ)@dFbi4@gAwfNEhE88NwQEk8Z$LXbvD3LG5qQ+j;xK!Pub$y1YkP z9`z0ANMm3_4oagw^g;uX8Ok@pXnkN`JQ!~b2zyUO`JbVWG`$;8GPjdwmFv&?d{$us`uWm}F^0YsYs& z--P%C@bAWZgk2JKE~Cy=BhDuFm1f+&vVFB7v5eSn*J$SUb(%T$VH}n&wM{mnjaUN~ zbEBVSUw8R>?Bt^J!@zd~O^ozTq4oRzVMt)lqhp9$4cfOgeJJ`ZJ0n}G7OGXD>x;gw_;j7!g)`3qr`zAE|qCph((I1B-O`FDs3YVC7YcuKx_nm zBtz)Wq8kaVi0fCA0?&=!c_z8V&sZ*(TmBhCWy`?PKl zH04(iTf>rdqJhCaMyOL9BK#@pI44?Dd((@Dc(ZUGCB?lnU(0OWtZ>j2`BA()F&talW_f~S#pYS!Rhs&_uT^0TeIp_4U z$zgq#h5t=lGt@-b-O6UOiL|Wuv!Yci<@XGP6aCP>qY0f+6UG=>udI%U(x%@Iwi$Pn z1htJIZh#N`ISu)9l#rgn>CT8_`PR-7f(sP?SSYUZJl{KF6~C1~5c5E|26qNq_7MU) zN15QLfm_@2hk$Vr7k3i2V7QUxNN?v>i$^rr_jL1!Fu-jniipAaJ(c}vLbLfE%`eZk zss)W)dWhFiget3t1EFm^JB!g>8=RVWKm zs5UxFCW;sD7fw-dCCLkDXkvUDCa?41Bhijjw*YlvFc1%q)1Ysc7HQ|ir*(J^sG%or zJW7sP*?`@!yM%7AinlOmZOHb0`2egY?nNn!PAFThf=ft+g5iu%3oVE54e`{ZfNk8^ ztx~?c&hodvK*xWK7LqgiQ+TFT+dUcBFP=jt_hfBl+7KRAMEVe&*83jkRzA^lkM0|& zYCN2tUvxv&jSam&fD5zCfD;^7RCQcys?cTEm|zuM1f5$n6H%@X)*z13dwkzOOVdTr z8kbb*3M0Z}>G$2_gXvYHHCEdiU5!Ef#`quZ5Wd++`&c~LA8jCsmizp_Lx= zRBWMLlN^0RZt6*#$TpTq+`eva1~=+!@17bS$T2rYQh;dYMiIBAj2?p(>qW9vUai{v zBO2zfBGF^(#R@a(ywoY$y%@ls#rLZu(|-*aiEP1;XCtO?z@(JHsAq)=3l!x9y!kO) zzUqg)IEZvm)(C=sSf;Q}kylf&AbVkFp2n4|lgQE6q@tqL1Z>(NSe8_d;A=`gi)S#5 zyhAR~c>9?hNeEgH2EB(XuA`Mh<+V;a!xE_wkSKsR`-6`v+VKls8yEqJj(7wG_$ z1Z<)aYDVnPHr+D>ts0Tz(jn0ccUB|rs6j@e=TE8fJ!3sjhlNq~Zclpr?WRN}!b)5c z^~>OH@9M4KfBv_D6aV{2;9LEtc)5M>ymG|a+7}nx9^9FMpGWjWE1~zBFA?m=ZHe|p zUN;_KgZqEMnDDf=h7;$7NQ9d6k1^O^A>s;M3mb9}%zgX%*f?@ZX@;Z*?Fz z^mYV~;1X<2BA|zhNJA}*ybG?tE41i2kOgvT2XcRx(ComF|62mQLA-wf*x!36Zozgr zg4@re(=a+cLMKASr_)=p_?P(pJMY9I*s1AbZz}DxXs8eQ_MBzlb}m8-hNnOC-^EA% zPbi^CFF#JnFH`a>lpIh(;vc`{q3iUxpRiSBLbPyV0Z#jh)7o(&5+@wn_JN?|5$oVC zzW)%9Fvk#o2&s_cs*?OLX~xu8BKCPQmWa$LnhXbWE;0E ze+2JN+n#HJlWf_*ZBi_|>Wr;HTZe`Y4Fy-epx;n|l*^XpLw030U`skAh@*)N)*m6+ zyTstYIgk#CL2)M>Ml)Op!i}KX$Wzdn0>N-vXmDDD;E4LJ=d!@%Y!NzYgnnK58oYsk zEdodgAgc&Avsdx~0!|Q_YQ^#46rOGX4uL7)>wr^W`WwJ-Ia|OM{kl=W|03W~AASSy z7+}8*Sj>lw_;ure|32U_|3x1OD3^Nj!P?rgvHECc z29AC`E=m;d(ECIdH#kW3nxC7`&Fb9(w33^hU&+m^>8YT`+|r}PS-n@3?@iC*S23SH z%B`;XeR#i`F>)&_ODnt&Xs08dZbcWk+^Fw2^&I}8vbCwl$s~bl#Z0;ZZd7@3lXPM? z0`&3QHBTat32SV$vL&rOW>*wQdSG(JO2HKd^ zJ^i?YB9{Db(5N9mz)Am+0JQxfDE>X={{toBMEdK<{UbujJCT5nk~+r;nqKBjspgxiWaLwbhtmxZ{kRXU+r^TVr8_^~ z?Je*38cF}Fh*fcN>GQ9sRcd|_S78{of#p za2o#yXyir<)p894bLA)e&j8@Tdqn!I?)G?d^C3GSQ0JxO%Oh?8*c{{S*3^n3sS literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/set_default_site.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/set_default_site.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9546e36f111e8a111e16490764128f728e395fca GIT binary patch literal 2391 zcmZuzPmj|^6rXYYFWF>SwhM(;twvQrL?X$d2h<8sf$X+OCs~56}bL=%=XEkI+-)YfrtkQcpegJ=R!hy5 z7L(TCF^{uNNR%HazmWMT+sSH5CsO!Y&O|yXb`q@6P;BR3x5qB+%%W({?#+TI9E5_i zZteu@fv-*U9Gzy6a8{nnZUr&h6KtkHIgA-3d@qax9VRh*66$?cM51X*7h)`{Kr%b% zp)+(#7PNCXNC89xQL&}xF0;~FdKMIuc{h!Id-*@0P zQgy~MovTzQ1Ai}xMSmQ2xD$->~yd2(pM=)!2jScTEi)rGxqhH#QR z2D=(sEFAe-*Iur@LOomk1oE|9ZgDbpHQVTwcFQ7PkBy z_B2NgkRs>u21wl>socoDUtfAZIyC_K57>PFyOrMH>qj7uUEoe32jfOLo`$_oQ+O}uCWU$tyOb$$@zM<+yiILO^I;rt>5nL-oJ6@&UV+oarf@7 z#4nxq;k#1Wo+MmEO1_U8PO>)=eZZ8;P-ys&+`hl<-|l+#F60RAvW*$aDv;#NR!M&> z0E|HqAyb|Qd-(y7%pQahd}%VfxN>GqWf<$s2zj$AH&Md`@KTvmB&s+XPz&yOvP+(Q zuTgB_kDs80JcDQC1fe6d_aSVN_!xM#1B4hgz>&IP&@H+FsIphU8MVyw;*~|d8R|idhRP8eB#_nfZeObWv^pRDFj>yFNC#T`43ZZnzaA` literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/set_fake_emails.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/set_fake_emails.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7bf6e18765d85cdfcd1c552e9947c5c8e649addd GIT binary patch literal 3040 zcmbsrO^@5gm6Z4;E~Wjjy>aX4SxUn=YOfbu4&)n;^Joj@*xcMIRLH&8rOL%)@QAtr6b;s+cP6DD%^<8nH5+w zJFu&@89TF1&;i^E+=m*sx$|7(j<8PK!5Z&;q4nMTAFdJ^9kByJ#f(L<^5@5{OW^k~ zIuwM(FI$N{kjU8KshBLS<1hCQ(9IwV#Va5vTK+NHQXl z!$_tH;y$^jh+2e`J0zP#iiGKG#u82dO_TVTutSi7?Z<+AH4#a55=e+g`@4JhpFBjy z$8sTj*Znt`MC2 z{q{S!H(@i;S09QaHk-%7hp!=Cb@6LAhxJ6iCF7sB`abBv!AM{?5y=ZD5Y942-nn&K z-6H$Pgo_bd#97}bpQlPiXvaB|pifpgQHr~jKT*RwWE4r2(Hf6ggFXmbjea;gFi>Ch zX8@UYs-5YDey;0Up-(|)-pbmj=L?9yiUOKqobe8K`PvJsp?bUv)E-dRSEw6&lWTly zW%m_+6)4wMDBJuspj=;}yv}a` zA!uhT^ZV`6;1Ii|-RvxliHPTUYrt}MFi6q?lSrO1PoM3WR8CUc9c!oG?&S;S38GH4IUp-@E zDaT+e)5Tm}ic_!iPglixRg{XyCzy0~As|Z31sD%ZRaKQ4#Bu~VNb1x2Ib7Jty1ej0 z_KOQwW&gh~1lO5r0Wy_c#yMqjyud1^N^f;pZtdOn!(E{cvUEN?WaEVz z9zyXP#?k(8ewK+UwN zu6h|1j8pv?6pgxVowT7mw7BuQc4EM6!fe89!EC{7!)(Ls!0f=>fw=>-3$vS~rnJD>_mZ-qhi1+DwHow*7M#XQ|lq0|J zcC|nL_M}%BMQ^$W!-LV~SN_u8)`}kO6}_|db4}O2)t_#Esbw4dYT=!2o@;mmG;}O` z*B<3NpS|2Nq4{#LzZes2eiGdQQD;8H%#>Kk$5RZ}^+&FgoE>TgNxNu^nJOlblh+^EAJnsk!MXy0dxY~okFU&-H~ zX4t&~JKdj(5Yn~{FPhSBN=9kbLPCnq<0zAFAU{FyCVo zXf4b{4>EM+4>T8Y7xNd#RTw?sS;aiaY!A3B{09HLcag#M1%0=4X!R1Hv~(#xo)$4U zy7VZ0x?pkRy4OI0s&NI|QaoKmQb2SZt4z#jIDy)ws+uA(_vH{k*=;IbDB_sXOYQo) zyn#%pq_hECg`qG+q4wxT%X_1uKI(g=O({=9O5w>`6*~0vsEUK&$|Ys#``X_(mtUmt zFUz5iZzzdx>Nys0oZ$^<+Y6V Ek0NJg(f|Me literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/set_fake_passwords.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/set_fake_passwords.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca089a5364aaa2854bf56ffa8046f1ddfd813a48 GIT binary patch literal 1970 zcma)7OOM<{5bpN)HQw1JkYph|L@N-9k;se$5}*j7Y}nl#K*=f(A$)0h+&wd%^()=& z4QtI_m`FM0KO{$f1qUR407qXrapcO0Dv$Spa-pRzSG&vIUsZiozO%U*5Ey^_`Zxd0 zCFD! zpE5H~bbDZw3kGVDr^hThijp*%q>??I%e*}a@Ziy--Mu@H@1o%&1(yfGUl1KKq>bMh zXwbK2;28qvSs`RPw3>}Ok(S>AY`CQvbjqGmg#zY2Iy3!MlaG#MC4gKfDCLsphYrO92`tI5f^!645 z==y&Jn|*TqhQ7`w$4tm+RHbIPA6p$Te0neuXbaMi6?sXQ^cAIKNf!WCSO^b+y>PmB zzzow9eG$AsCJ_L+aj*7o-Yiv-m8RKTKi3Qq`%R!tp(HmD`}(tk)<&;0KbI_*PtTar z5~VC5m&lloM|x;Cwg8SaUWdPNqu3-x-q>@QmURFZcU)|?I+O11`UBwEnk|t&b^q+T z(XgjBz;QJ|u>}IIa&%Qn)oeyW@JP)nWS(vY7njY|-M#&t$KOBV`#az5@q?X*4}ZA- zU>6u;Yne_Pw~Q3<2uRZBJWc@{=f9ADR$~C8^!QNK$GSGfluwFW#)rvxSL#Dkl;fjl zR_XB(aDJR7lW}=$=0*Pb=*zKAj07j+!)PY;SS+G^R&e=~k-3IA=rK?bb`a{gBcvV! zKVC0X^(J`vHcWj91fc_JQz zs}-S*{Aq0LQH>K9Rc;ifaxLD$uiZKHqEvnax_%b~v0O;44{7!x(ShZ|+NA-#V%1xx zsa}6F3>u&FJjx{JO~A1SRw?QO&Yx6Ky53Qj;mo#D!fhp=REd(B>tk(X#^X6~S+@jJ z@LMA4V-U?|R{^n1Q_j!v4yoEkBZRGxS9r2U#Rq)0H5jyS?+piy$GIqC&fzE25`PpI z`Lqpvc=`N|QORT!Rc79XKYZ_ON6FE7d5k8|(iQ$C+kA!BU#q2y#+6A@y>_N`9O0e2 ba3Svg*XwwFgQU~gPHc$zfL^i&mfiao8F?-y literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/shell_plus.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/shell_plus.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4f771cf10a2d51402772d9e2b7e382bd7fad5258 GIT binary patch literal 16473 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 D1R7{E literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/show_template_tags.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/show_template_tags.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..877b7754b0c4163017cc7fae47e913149214b07b GIT binary patch literal 3801 zcmai1&2JmW6`$E%E|*J6qGVgKfubPXxCn!UY||zN4A+Ql*+B}&2^yzv7fu%|&XA(C zAJojymWU-#Kn9W?3ZyypC|!#7U+ATm9DC|(7~3m-Qnzx+M6=tb5@FWMvP#yz-LCM5C<@inLH5ns*W{ z?-p5>z@XPoi$ugG8O7;%TP5lcy!BX2v+OX|<}j7*r)9|H%`e)Zrmf6v;Eb_tYnbh zdD!(T|Ni?A9^Ly%)%@VYtxq1@iyz+p;9liEy8T||qk8cEovx=`>{$hQv5=;!YiSZ= zlnTJ_I#taIS$V2RZ0Qc*o{wG>0-QQEQLp?LaFy1b5IoKQbx1`=P#iai<8BKNn zsm!1Daqa%((CifX4|>=8dTivIlVq@$jHK?1-6S6sF*GG}JuY(Hhek1y$=vjpn$Uf{ zQ#^w@vq_p5NvhPn$)Q?>BqWU{K^YHt$lKg<&veHzK%QrH_W;DH?u@hR3N9Ss{u;WA zJ=^!r`Ze3Ho%Ma&_s{xutKs^?$Ul^6T0HCW$lESb(S;KaN0nDhjE-s}C1oDDN(zjo zQ`rp`x^7xeS*Tl)X`?Vp_T-X5F{GMQwWwM_)#a*9G~ISlT_EZbsw*g(CXxc$%by(? zkmJxt3ZPTS&iaq23>@T$A9KM^_}n?zEFJY~=?Lcv)3*H)+iyQ+mVXm`7kt}-|Jq|_ zoMTsbi}@$cF_d<~f5kuNYS+|0<3lcL!har=&XKd+`6jha8I9p+o$a(3>~)G^hXU`7 zj#1+*8|R}=DieXWZ&Wf)LD#LlxF_^5`DO6-m!#=1kUSmYg3 zbdoe(EbG~Q9^v@OR80ykX&xq|(sZU8bF}FsSSaLDvIHk}vT15a3i*az4k0J0d~<(V z7%4g**(m8~aPtvvknEBCgG5PO%g!I?0+EpzgbKFK2U6vFA;^v~lN)`+jF7!#V4x9= zd9nw|`$`VR6GYqhfB5!0*Wc>fohlwG3Xd26#5Z%F=+_6-rH@*27;-XAQC6~J_Bk*c zrgmWj_hH3e&?JCXT}edcK!W54sGMi|+(WD2W}0N%BDr-Pv;U65X5SuKyT#U8y_>LE zlImL^78B2eIE6hc#J8|=1Tj9nIJb|*=jg(*m8Q` zt2|OPgbMQ1n)4;mz7B7ag`l0ut=rgL(|JCdb^e!lr<1#N{q z3h`b{CzYEelgisI#yRk}X0NHP+7;H@B7bPxrJQz1(ft(Nv}(P4J}uKU#==#175IkY zZgP)rc&EJ$N4$?r5mNmn(sJJqIgQ<;P9X_*cy4z`dJv$JqT3!7HEVIoAlSovd;fQ-)gY-4%t z-udvEAJRI4F#a}UC~szr0nX1O8Oj__)5 zXllRpnC<@qSHnwMS_KiSLftV zaGVpayb_Pc6=arsF41`Qz+J+IJ98~T zJ77OSIYo}Er%tqk_av1sL)$5K+@IBNPbN1y*Yu-VKxrY7ik|S9_b3_NnAPvw*t#*R zUDFtPLAQHBuY32hO>FGLu8140jiiZ@md1DnhU1a0ygbQd6~^&6n-oYtb1@N!4+RdYdYnj8Gm@dDZ|VP*q>T zfTG~2d~7O;fyE-#2d8^My=7M<3bNIa5K(q#)0ikc7dvu6M{6(HH_i$X1*l>YCu$Hy zvg)XT!sM^v55dO|`C1+45**nj}ZPKa;cca#F#uPb> zUZk#(tAorU{~v0(bfMPK0g&R@mI_K3Hd)07s6QmP_nX! m5rP7H|No{giU;P&~!O!ym literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/show_urls.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/show_urls.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..77d1b7fcd4bb461cbc4ecc31945ec0273e91e559 GIT binary patch literal 7636 zcmb_hO>7)TcJAu#`Rn=NkfKP6mgTnoM<$1|?8I6{QEZE{vtF5UBzx^l?2Mb!O>)Sd z?om|@MUHxcMJT}XL5UVv1cOXZWdBx|UXT)6cZBwXCYA{9MbbS*?66ui9z9&??r7s-E#n zt%=%1t6VFqcGjP4P1UAUJ?9^3P1mMdM{7r!_O|9)ZvKJh=J)j43|a-Zh*lA;S+q*- z1X>el&ADZF@_|-6=1#ds@Sk>%;y?5KbZs8vX5BfAoAazaqxPK3?r4=`Ux7nyrNZK@ z@T6=8>jL$XXtvsZb8WZIy>)K~kn*>i-o53}6Dy&-vC|Z?qR06+9pPOMTP-JW_Z%rb9>jUn zZ+jy2w>{pVg${oVmDllz0t!!~O~Hl`LwY=Mo7Q}QWu;=o*?K*2T3)>#TlIP?bUQxP z3-$Wlj^igiKhXFjkg4KHcj*J+aj~?;ySt(*!?pTq7QZ}GZiK-r)z_9pQ+kVSr?KU%dt%Ambb|G;?(Ik~5DLB|44coq@EiiP3;D4F#YIFa=4C1(1Dd&q;0Z2+G@6f-8O{eai*Op4D^Y$ z$M_@G;s>*urqw z!ojeG@nPRm*sR?3Fpxa-eUD$UhjXkP^wM5|Dgrj5V&#^HR0QA$B&}Ghq~nwe-SOg- zbXIYAGLDZE82iNd#sj*smZ#z2dtL)Of$7w7NX9_nZfz)US4jBw(sl;+wpxnT(jkdXM+{H z<;cbc42aFcj`W1R7IM|s=HaH-kky6~Io6=`8gE*dh)_svPwTUY?K7rDY!e5WmPHG4 z(~nXEScVowR`3z*tr`UzNS1G1Bb)aKmRCW^?vd4-kw)L#*Jfb#MmXl&WA42BoO?Wh zxf)n|ex++IE_MPDa_PBUeX$c;0{iXNCGWsije4%!!6_w9g*}AXs~u?z?4})Z*W;dTdady;t?N;FL+GG|W!ltl? z9d;vhJ^Oq|cxxSBNx1p)#T0EJ z)JJ$h1FWps>rEIodo;=p1A80xUsOzflF$>4IOBS2PRExCvFzd^HXJ$tN^5Z;sV7#R z&(mt`J7oKZ3Ii2scVyMRz7aMX9<=@pgp{oPJW)^#( z$4R<=YvrwO<&Gznq75CGO=pZ|+1n0p(xI_sXhUX|RGbo>w#Vb5ULP}`3t00-Jivz$mSuI5 zrB!LEGRw+K9BRfo{jx4tL8BR%r6LC!AB|0a8DcPRZGXT?%X`i!) zaD7`jepBjwl5O^ZlH(WTv0r2c~_trqAI0#|%A%ExnhH()@4TVh?ko z6lQ0DrG$5OUF+p!L8hYYo-Td@Toe5wwf1$Iy*n?}dZ@RlHF1vD*`C?Uey9Z>nVOu~ zvK}-34%2!T)4G>|bMlx5h>h4r^UJ+_lsTpapHsd6 zir(YB$zVajk{SQy&I9`V=J6Q~JyY^T{{>j9vb3Wjq;B*k-Q)ctM!XnJ?(4m&XyUQn zw%syTeKIP6{t?=zs0`jr>`ZY>f2{NOqg?+~bR@#)$aJ6ozDZU#xTc_)&7#6+^iLDk zeHI!0Gr-OEb=1yA6AE%JI)b<9o_J*T&+ltA|1rD!>4&73FJMP>@ui|>fZCVRigH*< z4iH<>|4;WtNJxuvN)EN&+CMqln;GG_IKnYAj^nX$_W`6b-OB~%2l6-gPop&W__4gO`BIc~Uv@7&((h>U zLLaStL^19wp!w*>|S;fu#3{1huK9Juu@u(otMr9pZ{mIUYgMV-X)5kzTzRo8(4flLFrgQ^*f&*%RxkkN6(3Y5Up=kgG^3 zt#wZhjn)Rjec!8I^(p8R*H9S_k8?NQSb6({H{QN+r@|`w$_hUR1htYMt~Udu5_daI z?zy}IV0ZB?h;z1!^ui88X?v7lRP9@B@|emuboB-MP=v!z013Z9m@dKo ztHi}l;y3$#?*P??vkmJH_l5uwF(3jHbXWN?OpJ3#Q5xPVLUm4IX7_^1UF@*Y=y0sl zzPHgN*THuwsDTIZL&t@mB3~8f>-BX%T!jEAk67yjjbVGVO%&#gwu$0QwN2$70v&8o znzrZ{wnyi$(#n{NZTT(K4z`8AhGrMfa6cxAs0>3&8XPX0j-SN&muQ@MMx3v7C&0CR zapw;%E`GyVT>IpuZsz{QUiJRVy^0wdaHerOkr=1QFt$eip8WhZ0%b8s1;YHd(Nw$1 zU!>Y`6o(j118@hAILv5YWzG8oJ*?f(Qg1grQa;gx4+f`*T47nRxe*&$g~1w(u3_8uNMIy^6rrbw6dA{NCON)@D8eD$ z*S`(Nb{CExrao(g1$?;`iqopX?1No^$lGJoWD$O`$b|c1}g z!r#C|{-z?suhT2h6h-+dE|sSIHOBnfn!;}+l-|ONzdc6vcL{KiIFDHU8^8xtV*_z# zoPJl`F2p7!d9{PY4jK^se`x^!Cao;le*O;X$PJqkiRM!ayos(K3>Ro>-4~y^?L#H$ z8jCM29@;L_Ri&phs6bCkr0fx!*2eYo30quI#D|+ii~41&`MZPFjHvv2r{Nc5!N2tk z+CMy?{T10|Qr~8P+*-!W8m)#@lvbpS3tg8et=jKr<=}Jckx1 z)4|Dd#aYS*w;hRee%+Jgn>Z2Xm#L^yK?aq-iy}@ZnJHhQMrOkiYB;F?U1s5;4v8zA zQ0~S~!&4rUe}npRZQcwdZk`(aD78=E4hsHG)>S4~U*lnmuAGJ`YMdWy@GF?198hdE zMKci6L1q}|MlOeLT$Im=O@fgiksZkc4;1U%!`)10H8#1|=E?07$(57Y#3{M8{K3r| zwS4lfue|Z@janAxN7eXyG$w_coo1U;45GX}?m;@Owy4Z<%Cuq=>6?f%VG<jc%HnK##9yJ%^l2TbBD2^Dy@VQ4 zM%C6C{pSpVAZgSonY55V>TI4(p+<8S^a7hkvYDkvH}xsKgoLvIC_zf9O(QMcVl%)x zhkBMx8`BtVu@aj?i9Q20X6mOw=eRx(n8{9>X}r@IW9i+}VY8uvrSxFbHDr@aA|Bn-`GeheqSU4#E>hV`2lJ7^mtEF3BZDBwYtlhF z=|e`BLN1Ys%sxSoRYsXvElRH$6tN>qoH3F6ZCU&~49=2i_X~9DK|_dn9<7MlO+3 z)V|m~naHAlbRS_tvK~kTavRBHE|Cei{psR ze1#*r#*iQ2o^i8LD!CQ7TR;|syrYuq{<(#~NBwSlvcm)0u_;}kYan$FZL&jSz%e6K zwMKJqIE@WET%~J7x>}=n9+#a!hbUd4!xfnWF!#Jg*=hT@T|GZK*9#bn4+0CeN_R#$ zRWN)7F_jAb;S6%rFK~13t;EGT%yJ$1jZf)8T%b63Xen!xs&gFFT{t5Sat^v>b8z<= z+N;Pr=pt}1b-)5F*eVVSr<0>@_f`C@9GSY0PE2HWNS)J38EN03VgLwaErIzrIOarLDt$xqh- zsO6JyKvlYtR9?Pz;s8QPDXsxq2t>k$sH!u;4VpGH8pORSym;c|Rq9E}VG`busK%nEk=n%Bt4U6Jjf5b`W0TLy!lxx#QNZrwF-j)=v#G>SQkgaX E2gR65cmMzZ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/sqlcreate.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/sqlcreate.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a58725b90bd5b06c742036778a1a1dace236799c GIT binary patch literal 3669 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 z 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 b`Tr*Ry8FH_bXVUK2){3s@%0Yi5o7-g(QuOt literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/sqldsn.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/sqldsn.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d4f6c7d6b0a3e9ad878fb9a64aeea9948cd336d0 GIT binary patch literal 4236 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 F{vYxy6gL0> literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/syncdata.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/syncdata.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c9b67f4645b6914c3291835fcf9f12d6edc4255 GIT binary patch literal 6684 zcmbVQO>Epqb}s((ANxnGUrV;^<$CO~d&g=GHj|lT;`NR_vUi>JI2+ru<1jG@s>zlp zvB`E7+m;&aMPPZer$Ll^4y_=ED@U4j2K_m=jegs!p}*>?4_Rm4!D?na zJPdnVPV5-p%YTNkwdaI8k=cs|11EG%;Sc=4;bt6}SAxiKT|i$kw@0z*1R^qBFYsbd zbd8(+*yH9E0fZUIt|Lr73a^>*u4mHFwj(_AxgP}PuJg>3!@?P4b0&ZZuJ0ejBkq|S zrV}2BTnnW z$QJQo;B~aLy>J&u^)vZt%ICUII@S8wP7&gau;-( z!ruvs(K0XxVIO^Nm5eVG(H@7^oA4kK@XU@(@Y(DeCXPbe) zy*Y$LQ0O4%r#}J#vHR%oy)9UUB zAYkem9fnTD6i#RAQM35bi9bOR4OAY3YB5W76?x!d2}o z-XAwNHpIR^+~D3IdgejNVo+=MVP3qnoDDu2f9vM6$al@GOR8)}+j~$Tv(KY}>27!Q zw47;Bs=J2}ZDKz1(q@L%&Zh2+Z#+@3lRI zStYAl7(M~qanv=pGU6fkNZQ4V`DrfBR(3loKMUFLbEwi*E=W6Yw!J{SQocWa@1fl6 z@C~~vr_HNU4^80>9ZvSK1C1$#4&M=}9v==piL+BmOJamh+Jv>WF*_n17HQ*jmse?f zO~f2}s0%OXr)6LTf5?*Ab}w**usS@R&-Bq zCwhef*0H#Z@+pe=HL8QJ6J^Ry*cN;8_Y*DA_LQl5!X`SdAg=36mgrkhz$0Z+!U)tA zBTAyJ0bY)llhRaA$|uUCl2rJg9DGRdPr8$8Qr#;hmHje*lvJnX6Nam-y83>JKZ+}E zDaQPfvH~0md-~`Lnk(KHS^M&4^s516Xx*N&9L z=&Lz4;|u22pd!ZjpA9qrZAo_v*BeN&W;#HZMs|x!hmHgPjGG!pF-_)hb{yIJo;U2y z@NK+3^|5)=95_Ss`7Ye4M7r-C;_9L!Md=Chx~`mg<^&_U)|hi<7;&p&6K$P_o$jVS}xtpHH^uNn-TR5eZ~u!aNV43ADfp2C$IMnRpVwcds$%Oey5r0B$>35 zA0X9mDWHg6oEk+m)PojcZCcL4o3u3KFfaTvjcI`wS|xkn#g4W3%;VdU@G_s7g&$Vq z^kApX5%aQiu3%SwlhRrS<;RC2pmfBFq=l{oB zFcWzR$SCUnJrwa5sK^s0%vPZ0${Mv)wA3}muV&vVOv{N9!az*4@uR~_u|6%Gus=nt zov>*+(GvAURTvbT{XToZ9-|e0M`v+m-{6S?W2LY$83z4Gd7%)Li?N^TkJ%rvP$g)W z0b?y;d+Le8|2#IRwZ^7(GE0v!3v*GrZ&eFJz%PL2SIRZXz)pjcSBF)nurw`=D6B?r z82B-#Q(9#whO_D+=FOvc8UJuHvsP=zi*08VN8~%Ope9lE0$iI;DZ3oH^dOaJD8pL0 zcdB^@y|=|z-h~ATyq^GrRBxtMA)~WWR%eyAa-rN%#;rm^8Su>R(}_r%r25>#!z&X7 zEWQ-P1VPxOgi_vNlM0DzQjHN8OEzin2Q?X-5gQ>Gvi%bSVOj~^z>vNAv377HQMTBz z_T+;}BWX+##K9{x<4V#zQrzmk%3manNh_{SYrr=be&AN7M$&|^YCnT8P876jYp`IG z)})=ZGdTEHHt#x@#n@%<6~jxZ&25R?^P=zzZdA?zN_K zNecr1x1 zkJQO>vIq>nNS3F|bQy7q`J|QMDo%2&gmF@Gs~@omJnD3XR0WCwmD$&^miVwh`{t|i z-4B1|v&jn1Tb-W4?DB~UnVmWKI5`9V{N2fFvbwjrw>DWz){>R|%CXAVrIM~BYu8zV z8tQSDU}&#n<>|jmAHBE+KJf>*GfR1kP0s;ZBlSGEE^&VV++|5^IjOj{5?f=`(-`np zGn{*C@&v2XbvpC0`t|Yhw#aB@N8FqJhvIw=`hT5NxFZ9)Y1C)HNV7vw?ecXFzdI_3&IjQ0%ttaa=H`|eJ!x}|Z2dl|CB;B5zPioV5lk-xJ z+S7jlrwOBatn<};mCkQq)md5ABZ9HYA-!_31YASq{$&D{CJDG!HlnZH-Y z^#IQbn9<>l=Y){3m)ZDIVeks$dny*0EqH?@vgVScO9e^m6D4L8_{v&C#H61nE;~^( zB0Gvz%^wN^;k_Cm-lwEMs_#X9$Xh@|FXz5bujL|sxr@=aj=+BxV+SZX?Wxk`U39yF>K`W^5{6`2%$F}R-VGVdIyrqd4j0@5bsm0MOf~;-OhON0pcr}y8;uR zj=Zpkr|H6LoWwTZ>yEGF2gAuP7ttpjkY3gp$Vs>?I#>C3>3HP&`S(#FUo?S@Q<8~%e!9OFw-=vC?F#JbU-9wd@ ze1Q~Js*@6MQbVh8=kDW2pFg;5Z{2Yb6E`ZY^+!QqlV!o$j57Wao$`IEeut{x zrb=>C@vO#-XYN-oK3x7lA5)5@6U*r&E zMxmv)DePC5RGM#NjJ_*aw~B8WcvfZbNnaEfsG zJ5y>q|H3H((}OTJikJ5aYvDNJmcCj2EL6V$h21#;)$*{7OU%x1x|CF zHSXghl@0nLQ@34Q6p?9kF+vKRY2ND*?qyniE??C{Vyyc*)!U_PKd1Lo_Iz0XZ@_v{ z0Q*6n45`s6Nha%=$=c46 zUCs1B`UCh0$&o96fICM{m9LyQa)k@8Ct2-Ec;t5;+ppg*KlVYp9U^Fd{PuV9uZz&1 zW^maY0FR){2?&ZP<|sCQi{s3SEo`vO?aYat8aup^xv^X02KO>Q_Ol=k>aokitQj|J z?D1CCj@uZ0f~Ze}=ZFT(U)php;;&FQ{0qFHqb}A>%0^_)6-|ca8JluGll z>{_~cKqULP$TE^s-P(f3LKFfN-K?ODn=Ngbj&s6?8^xh35zIEWB@7jh8WzNwhP@H$y4a^ZJ1R^VTzZQyrC>= zE%8rS*-KQ}i$mqC8VXO{H9kb&KlskBoT^c|i+iODaT)YhNV+_Yio_y z7^Bnoj?wAeW2Bm@wZxUbc&OT|&KkkacdB44I zazv8=j>7LncpDG3%d^ z@m%)LSbo;$>7YM5SCb-txA%TuLUM1-$nb=Wne5Xk$;U;)7K-K4q|=9s4l5bUReyV% zWq+Pug;2*Od$V)xPT)=8%-kn=9|W>O?AtEh$05Gs__$MldoU9MGQEWz9N9kLi_Z3@ z_clh3x~}$<#FRTpbeNc9opXa*NpdY472Fq67DEI5a=Hp$kEikq7v^vvtGA=c&0u*gR>TjSeXonawZ@2W&S^R$Qt*sb{- z2U|5d*ih|_|JC>U=DA9_+$3XSzLrOwmPtnYA8sn~(2!qtK=`<2wV;%{=5PN8VR_5= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/update_permissions.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/update_permissions.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a94b05ab76b0f3d4dd9f14225507c0b81c6105f1 GIT binary patch literal 2545 zcmZuzPj4GV6rWk|AA7xaoHT7|fz}kY#ZqG)Vxz zjo|tHx4*qV$_V`_Cnt{%%qfc8 z-u5|NiH1WzBrvV;UN`iEb|z>`2Tq8QT#aD2@Dz10(MaL2=<3uUIx!B> z0d~!&NJp*(ftab4pD_NM(ID~(ug^GM??kN5W7_U@dX&^roi&EB~ch{XLbpI;XME;C4s@Zb~PVi&WpHK|HQ3EoJw% zB=@B@7ZIbLU?X~We0g1(%9iWuPQ&i(QH?@s`fUL>omzx;{81p7Bi#a{qnN;P%INsK zvXe<(+i&m@q&=w-xlZTJgTvj=~R{AGLT7T#Wtp!0%Gt zB7HyXMjqV*EGqc60D-U~eQM?Ku(!Y&^V; zr4BrD1JpKJhru^NngA*;Aa*T#PobKR@uVP8a)^?`DnNLmhed&>+A*5wpk;veEn4Ag%isYXMa&t z`lWs~DJM3WJJKeVhbVkQM>=9u8OGy>&<~+z7S>d) zyudeJCSDe&0b@fZ{v41lO3=9KdR3-Xw(A&jq_Kw=xZTR@x3LDcpGeiN7zb+?>%QdyA= zZS$^M&Ow(6?rwq*#&cB9_%G1&=Wm^$IeZPU(WvQs8#dbt! z=nrY?sDc9;n)#snq)QtNeOhMC#o*pBg+4dVOyTlexW zgnKQ^UQ-^#dRyv!;#~8z!q_Dli2Ss6QHI)189Wce}l3WGi z+NYlwh$$c*c=Z}?QZoa_S{R0mi6jFsSY)&i1N@`l@{@G19B zT?Rx+N0~%ClYdxb`{(j1idfeiQ_0pE3$B@gfGNnn3+rxPR83h_sz5V1U3v{I{zz=k zqC^5DyZ4L#tC^ujdf;ApO<}ewnzQhF^Q9uAGiNoo;C~2{4gJK_%(r1yZzOtvRFy56 dgVXe!wu7{|oTdAw%mA+fanx5rQb%(N{{bIP#Z3SJ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/validate_templates.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/management/commands/__pycache__/validate_templates.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1a70786c949f9722ffd1d3f466f1b01e8ddb8c1 GIT binary patch literal 2986 zcmZ`*&2JmW6`$GfC6^ykWZAMEmv!m_Oe?ZL3I`~RwsIsJ23*;Y6w6(-SgbfpiqvwK zniY&~9)`oSrPRV1!Y*uWQY3l^^;d_#_?<{fK4GoY>(!=Ac;a#9_=mAuqxJ zmQF8_o(zVg(3iMgTV8wfLxEor{a)mUo#NCEUcdNYSnwkr!4wb-g{v^?s!VaUKxZn` znBG&T)HS{!UCIn*zOh`BSVxi+nG{W&5SQ0g*gxHRUj1_SZjP~%(-ReunMd82&*k|>%dz9-fFR* z5%B1}-NfG9jN(m9SXL5fohSJ?$jm7AkohRNyB#;8ST_8zjEBDLcl2b(XcR!fSaYUGKG@1R4S5`hpfU30v1rJ+aj^5N=TEl|b{gAH_VyD8PU%J9 z3_6yT3p)2FS$UER=KIn7rkd$uJPLSL@fq`c-Wv~tNQ%r^UP1|LA_%*gG4ix8}#p7(q5pK1G3;EMJMPcB3vGru<$?Xw^{Ylr=#_UJ+$ z$I(ZvkK3XzgUylOIq`deXtRMI^Tq@oQ^1|(=xdtT~r%)I)po{4CUF8FmQ zocFPUZo)*ULp5s963o`pY|!M|ypCJT9*V1C#3IyTd;&xK1SUxabf#c2PU!ialnm5u z^4qnEBDI;8(p0%r_!?rs>DnP64iuKUd+?~KXG$zG4Re%PNAUb3e+ZRTWJ6?TH-dWV z95+?I0e56p7hVghxYc>WV5bat#BYPRn9#YbHWx4Se+*2KBP4i?UyCN!7ao2~w?jc0 zKPxcmFrL8>{{*fik}^6~__|aIDkYvOwJDjXQkMo(dSt3h=|oF4si*K5Hvk@EWg2o8_sfVpeFkHLut;eO9Jt{KQU5cV5j?<^ZS6tV?BL=IcsoUQ+%#)n-+sC^>z7NMtS5rc}~Fo!J`@{|A7}l6os}cNy*m zNSoN_|422sy#Z@i_a z+T4yZ@RUg{wU~3Ff$RZP!P@LvT0<)?9J!v>ra&E%=!Hh)^^+3l{Em_dbc^JEYBT3! zGO>$2tdiDJb#{YQ)B0dza8uq&>r>iQ*2(33#&e)w!S2uMFUhY-q`V}l4JT^gQ*DDF zC2up>^*PvisvVNkf5Z6uVWIUE$W~H&9rE)zo!^`fFH$x0vF#PBQfrYpEd4@M87BChp!^f$y=ppbmMWvk{U>gwo)*f?`P(*FW|Xw zj*mApp=0K&@5724$Wozia%?didyQMeo(k~ib>gVo@4-98r^oN0!uL>L8^rx6)BA$; zd8PtTWLnr4(zUO`OY$1yZ0JR-9fP$KvTxkSacEUp1rWBV272qj1yEK{>VVv#s~~v*dh2k4LzC(Pwu(!d4*x0I zQ}VoF%*G)G$??3?u^$#8wHwlvU=vsuP5v=e_f(N%JId z1Xhk1ibXH5c?Ef>wIg>AGbs|5$EDlbL%)?B9p?YQ-> zm9?-TaQvH=XWYI0f7J4ShIs|M>vNSw8e3uPGsrC#mwTfSF7?e8G)u@~Ui0qV{}nIU kGM4>N6w$&MybI4#*RdWHDfl@)pLv8V1=|f~*+I(sFB8Nm+W-In literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/admin_generator.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/admin_generator.py new file mode 100644 index 0000000..cf67870 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/admin_generator.py @@ -0,0 +1,347 @@ +# -*- coding: utf-8 -*- +""" +The Django Admin Generator is a project which can automatically generate +(scaffold) a Django Admin for you. By doing this it will introspect your +models and automatically generate an Admin with properties like: + + - `list_display` for all local fields + - `list_filter` for foreign keys with few items + - `raw_id_fields` for foreign keys with a lot of items + - `search_fields` for name and `slug` fields + - `prepopulated_fields` for `slug` fields + - `date_hierarchy` for `created_at`, `updated_at` or `joined_at` fields + +The original source and latest version can be found here: +https://github.com/WoLpH/django-admin-generator/ +""" + +import re + +from django.apps import apps +from django.conf import settings +from django.core.management.base import LabelCommand, CommandError +from django.db import models + +from django_extensions.management.utils import signalcommand + +# Configurable constants +MAX_LINE_WIDTH = getattr(settings, 'MAX_LINE_WIDTH', 78) +INDENT_WIDTH = getattr(settings, 'INDENT_WIDTH', 4) +LIST_FILTER_THRESHOLD = getattr(settings, 'LIST_FILTER_THRESHOLD', 25) +RAW_ID_THRESHOLD = getattr(settings, 'RAW_ID_THRESHOLD', 100) + +LIST_FILTER = getattr(settings, 'LIST_FILTER', ( + models.DateField, + models.DateTimeField, + models.ForeignKey, + models.BooleanField, +)) + +SEARCH_FIELD_NAMES = getattr(settings, 'SEARCH_FIELD_NAMES', ( + 'name', + 'slug', +)) + +DATE_HIERARCHY_NAMES = getattr(settings, 'DATE_HIERARCHY_NAMES', ( + 'joined_at', + 'updated_at', + 'created_at', +)) + +PREPOPULATED_FIELD_NAMES = getattr(settings, 'PREPOPULATED_FIELD_NAMES', ( + 'slug=name', +)) + +PRINT_IMPORTS = getattr(settings, 'PRINT_IMPORTS', '''# -*- coding: utf-8 -*- +from django.contrib import admin + +from .models import %(models)s +''') + +PRINT_ADMIN_CLASS = getattr(settings, 'PRINT_ADMIN_CLASS', ''' + +@admin.register(%(name)s) +class %(name)sAdmin(admin.ModelAdmin):%(class_)s +''') + +PRINT_ADMIN_PROPERTY = getattr(settings, 'PRINT_ADMIN_PROPERTY', ''' + %(key)s = %(value)s''') + + +class UnicodeMixin: + """ + Mixin class to handle defining the proper __str__/__unicode__ + methods in Python 2 or 3. + """ + + def __str__(self): + return self.__unicode__() + + +class AdminApp(UnicodeMixin): + def __init__(self, app_config, model_res, **options): + self.app_config = app_config + self.model_res = model_res + self.options = options + + def __iter__(self): + for model in self.app_config.get_models(): + admin_model = AdminModel(model, **self.options) + + for model_re in self.model_res: + if model_re.search(admin_model.name): + break + else: + if self.model_res: + continue + + yield admin_model + + def __unicode__(self): + return ''.join(self._unicode_generator()) + + def _unicode_generator(self): + models_list = [admin_model.name for admin_model in self] + yield PRINT_IMPORTS % dict(models=', '.join(models_list)) + + admin_model_names = [] + for admin_model in self: + yield PRINT_ADMIN_CLASS % dict( + name=admin_model.name, + class_=admin_model, + ) + admin_model_names.append(admin_model.name) + + def __repr__(self): + return '<%s[%s]>' % ( + self.__class__.__name__, + self.app.name, + ) + + +class AdminModel(UnicodeMixin): + PRINTABLE_PROPERTIES = ( + 'list_display', + 'list_filter', + 'raw_id_fields', + 'search_fields', + 'prepopulated_fields', + 'date_hierarchy', + ) + + def __init__(self, model, raw_id_threshold=RAW_ID_THRESHOLD, + list_filter_threshold=LIST_FILTER_THRESHOLD, + search_field_names=SEARCH_FIELD_NAMES, + date_hierarchy_names=DATE_HIERARCHY_NAMES, + prepopulated_field_names=PREPOPULATED_FIELD_NAMES, **options): + self.model = model + self.list_display = [] + self.list_filter = [] + self.raw_id_fields = [] + self.search_fields = [] + self.prepopulated_fields = {} + self.date_hierarchy = None + self.search_field_names = search_field_names + self.raw_id_threshold = raw_id_threshold + self.list_filter_threshold = list_filter_threshold + self.date_hierarchy_names = date_hierarchy_names + self.prepopulated_field_names = prepopulated_field_names + + def __repr__(self): + return '<%s[%s]>' % ( + self.__class__.__name__, + self.name, + ) + + @property + def name(self): + return self.model.__name__ + + def _process_many_to_many(self, meta): + raw_id_threshold = self.raw_id_threshold + for field in meta.local_many_to_many: + if hasattr(field, 'remote_field'): + related_model = getattr(field.remote_field, 'related_model', field.remote_field.model) + else: + raise CommandError("Unable to process ManyToMany relation") + related_objects = related_model.objects.all() + if related_objects[:raw_id_threshold].count() < raw_id_threshold: + yield field.name + + def _process_fields(self, meta): + parent_fields = meta.parents.values() + for field in meta.fields: + name = self._process_field(field, parent_fields) + if name: + yield name + + def _process_foreign_key(self, field): + raw_id_threshold = self.raw_id_threshold + list_filter_threshold = self.list_filter_threshold + max_count = max(list_filter_threshold, raw_id_threshold) + if hasattr(field, 'remote_field'): + related_model = getattr(field.remote_field, 'related_model', field.remote_field.model) + else: + raise CommandError("Unable to process ForeignKey relation") + related_count = related_model.objects.all() + related_count = related_count[:max_count].count() + + if related_count >= raw_id_threshold: + self.raw_id_fields.append(field.name) + + elif related_count < list_filter_threshold: + self.list_filter.append(field.name) + + else: # pragma: no cover + pass # Do nothing :) + + def _process_field(self, field, parent_fields): + if field in parent_fields: + return + + field_name = str(field.name) + self.list_display.append(field_name) + if isinstance(field, LIST_FILTER): + if isinstance(field, models.ForeignKey): + self._process_foreign_key(field) + else: + self.list_filter.append(field_name) + + if field.name in self.search_field_names: + self.search_fields.append(field_name) + + return field_name + + def __unicode__(self): + return ''.join(self._unicode_generator()) + + def _yield_value(self, key, value): + if isinstance(value, (list, set, tuple)): + return self._yield_tuple(key, tuple(value)) + elif isinstance(value, dict): + return self._yield_dict(key, value) + elif isinstance(value, str): + return self._yield_string(key, value) + else: # pragma: no cover + raise TypeError('%s is not supported in %r' % (type(value), value)) + + def _yield_string(self, key, value, converter=repr): + return PRINT_ADMIN_PROPERTY % dict( + key=key, + value=converter(value), + ) + + def _yield_dict(self, key, value): + row_parts = [] + row = self._yield_string(key, value) + if len(row) > MAX_LINE_WIDTH: + row_parts.append(self._yield_string(key, '{', str)) + for k, v in value.items(): + row_parts.append('%s%r: %r' % (2 * INDENT_WIDTH * ' ', k, v)) + + row_parts.append(INDENT_WIDTH * ' ' + '}') + row = '\n'.join(row_parts) + + return row + + def _yield_tuple(self, key, value): + row_parts = [] + row = self._yield_string(key, value) + if len(row) > MAX_LINE_WIDTH: + row_parts.append(self._yield_string(key, '(', str)) + for v in value: + row_parts.append(2 * INDENT_WIDTH * ' ' + repr(v) + ',') + + row_parts.append(INDENT_WIDTH * ' ' + ')') + row = '\n'.join(row_parts) + + return row + + def _unicode_generator(self): + self._process() + for key in self.PRINTABLE_PROPERTIES: + value = getattr(self, key) + if value: + yield self._yield_value(key, value) + + def _process(self): + meta = self.model._meta + + self.raw_id_fields += list(self._process_many_to_many(meta)) + field_names = list(self._process_fields(meta)) + + for field_name in self.date_hierarchy_names[::-1]: + if field_name in field_names and not self.date_hierarchy: + self.date_hierarchy = field_name + break + + for k in sorted(self.prepopulated_field_names): + k, vs = k.split('=', 1) + vs = vs.split(',') + if k in field_names: + incomplete = False + for v in vs: + if v not in field_names: + incomplete = True + break + + if not incomplete: + self.prepopulated_fields[k] = vs + + self.processed = True + + +class Command(LabelCommand): + help = '''Generate a `admin.py` file for the given app (models)''' + # args = "[app_name]" + can_import_settings = True + + def add_arguments(self, parser): + parser.add_argument('app_name') + parser.add_argument('model_name', nargs='*') + parser.add_argument( + '-s', '--search-field', action='append', + default=SEARCH_FIELD_NAMES, + help='Fields named like this will be added to `search_fields`' + ' [default: %(default)s]') + parser.add_argument( + '-d', '--date-hierarchy', action='append', + default=DATE_HIERARCHY_NAMES, + help='A field named like this will be set as `date_hierarchy`' + ' [default: %(default)s]') + parser.add_argument( + '-p', '--prepopulated-fields', action='append', + default=PREPOPULATED_FIELD_NAMES, + help='These fields will be prepopulated by the other field.' + 'The field names can be specified like `spam=eggA,eggB,eggC`' + ' [default: %(default)s]') + parser.add_argument( + '-l', '--list-filter-threshold', type=int, + default=LIST_FILTER_THRESHOLD, metavar='LIST_FILTER_THRESHOLD', + help='If a foreign key has less than LIST_FILTER_THRESHOLD items ' + 'it will be added to `list_filter` [default: %(default)s]') + parser.add_argument( + '-r', '--raw-id-threshold', type=int, + default=RAW_ID_THRESHOLD, metavar='RAW_ID_THRESHOLD', + help='If a foreign key has more than RAW_ID_THRESHOLD items ' + 'it will be added to `list_filter` [default: %(default)s]') + + @signalcommand + def handle(self, *args, **options): + app_name = options['app_name'] + + try: + app = apps.get_app_config(app_name) + except LookupError: + self.stderr.write('This command requires an existing app name as argument') + self.stderr.write('Available apps:') + app_labels = [app.label for app in apps.get_app_configs()] + for label in sorted(app_labels): + self.stderr.write(' %s' % label) + return + + model_res = [] + for arg in options['model_name']: + model_res.append(re.compile(arg, re.IGNORECASE)) + + self.stdout.write(AdminApp(app, model_res, **options).__str__()) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/clean_pyc.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/clean_pyc.py new file mode 100644 index 0000000..f710eb5 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/clean_pyc.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +import fnmatch +import os +from os.path import join as _j + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError + +from django_extensions.management.utils import signalcommand + + +class Command(BaseCommand): + help = "Removes all python bytecode compiled files from the project." + + requires_system_checks = False + + def add_arguments(self, parser): + parser.add_argument( + '--optimize', '-o', '-O', action='store_true', + dest='optimize', default=False, + help='Remove optimized python bytecode files' + ) + parser.add_argument( + '--path', '-p', action='store', dest='path', + help='Specify path to recurse into' + ) + + @signalcommand + def handle(self, *args, **options): + project_root = options.get("path", getattr(settings, 'BASE_DIR', None)) + if not project_root: + project_root = getattr(settings, 'BASE_DIR', None) + + verbosity = options["verbosity"] + if not project_root: + raise CommandError("No --path specified and settings.py does not contain BASE_DIR") + + exts = options["optimize"] and "*.py[co]" or "*.pyc" + + for root, dirs, filenames in os.walk(project_root): + for filename in fnmatch.filter(filenames, exts): + full_path = _j(root, filename) + if verbosity > 1: + self.stdout.write("%s\n" % full_path) + os.remove(full_path) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/clear_cache.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/clear_cache.py new file mode 100644 index 0000000..b022c61 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/clear_cache.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Author: AxiaCore S.A.S. http://axiacore.com +from django.conf import settings +from django.core.cache import DEFAULT_CACHE_ALIAS, caches +from django.core.cache.backends.base import InvalidCacheBackendError +from django.core.management.base import BaseCommand, CommandError + +from django_extensions.management.utils import signalcommand + + +class Command(BaseCommand): + """A simple management command which clears the site-wide cache.""" + + help = 'Fully clear site-wide cache.' + + def add_arguments(self, parser): + parser.add_argument('--cache', action='append', + help='Name of cache to clear') + parser.add_argument('--all', '-a', action='store_true', default=False, + dest='all_caches', help='Clear all configured caches') + + @signalcommand + def handle(self, cache, all_caches, *args, **kwargs): + if not cache and not all_caches: + cache = [DEFAULT_CACHE_ALIAS] + elif cache and all_caches: + raise CommandError('Using both --all and --cache is not supported') + elif all_caches: + cache = getattr(settings, 'CACHES', {DEFAULT_CACHE_ALIAS: {}}).keys() + + for key in cache: + try: + caches[key].clear() + except InvalidCacheBackendError: + self.stderr.write('Cache "%s" is invalid!\n' % key) + else: + self.stdout.write('Cache "%s" has been cleared!\n' % key) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/compile_pyc.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/compile_pyc.py new file mode 100644 index 0000000..1b702fd --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/compile_pyc.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +import fnmatch +import os +import py_compile +from os.path import join as _j + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError + +from django_extensions.management.utils import signalcommand + + +class Command(BaseCommand): + help = "Compile python bytecode files for the project." + requires_system_checks = False + + def add_arguments(self, parser): + parser.add_argument('--path', '-p', action='store', dest='path', + help='Specify path to recurse into') + + @signalcommand + def handle(self, *args, **options): + project_root = options["path"] + if not project_root: + project_root = getattr(settings, 'BASE_DIR', None) + + verbosity = options["verbosity"] + if not project_root: + raise CommandError("No --path specified and settings.py does not contain BASE_DIR") + + for root, dirs, filenames in os.walk(project_root): + for filename in fnmatch.filter(filenames, '*.py'): + full_path = _j(root, filename) + if verbosity > 1: + self.stdout.write("Compiling %s...\n" % full_path) + py_compile.compile(full_path) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/create_command.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/create_command.py new file mode 100644 index 0000000..5844f91 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/create_command.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +import os +import sys +import shutil + +from django.core.management.base import AppCommand +from django.core.management.color import color_style + +from django_extensions.management.utils import _make_writeable, signalcommand + + +class Command(AppCommand): + help = "Creates a Django management command directory structure for the given app name in the app's directory." + + requires_system_checks = False + # Can't import settings during this command, because they haven't + # necessarily been created. + can_import_settings = True + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--name', '-n', action='store', dest='command_name', + default='sample', + help='The name to use for the management command' + ) + parser.add_argument( + '--base', '-b', action='store', dest='base_command', + default='Base', help='The base class used for implementation of ' + 'this command. Should be one of Base, App, Label, or NoArgs' + ) + parser.add_argument( + '--dry-run', action='store_true', default=False, + help='Do not actually create any files' + ) + + @signalcommand + def handle_app_config(self, args, **options): + app = args + copy_template('command_template', app.path, **options) + + +def copy_template(template_name, copy_to, **options): + """Copy the specified template directory to the copy_to location""" + import django_extensions + + style = color_style() + ERROR = getattr(style, 'ERROR', lambda x: x) + SUCCESS = getattr(style, 'SUCCESS', lambda x: x) + + command_name, base_command = options['command_name'], '%sCommand' % options['base_command'] + dry_run = options['dry_run'] + verbosity = options["verbosity"] + + template_dir = os.path.join(django_extensions.__path__[0], 'conf', template_name) + + # walk the template structure and copies it + for d, subdirs, files in os.walk(template_dir): + relative_dir = d[len(template_dir) + 1:] + if relative_dir and not os.path.exists(os.path.join(copy_to, relative_dir)): + if not dry_run: + os.mkdir(os.path.join(copy_to, relative_dir)) + for i, subdir in enumerate(subdirs): + if subdir.startswith('.'): + del subdirs[i] + for f in files: + if f.endswith(('.pyc', '.pyo')) or f.startswith(('.DS_Store', '__pycache__')): + continue + path_old = os.path.join(d, f) + path_new = os.path.join(copy_to, relative_dir, f.replace('sample', command_name)).rstrip(".tmpl") + if os.path.exists(path_new): + path_new = os.path.join(copy_to, relative_dir, f).rstrip(".tmpl") + if os.path.exists(path_new): + if verbosity > 1: + print(ERROR("%s already exists" % path_new)) + continue + if verbosity > 1: + print(SUCCESS("%s" % path_new)) + with open(path_old, 'r') as fp_orig: + data = fp_orig.read() + data = data.replace('{{ command_name }}', command_name) + data = data.replace('{{ base_command }}', base_command) + if not dry_run: + with open(path_new, 'w') as fp_new: + fp_new.write(data) + if not dry_run: + try: + shutil.copymode(path_old, path_new) + _make_writeable(path_new) + except OSError: + sys.stderr.write("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/create_jobs.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/create_jobs.py new file mode 100644 index 0000000..30c7e0c --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/create_jobs.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +import os +import sys +import shutil + +from django.core.management.base import AppCommand +from django.core.management.color import color_style + +from django_extensions.management.utils import _make_writeable, signalcommand + + +class Command(AppCommand): + help = "Creates a Django jobs command directory structure for the given app name in the current directory." + + requires_system_checks = False + # Can't import settings during this command, because they haven't + # necessarily been created. + can_import_settings = True + + @signalcommand + def handle_app_config(self, app, **options): + copy_template('jobs_template', app.path, **options) + + +def copy_template(template_name, copy_to, **options): + """Copy the specified template directory to the copy_to location""" + import django_extensions + + style = color_style() + ERROR = getattr(style, 'ERROR', lambda x: x) + SUCCESS = getattr(style, 'SUCCESS', lambda x: x) + + template_dir = os.path.join(django_extensions.__path__[0], 'conf', template_name) + verbosity = options["verbosity"] + + # walks the template structure and copies it + for d, subdirs, files in os.walk(template_dir): + relative_dir = d[len(template_dir) + 1:] + if relative_dir and not os.path.exists(os.path.join(copy_to, relative_dir)): + os.mkdir(os.path.join(copy_to, relative_dir)) + for i, subdir in enumerate(subdirs): + if subdir.startswith('.'): + del subdirs[i] + for f in files: + if f.endswith('.pyc') or f.startswith('.DS_Store'): + continue + path_old = os.path.join(d, f) + path_new = os.path.join(copy_to, relative_dir, f).rstrip(".tmpl") + if os.path.exists(path_new): + if verbosity > 1: + print(ERROR("%s already exists" % path_new)) + continue + if verbosity > 1: + print(SUCCESS("%s" % path_new)) + + with open(path_old, 'r') as fp_orig: + with open(path_new, 'w') as fp_new: + fp_new.write(fp_orig.read()) + + try: + shutil.copymode(path_old, path_new) + _make_writeable(path_new) + except OSError: + sys.stderr.write("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/create_template_tags.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/create_template_tags.py new file mode 100644 index 0000000..c444e43 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/create_template_tags.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +import os +import sys + +from django.core.management.base import AppCommand + +from django_extensions.management.utils import _make_writeable, signalcommand + + +class Command(AppCommand): + help = "Creates a Django template tags directory structure for the given app name in the apps's directory" + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--name', + '-n', + action='store', + dest='tag_library_name', + default='appname_tags', + help='The name to use for the template tag base name. Defaults to `appname`_tags.' + ) + + requires_system_checks = False + # Can't import settings during this command, because they haven't + # necessarily been created. + can_import_settings = True + + @signalcommand + def handle_app_config(self, app_config, **options): + app_dir = app_config.path + tag_library_name = options['tag_library_name'] + if tag_library_name == 'appname_tags': + tag_library_name = '%s_tags' % os.path.basename(app_dir) + copy_template('template_tags_template', app_dir, tag_library_name) + + +def copy_template(template_name, copy_to, tag_library_name): + """Copy the specified template directory to the copy_to location""" + import django_extensions + import shutil + + template_dir = os.path.join(django_extensions.__path__[0], 'conf', template_name) + + # walk the template structure and copies it + for d, subdirs, files in os.walk(template_dir): + relative_dir = d[len(template_dir) + 1:] + if relative_dir and not os.path.exists(os.path.join(copy_to, relative_dir)): + os.mkdir(os.path.join(copy_to, relative_dir)) + for i, subdir in enumerate(subdirs): + if subdir.startswith('.'): + del subdirs[i] + for f in files: + if f.endswith('.pyc') or f.startswith('.DS_Store'): + continue + path_old = os.path.join(d, f) + path_new = os.path.join(copy_to, relative_dir, f.replace('sample', tag_library_name)) + if os.path.exists(path_new): + path_new = os.path.join(copy_to, relative_dir, f) + if os.path.exists(path_new): + continue + path_new = path_new.rstrip(".tmpl") + fp_old = open(path_old, 'r') + fp_new = open(path_new, 'w') + fp_new.write(fp_old.read()) + fp_old.close() + fp_new.close() + try: + shutil.copymode(path_old, path_new) + _make_writeable(path_new) + except OSError: + sys.stderr.write("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/delete_squashed_migrations.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/delete_squashed_migrations.py new file mode 100644 index 0000000..b6956a1 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/delete_squashed_migrations.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +import os +import inspect +import re + +from django.core.management.base import BaseCommand, CommandError +from django.db import DEFAULT_DB_ALIAS, connections +from django.db.migrations.loader import AmbiguityError, MigrationLoader + +REPLACES_REGEX = re.compile(r'\s+replaces\s*=\s*\[[^\]]+\]\s*') +PYC = '.pyc' + + +def py_from_pyc(pyc_fn): + return pyc_fn[:-len(PYC)] + '.py' + + +class Command(BaseCommand): + help = "Deletes left over migrations that have been replaced by a " + "squashed migration and converts squashed migration into a normal " + "migration. Modifies your source tree! Use with care!" + + def add_arguments(self, parser): + parser.add_argument( + 'app_label', + help='App label of the application to delete replaced migrations from.', + ) + parser.add_argument( + 'squashed_migration_name', default=None, nargs='?', + help='The squashed migration to replace. ' + 'If not specified defaults to the first found.' + ) + parser.add_argument( + '--noinput', '--no-input', action='store_false', dest='interactive', default=True, + help='Tells Django to NOT prompt the user for input of any kind.', + ) + parser.add_argument( + '--dry-run', action='store_true', default=False, + help='Do not actually delete or change any files') + parser.add_argument( + '--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to run command for. Defaults to the "%s" database.' % DEFAULT_DB_ALIAS, + ) + + def handle(self, **options): + self.verbosity = options['verbosity'] + self.interactive = options['interactive'] + self.dry_run = options['dry_run'] + app_label = options['app_label'] + squashed_migration_name = options['squashed_migration_name'] + database = options['database'] + + # Load the current graph state, check the app and migration they asked for exists + loader = MigrationLoader(connections[database]) + if app_label not in loader.migrated_apps: + raise CommandError( + "App '%s' does not have migrations (so delete_squashed_migrations on " + "it makes no sense)" % app_label + ) + + squashed_migration = None + if squashed_migration_name: + squashed_migration = self.find_migration(loader, app_label, squashed_migration_name) + if not squashed_migration.replaces: + raise CommandError( + "The migration %s %s is not a squashed migration." % + (squashed_migration.app_label, squashed_migration.name) + ) + else: + leaf_nodes = loader.graph.leaf_nodes(app=app_label) + migration = loader.get_migration(*leaf_nodes[0]) + previous_migrations = [ + loader.get_migration(al, mn) + for al, mn in loader.graph.forwards_plan((migration.app_label, migration.name)) + if al == migration.app_label + ] + migrations = previous_migrations + [migration] + for migration in migrations: + if migration.replaces: + squashed_migration = migration + break + + if not squashed_migration: + raise CommandError( + "Cannot find a squashed migration in app '%s'." % + (app_label) + ) + + files_to_delete = [] + for al, mn in squashed_migration.replaces: + try: + migration = loader.disk_migrations[al, mn] + except KeyError: + if self.verbosity > 0: + self.stderr.write("Couldn't find migration file for %s %s\n" + % (al, mn)) + else: + pyc_file = inspect.getfile(migration.__class__) + files_to_delete.append(pyc_file) + if pyc_file.endswith(PYC): + py_file = py_from_pyc(pyc_file) + files_to_delete.append(py_file) + + # Tell them what we're doing and optionally ask if we should proceed + if self.verbosity > 0 or self.interactive: + self.stdout.write(self.style.MIGRATE_HEADING("Will delete the following files:")) + for fn in files_to_delete: + self.stdout.write(" - %s" % fn) + + if not self.confirm(): + return + + for fn in files_to_delete: + try: + if not self.dry_run: + os.remove(fn) + except OSError: + if self.verbosity > 0: + self.stderr.write("Couldn't delete %s\n" % (fn,)) + + # Try and delete replaces only if it's all on one line + squashed_migration_fn = inspect.getfile(squashed_migration.__class__) + if squashed_migration_fn.endswith(PYC): + squashed_migration_fn = py_from_pyc(squashed_migration_fn) + with open(squashed_migration_fn) as fp: + squashed_migration_lines = list(fp) + + delete_lines = [] + for i, line in enumerate(squashed_migration_lines): + if REPLACES_REGEX.match(line): + delete_lines.append(i) + if i > 0 and squashed_migration_lines[i - 1].strip() == '': + delete_lines.insert(0, i - 1) + break + if not delete_lines: + raise CommandError( + ("Couldn't find 'replaces =' line in file %s. " + "Please finish cleaning up manually.") % (squashed_migration_fn,) + ) + + if self.verbosity > 0 or self.interactive: + self.stdout.write(self.style.MIGRATE_HEADING( + "Will delete line %s%s from file %s" % + (delete_lines[0], + ' and ' + str(delete_lines[1]) if len(delete_lines) > 1 else "", + squashed_migration_fn))) + + if not self.confirm(): + return + + for line_num in sorted(delete_lines, reverse=True): + del squashed_migration_lines[line_num] + + with open(squashed_migration_fn, 'w') as fp: + if not self.dry_run: + fp.write("".join(squashed_migration_lines)) + + def confirm(self): + if self.interactive: + answer = None + while not answer or answer not in "yn": + answer = input("Do you wish to proceed? [yN] ") + if not answer: + answer = "n" + break + else: + answer = answer[0].lower() + return answer == "y" + return True + + def find_migration(self, loader, app_label, name): + try: + return loader.get_migration_by_prefix(app_label, name) + except AmbiguityError: + raise CommandError( + "More than one migration matches '%s' in app '%s'. Please be " + "more specific." % (name, app_label) + ) + except KeyError: + raise CommandError( + "Cannot find a migration matching '%s' from app '%s'." % + (name, app_label) + ) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/describe_form.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/describe_form.py new file mode 100644 index 0000000..609002c --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/describe_form.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +from django.apps import apps +from django.core.management.base import CommandError, LabelCommand +from django.utils.encoding import force_str + +from django_extensions.management.utils import signalcommand + + +class Command(LabelCommand): + help = "Outputs the specified model as a form definition to the shell." + + def add_arguments(self, parser): + parser.add_argument('label', type=str, + help='application name and model name') + parser.add_argument( + "--fields", "-f", action="append", dest="fields", default=[], + help="Describe form with these fields only" + ) + + @signalcommand + def handle(self, *args, **options): + label = options['label'] + fields = options['fields'] + + return describe_form(label, fields) + + +def describe_form(label, fields): + """ Return a string describing a form based on the model """ + try: + app_name, model_name = label.split('.')[-2:] + except (IndexError, ValueError): + raise CommandError("Need application and model name in the form: appname.model") + model = apps.get_model(app_name, model_name) + + opts = model._meta + field_list = [] + for f in opts.fields + opts.many_to_many: + if not f.editable: + continue + if fields and f.name not in fields: + continue + formfield = f.formfield() + if '__dict__' not in dir(formfield): + continue + attrs = {} + valid_fields = ['required', 'initial', 'max_length', 'min_length', 'max_value', 'min_value', 'max_digits', 'decimal_places', 'choices', 'help_text', 'label'] + for k, v in formfield.__dict__.items(): + if k in valid_fields and v is not None: + # ignore defaults, to minimize verbosity + if k == 'required' and v: + continue + if k == 'help_text' and not v: + continue + if k == 'widget': + attrs[k] = v.__class__ + elif k in ['help_text', 'label']: + attrs[k] = str(force_str(v).strip()) + else: + attrs[k] = v + + params = ', '.join(['%s=%r' % (k, v) for k, v in sorted(attrs.items())]) + field_list.append(' %(field_name)s = forms.%(field_type)s(%(params)s)' % { + 'field_name': f.name, + 'field_type': formfield.__class__.__name__, + 'params': params + }) + return ''' +from django import forms +from %(app_name)s.models import %(object_name)s + +class %(object_name)sForm(forms.Form): +%(field_list)s +''' % {'app_name': app_name, 'object_name': opts.object_name, 'field_list': '\n'.join(field_list)} diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/drop_test_database.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/drop_test_database.py new file mode 100644 index 0000000..0e058db --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/drop_test_database.py @@ -0,0 +1,151 @@ +# -*- coding: utf-8 -*- +import os +import logging +import warnings + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from django.db import DEFAULT_DB_ALIAS +from django.db.backends.base.creation import TEST_DATABASE_PREFIX + +from django_extensions.settings import SQLITE_ENGINES, POSTGRESQL_ENGINES, MYSQL_ENGINES +from django_extensions.management.mysql import parse_mysql_cnf +from django_extensions.management.utils import signalcommand +from django_extensions.utils.deprecation import RemovedInNextVersionWarning + + +class Command(BaseCommand): + help = "Drops test database for this project." + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--noinput', action='store_false', dest='interactive', + default=True, help='Tells Django to NOT prompt the user for input of any kind.' + ) + parser.add_argument( + '-U', '--user', action='store', dest='user', default=None, + help='Use another user for the database then defined in settings.py' + ) + parser.add_argument( + '-P', '--password', action='store', dest='password', default=None, + help='Use another password for the database then defined in settings.py' + ) + parser.add_argument( + '-D', '--dbname', action='store', dest='dbname', default=None, + help='Use another database name then defined in settings.py' + ) + parser.add_argument( + '-R', '--router', action='store', dest='router', default=DEFAULT_DB_ALIAS, + help='Use this router-database other then defined in settings.py' + ) + parser.add_argument( + '--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to run command for. Defaults to the "%s" database.' % DEFAULT_DB_ALIAS, + ) + + @signalcommand + def handle(self, *args, **options): + """Drop test database for this project.""" + database = options['database'] + if options['router'] != DEFAULT_DB_ALIAS: + warnings.warn("--router is deprecated. You should use --database.", RemovedInNextVersionWarning, stacklevel=2) + database = options['router'] + + dbinfo = settings.DATABASES.get(database) + if dbinfo is None: + raise CommandError("Unknown database %s" % database) + + engine = dbinfo.get('ENGINE') + + user = password = database_name = database_host = database_port = '' + if engine == 'mysql': + (user, password, database_name, database_host, database_port) = parse_mysql_cnf(dbinfo) + + user = options['user'] or dbinfo.get('USER') or user + password = options['password'] or dbinfo.get('PASSWORD') or password + + try: + database_name = dbinfo['TEST']['NAME'] + except KeyError: + database_name = None + + if database_name is None: + database_name = TEST_DATABASE_PREFIX + (options['dbname'] or dbinfo.get('NAME')) + + if database_name is None or database_name == '': + raise CommandError("You need to specify DATABASE_NAME in your Django settings file.") + + database_host = dbinfo.get('HOST') or database_host + database_port = dbinfo.get('PORT') or database_port + + verbosity = options["verbosity"] + if options['interactive']: + confirm = input(""" +You have requested to drop the test database. +This will IRREVERSIBLY DESTROY +ALL data in the database "%s". +Are you sure you want to do this? + +Type 'yes' to continue, or 'no' to cancel: """ % (database_name,)) + else: + confirm = 'yes' + + if confirm != 'yes': + print("Reset cancelled.") + return + + if engine in SQLITE_ENGINES: + try: + logging.info("Unlinking %s database" % engine) + if os.path.isfile(database_name): + os.unlink(database_name) + except OSError: + return + elif engine in MYSQL_ENGINES: + import MySQLdb as Database + kwargs = { + 'user': user, + 'passwd': password, + } + if database_host.startswith('/'): + kwargs['unix_socket'] = database_host + else: + kwargs['host'] = database_host + + if database_port: + kwargs['port'] = int(database_port) + + connection = Database.connect(**kwargs) + drop_query = 'DROP DATABASE IF EXISTS `%s`' % database_name + logging.info('Executing: "' + drop_query + '"') + connection.query(drop_query) + elif engine in POSTGRESQL_ENGINES: + import psycopg2 as Database # NOQA + + conn_params = {'database': 'template1'} + if user: + conn_params['user'] = user + if password: + conn_params['password'] = password + if database_host: + conn_params['host'] = database_host + if database_port: + conn_params['port'] = database_port + + connection = Database.connect(**conn_params) + connection.set_isolation_level(0) # autocommit false + cursor = connection.cursor() + drop_query = "DROP DATABASE IF EXISTS \"%s\";" % database_name + logging.info('Executing: "' + drop_query + '"') + + try: + cursor.execute(drop_query) + except Database.ProgrammingError as e: + logging.exception("Error: %s" % str(e)) + return + else: + raise CommandError("Unknown database engine %s" % engine) + + if verbosity >= 2 or options['interactive']: + print("Reset successful.") diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/dumpscript.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/dumpscript.py new file mode 100644 index 0000000..086a8c8 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/dumpscript.py @@ -0,0 +1,758 @@ +# -*- coding: utf-8 -*- +""" + Title: Dumpscript management command + Project: Hardytools (queryset-refactor version) + Author: Will Hardy (http://willhardy.com.au) + Date: June 2008 + Usage: python manage.py dumpscript appname > scripts/scriptname.py + $Revision: 217 $ + +Description: + Generates a Python script that will repopulate the database using objects. + The advantage of this approach is that it is easy to understand, and more + flexible than directly populating the database, or using XML. + + * It also allows for new defaults to take effect and only transfers what is + needed. + * If a new database schema has a NEW ATTRIBUTE, it is simply not + populated (using a default value will make the transition smooth :) + * If a new database schema REMOVES AN ATTRIBUTE, it is simply ignored + and the data moves across safely (I'm assuming we don't want this + attribute anymore. + * Problems may only occur if there is a new model and is now a required + ForeignKey for an existing model. But this is easy to fix by editing the + populate script. Half of the job is already done as all ForeingKey + lookups occur though the locate_object() function in the generated script. + +Improvements: + See TODOs and FIXMEs scattered throughout :-) + +""" +import datetime +import sys + +from django.apps import apps +from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import ObjectDoesNotExist +from django.core.management.base import BaseCommand +from django.db import router +from django.db.models import ( + AutoField, BooleanField, DateField, DateTimeField, FileField, ForeignKey, +) +from django.db.models.deletion import Collector +from django.utils import timezone +from django.utils.encoding import force_str, smart_text + +from django_extensions.management.utils import signalcommand + + +def orm_item_locator(orm_obj): + """ + Is called every time an object that will not be exported is required. + Where orm_obj is the referred object. + We postpone the lookup to locate_object() which will be run on the generated script + """ + + the_class = orm_obj._meta.object_name + original_class = the_class + pk_name = orm_obj._meta.pk.name + original_pk_name = pk_name + pk_value = getattr(orm_obj, pk_name) + + while hasattr(pk_value, "_meta") and hasattr(pk_value._meta, "pk") and hasattr(pk_value._meta.pk, "name"): + the_class = pk_value._meta.object_name + pk_name = pk_value._meta.pk.name + pk_value = getattr(pk_value, pk_name) + + clean_dict = make_clean_dict(orm_obj.__dict__) + + for key in clean_dict: + v = clean_dict[key] + if v is not None: + if isinstance(v, datetime.datetime): + v = timezone.make_aware(v) + clean_dict[key] = StrToCodeChanger('dateutil.parser.parse("%s")' % v.isoformat()) + elif not isinstance(v, (str, int, float)): + clean_dict[key] = str("%s" % v) + + output = """ importer.locate_object(%s, "%s", %s, "%s", %s, %s ) """ % ( + original_class, original_pk_name, + the_class, pk_name, pk_value, clean_dict + ) + + return output + + +class Command(BaseCommand): + help = 'Dumps the data as a customised python script.' + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument('appname', nargs='+') + parser.add_argument( + '--autofield', action='store_false', dest='skip_autofield', + default=True, help='Include Autofields (like pk fields)' + ) + + @signalcommand + def handle(self, *args, **options): + app_labels = options['appname'] + + # Get the models we want to export + models = get_models(app_labels) + + # A dictionary is created to keep track of all the processed objects, + # so that foreign key references can be made using python variable names. + # This variable "context" will be passed around like the town bicycle. + context = {} + + # Create a dumpscript object and let it format itself as a string + script = Script( + models=models, + context=context, + stdout=self.stdout, + stderr=self.stderr, + options=options, + ) + self.stdout.write(str(script)) + self.stdout.write("\n") + + +def get_models(app_labels): + """ + Get a list of models for the given app labels, with some exceptions. + TODO: If a required model is referenced, it should also be included. + Or at least discovered with a get_or_create() call. + """ + + # These models are not to be output, e.g. because they can be generated automatically + # TODO: This should be "appname.modelname" string + EXCLUDED_MODELS = (ContentType, ) + + models = [] + + # If no app labels are given, return all + if not app_labels: + for app in apps.get_app_configs(): + models += [m for m in apps.get_app_config(app.label).get_models() + if m not in EXCLUDED_MODELS] + return models + + # Get all relevant apps + for app_label in app_labels: + # If a specific model is mentioned, get only that model + if "." in app_label: + app_label, model_name = app_label.split(".", 1) + models.append(apps.get_model(app_label, model_name)) + # Get all models for a given app + else: + models += [m for m in apps.get_app_config(app_label).get_models() + if m not in EXCLUDED_MODELS] + + return models + + +class Code: + """ + A snippet of python script. + This keeps track of import statements and can be output to a string. + In the future, other features such as custom indentation might be included + in this class. + """ + + def __init__(self, indent=-1, stdout=None, stderr=None): + + if not stdout: + stdout = sys.stdout + if not stderr: + stderr = sys.stderr + + self.indent = indent + self.stdout = stdout + self.stderr = stderr + + def __str__(self): + """ Return a string representation of this script. """ + if self.imports: + self.stderr.write(repr(self.import_lines)) + return flatten_blocks([""] + self.import_lines + [""] + self.lines, num_indents=self.indent) + else: + return flatten_blocks(self.lines, num_indents=self.indent) + + def get_import_lines(self): + """ Take the stored imports and converts them to lines """ + if self.imports: + return ["from %s import %s" % (value, key) for key, value in self.imports.items()] + else: + return [] + import_lines = property(get_import_lines) + + +class ModelCode(Code): + """ Produces a python script that can recreate data for a given model class. """ + + def __init__(self, model, context=None, stdout=None, stderr=None, options=None): + super().__init__(indent=0, stdout=stdout, stderr=stderr) + self.model = model + if context is None: + context = {} + self.context = context + self.options = options + self.instances = [] + + def get_imports(self): + """ + Return a dictionary of import statements, with the variable being + defined as the key. + """ + return {self.model.__name__: smart_text(self.model.__module__)} + imports = property(get_imports) + + def get_lines(self): + """ + Return a list of lists or strings, representing the code body. + Each list is a block, each string is a statement. + """ + code = [] + + for counter, item in enumerate(self.model._default_manager.all()): + instance = InstanceCode(instance=item, id=counter + 1, context=self.context, stdout=self.stdout, stderr=self.stderr, options=self.options) + self.instances.append(instance) + if instance.waiting_list: + code += instance.lines + + # After each instance has been processed, try again. + # This allows self referencing fields to work. + for instance in self.instances: + if instance.waiting_list: + code += instance.lines + + return code + + lines = property(get_lines) + + +class InstanceCode(Code): + """ Produces a python script that can recreate data for a given model instance. """ + + def __init__(self, instance, id, context=None, stdout=None, stderr=None, options=None): + """ We need the instance in question and an id """ + + super().__init__(indent=0, stdout=stdout, stderr=stderr) + self.imports = {} + + self.options = options + self.instance = instance + self.model = self.instance.__class__ + if context is None: + context = {} + self.context = context + self.variable_name = "%s_%s" % (self.instance._meta.db_table, id) + self.skip_me = None + self.instantiated = False + + self.waiting_list = list(self.model._meta.fields) + + self.many_to_many_waiting_list = {} + for field in self.model._meta.many_to_many: + try: + if not field.remote_field.through._meta.auto_created: + continue + except AttributeError: + pass + self.many_to_many_waiting_list[field] = list(getattr(self.instance, field.name).all()) + + def get_lines(self, force=False): + """ + Return a list of lists or strings, representing the code body. + Each list is a block, each string is a statement. + + force (True or False): if an attribute object cannot be included, + it is usually skipped to be processed later. With 'force' set, there + will be no waiting: a get_or_create() call is written instead. + """ + code_lines = [] + + # Don't return anything if this is an instance that should be skipped + if self.skip(): + return [] + + # Initialise our new object + # e.g. model_name_35 = Model() + code_lines += self.instantiate() + + # Add each field + # e.g. model_name_35.field_one = 1034.91 + # model_name_35.field_two = "text" + code_lines += self.get_waiting_list() + + if force: + # TODO: Check that M2M are not affected + code_lines += self.get_waiting_list(force=force) + + # Print the save command for our new object + # e.g. model_name_35.save() + if code_lines: + code_lines.append("%s = importer.save_or_locate(%s)\n" % (self.variable_name, self.variable_name)) + + code_lines += self.get_many_to_many_lines(force=force) + + return code_lines + lines = property(get_lines) + + def skip(self): + """ + Determine whether or not this object should be skipped. + If this model instance is a parent of a single subclassed + instance, skip it. The subclassed instance will create this + parent instance for us. + + TODO: Allow the user to force its creation? + """ + if self.skip_me is not None: + return self.skip_me + + cls = self.instance.__class__ + using = router.db_for_write(cls, instance=self.instance) + collector = Collector(using=using) + collector.collect([self.instance], collect_related=False) + sub_objects = sum([list(i) for i in collector.data.values()], []) + sub_objects_parents = [so._meta.parents for so in sub_objects] + if [self.model in p for p in sub_objects_parents].count(True) == 1: + # since this instance isn't explicitly created, it's variable name + # can't be referenced in the script, so record None in context dict + pk_name = self.instance._meta.pk.name + key = '%s_%s' % (self.model.__name__, getattr(self.instance, pk_name)) + self.context[key] = None + self.skip_me = True + else: + self.skip_me = False + + return self.skip_me + + def instantiate(self): + """ Write lines for instantiation """ + # e.g. model_name_35 = Model() + code_lines = [] + + if not self.instantiated: + code_lines.append("%s = %s()" % (self.variable_name, self.model.__name__)) + self.instantiated = True + + # Store our variable name for future foreign key references + pk_name = self.instance._meta.pk.name + key = '%s_%s' % (self.model.__name__, getattr(self.instance, pk_name)) + self.context[key] = self.variable_name + + return code_lines + + def get_waiting_list(self, force=False): + """ Add lines for any waiting fields that can be completed now. """ + + code_lines = [] + skip_autofield = self.options['skip_autofield'] + + # Process normal fields + for field in list(self.waiting_list): + try: + # Find the value, add the line, remove from waiting list and move on + value = get_attribute_value(self.instance, field, self.context, force=force, skip_autofield=skip_autofield) + code_lines.append('%s.%s = %s' % (self.variable_name, field.name, value)) + self.waiting_list.remove(field) + except SkipValue: + # Remove from the waiting list and move on + self.waiting_list.remove(field) + continue + except DoLater: + # Move on, maybe next time + continue + + return code_lines + + def get_many_to_many_lines(self, force=False): + """ Generate lines that define many to many relations for this instance. """ + + lines = [] + + for field, rel_items in self.many_to_many_waiting_list.items(): + for rel_item in list(rel_items): + try: + pk_name = rel_item._meta.pk.name + key = '%s_%s' % (rel_item.__class__.__name__, getattr(rel_item, pk_name)) + value = "%s" % self.context[key] + lines.append('%s.%s.add(%s)' % (self.variable_name, field.name, value)) + self.many_to_many_waiting_list[field].remove(rel_item) + except KeyError: + if force: + item_locator = orm_item_locator(rel_item) + self.context["__extra_imports"][rel_item._meta.object_name] = rel_item.__module__ + lines.append('%s.%s.add( %s )' % (self.variable_name, field.name, item_locator)) + self.many_to_many_waiting_list[field].remove(rel_item) + + if lines: + lines.append("") + + return lines + + +class Script(Code): + """ Produces a complete python script that can recreate data for the given apps. """ + + def __init__(self, models, context=None, stdout=None, stderr=None, options=None): + super().__init__(stdout=stdout, stderr=stderr) + self.imports = {} + + self.models = models + if context is None: + context = {} + self.context = context + + self.context["__avaliable_models"] = set(models) + self.context["__extra_imports"] = {} + + self.options = options + + def _queue_models(self, models, context): + """ + Work an an appropriate ordering for the models. + This isn't essential, but makes the script look nicer because + more instances can be defined on their first try. + """ + model_queue = [] + number_remaining_models = len(models) + # Max number of cycles allowed before we call it an infinite loop. + MAX_CYCLES = number_remaining_models + allowed_cycles = MAX_CYCLES + + while number_remaining_models > 0: + previous_number_remaining_models = number_remaining_models + + model = models.pop(0) + + # If the model is ready to be processed, add it to the list + if check_dependencies(model, model_queue, context["__avaliable_models"]): + model_class = ModelCode(model=model, context=context, stdout=self.stdout, stderr=self.stderr, options=self.options) + model_queue.append(model_class) + + # Otherwise put the model back at the end of the list + else: + models.append(model) + + # Check for infinite loops. + # This means there is a cyclic foreign key structure + # That cannot be resolved by re-ordering + number_remaining_models = len(models) + if number_remaining_models == previous_number_remaining_models: + allowed_cycles -= 1 + if allowed_cycles <= 0: + # Add the remaining models, but do not remove them from the model list + missing_models = [ModelCode(model=m, context=context, stdout=self.stdout, stderr=self.stderr, options=self.options) for m in models] + model_queue += missing_models + # Replace the models with the model class objects + # (sure, this is a little bit of hackery) + models[:] = missing_models + break + else: + allowed_cycles = MAX_CYCLES + + return model_queue + + def get_lines(self): + """ + Return a list of lists or strings, representing the code body. + Each list is a block, each string is a statement. + """ + code = [self.FILE_HEADER.strip()] + + # Queue and process the required models + for model_class in self._queue_models(self.models, context=self.context): + msg = 'Processing model: %s.%s\n' % (model_class.model.__module__, model_class.model.__name__) + self.stderr.write(msg) + code.append(" # " + msg) + code.append(model_class.import_lines) + code.append("") + code.append(model_class.lines) + + # Process left over foreign keys from cyclic models + for model in self.models: + msg = 'Re-processing model: %s.%s\n' % (model.model.__module__, model.model.__name__) + self.stderr.write(msg) + code.append(" # " + msg) + for instance in model.instances: + if instance.waiting_list or instance.many_to_many_waiting_list: + code.append(instance.get_lines(force=True)) + + code.insert(1, " # Initial Imports") + code.insert(2, "") + for key, value in self.context["__extra_imports"].items(): + code.insert(2, " from %s import %s" % (value, key)) + + return code + + lines = property(get_lines) + + # A user-friendly file header + FILE_HEADER = """ + +#!/usr/bin/env python + + +# This file has been automatically generated. +# Instead of changing it, create a file called import_helper.py +# and put there a class called ImportHelper(object) in it. +# +# This class will be specially casted so that instead of extending object, +# it will actually extend the class BasicImportHelper() +# +# That means you just have to overload the methods you want to +# change, leaving the other ones intact. +# +# Something that you might want to do is use transactions, for example. +# +# Also, don't forget to add the necessary Django imports. +# +# This file was generated with the following command: +# %s +# +# to restore it, run +# manage.py runscript module_name.this_script_name +# +# example: if manage.py is at ./manage.py +# and the script is at ./some_folder/some_script.py +# you must make sure ./some_folder/__init__.py exists +# and run ./manage.py runscript some_folder.some_script +import os, sys +from django.db import transaction + +class BasicImportHelper: + + def pre_import(self): + pass + + @transaction.atomic + def run_import(self, import_data): + import_data() + + def post_import(self): + pass + + def locate_similar(self, current_object, search_data): + # You will probably want to call this method from save_or_locate() + # Example: + # new_obj = self.locate_similar(the_obj, {"national_id": the_obj.national_id } ) + + the_obj = current_object.__class__.objects.get(**search_data) + return the_obj + + def locate_object(self, original_class, original_pk_name, the_class, pk_name, pk_value, obj_content): + # You may change this function to do specific lookup for specific objects + # + # original_class class of the django orm's object that needs to be located + # original_pk_name the primary key of original_class + # the_class parent class of original_class which contains obj_content + # pk_name the primary key of original_class + # pk_value value of the primary_key + # obj_content content of the object which was not exported. + # + # You should use obj_content to locate the object on the target db + # + # An example where original_class and the_class are different is + # when original_class is Farmer and the_class is Person. The table + # may refer to a Farmer but you will actually need to locate Person + # in order to instantiate that Farmer + # + # Example: + # if the_class == SurveyResultFormat or the_class == SurveyType or the_class == SurveyState: + # pk_name="name" + # pk_value=obj_content[pk_name] + # if the_class == StaffGroup: + # pk_value=8 + + search_data = { pk_name: pk_value } + the_obj = the_class.objects.get(**search_data) + #print(the_obj) + return the_obj + + + def save_or_locate(self, the_obj): + # Change this if you want to locate the object in the database + try: + the_obj.save() + except: + print("---------------") + print("Error saving the following object:") + print(the_obj.__class__) + print(" ") + print(the_obj.__dict__) + print(" ") + print(the_obj) + print(" ") + print("---------------") + + raise + return the_obj + + +importer = None +try: + import import_helper + # We need this so ImportHelper can extend BasicImportHelper, although import_helper.py + # has no knowlodge of this class + importer = type("DynamicImportHelper", (import_helper.ImportHelper, BasicImportHelper ) , {} )() +except ImportError as e: + # From Python 3.3 we can check e.name - string match is for backward compatibility. + if 'import_helper' in str(e): + importer = BasicImportHelper() + else: + raise + +import datetime +from decimal import Decimal +from django.contrib.contenttypes.models import ContentType + +try: + import dateutil.parser + from dateutil.tz import tzoffset +except ImportError: + print("Please install python-dateutil") + sys.exit(os.EX_USAGE) + +def run(): + importer.pre_import() + importer.run_import(import_data) + importer.post_import() + +def import_data(): + +""" % " ".join(sys.argv) + + +# HELPER FUNCTIONS +# ------------------------------------------------------------------------------- + +def flatten_blocks(lines, num_indents=-1): + """ + Take a list (block) or string (statement) and flattens it into a string + with indentation. + """ + # The standard indent is four spaces + INDENTATION = " " * 4 + + if not lines: + return "" + + # If this is a string, add the indentation and finish here + if isinstance(lines, str): + return INDENTATION * num_indents + lines + + # If this is not a string, join the lines and recurse + return "\n".join([flatten_blocks(line, num_indents + 1) for line in lines]) + + +def get_attribute_value(item, field, context, force=False, skip_autofield=True): + """ Get a string version of the given attribute's value, like repr() might. """ + # Find the value of the field, catching any database issues + try: + value = getattr(item, field.name) + except ObjectDoesNotExist: + raise SkipValue('Could not find object for %s.%s, ignoring.\n' % (item.__class__.__name__, field.name)) + + # AutoField: We don't include the auto fields, they'll be automatically recreated + if skip_autofield and isinstance(field, AutoField): + raise SkipValue() + + # Some databases (eg MySQL) might store boolean values as 0/1, this needs to be cast as a bool + elif isinstance(field, BooleanField) and value is not None: + return repr(bool(value)) + + # Post file-storage-refactor, repr() on File/ImageFields no longer returns the path + elif isinstance(field, FileField): + return repr(force_str(value)) + + # ForeignKey fields, link directly using our stored python variable name + elif isinstance(field, ForeignKey) and value is not None: + + # Special case for contenttype foreign keys: no need to output any + # content types in this script, as they can be generated again + # automatically. + # NB: Not sure if "is" will always work + if field.remote_field.model is ContentType: + return 'ContentType.objects.get(app_label="%s", model="%s")' % (value.app_label, value.model) + + # Generate an identifier (key) for this foreign object + pk_name = value._meta.pk.name + key = '%s_%s' % (value.__class__.__name__, getattr(value, pk_name)) + + if key in context: + variable_name = context[key] + # If the context value is set to None, this should be skipped. + # This identifies models that have been skipped (inheritance) + if variable_name is None: + raise SkipValue() + # Return the variable name listed in the context + return "%s" % variable_name + elif value.__class__ not in context["__avaliable_models"] or force: + context["__extra_imports"][value._meta.object_name] = value.__module__ + item_locator = orm_item_locator(value) + return item_locator + else: + raise DoLater('(FK) %s.%s\n' % (item.__class__.__name__, field.name)) + + elif isinstance(field, (DateField, DateTimeField)) and value is not None: + return "dateutil.parser.parse(\"%s\")" % value.isoformat() + + # A normal field (e.g. a python built-in) + else: + return repr(value) + + +def make_clean_dict(the_dict): + if "_state" in the_dict: + clean_dict = the_dict.copy() + del clean_dict["_state"] + return clean_dict + return the_dict + + +def check_dependencies(model, model_queue, avaliable_models): + """ Check that all the depenedencies for this model are already in the queue. """ + # A list of allowed links: existing fields, itself and the special case ContentType + allowed_links = [m.model.__name__ for m in model_queue] + [model.__name__, 'ContentType'] + + # For each ForeignKey or ManyToMany field, check that a link is possible + + for field in model._meta.fields: + if not field.remote_field: + continue + if field.remote_field.model.__name__ not in allowed_links: + if field.remote_field.model not in avaliable_models: + continue + return False + + for field in model._meta.many_to_many: + if not field.remote_field: + continue + if field.remote_field.model.__name__ not in allowed_links: + return False + + return True + + +# EXCEPTIONS +# ------------------------------------------------------------------------------- + +class SkipValue(Exception): + """ Value could not be parsed or should simply be skipped. """ + + +class DoLater(Exception): + """ Value could not be parsed or should simply be skipped. """ + + +class StrToCodeChanger: + + def __init__(self, string): + self.repr = string + + def __repr__(self): + return self.repr diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/export_emails.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/export_emails.py new file mode 100644 index 0000000..39c6144 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/export_emails.py @@ -0,0 +1,157 @@ +# -*- coding: utf-8 -*- +import sys +import csv + +from django.conf import settings +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group +from django.core.management.base import BaseCommand, CommandError + +from django_extensions.management.utils import signalcommand + + +FORMATS = [ + 'address', + 'emails', + 'google', + 'outlook', + 'linkedin', + 'vcard', +] + + +def full_name(**kwargs): + """Return full name or username.""" + first_name = kwargs.get('first_name') + last_name = kwargs.get('last_name') + + name = " ".join(n for n in [first_name, last_name] if n) + if name: + return name + + name = kwargs.get('name') + if name: + return name + + username = kwargs.get('username') + if username: + return username + + return "" + + +class Command(BaseCommand): + help = "Export user email address list in one of a number of formats." + args = "[output file]" + label = 'filename to save to' + + can_import_settings = True + encoding = 'utf-8' # RED_FLAG: add as an option -DougN + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.UserModel = get_user_model() + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--group', '-g', action='store', dest='group', default=None, + help='Limit to users which are part of the supplied group name', + ), + parser.add_argument( + '--format', '-f', action='store', dest='format', default=FORMATS[0], + help="output format. May be one of %s." % ", ".join(FORMATS), + ) + + def full_name(self, **kwargs): + return getattr(settings, 'EXPORT_EMAILS_FULL_NAME_FUNC', full_name)(**kwargs) + + @signalcommand + def handle(self, *args, **options): + if len(args) > 1: + raise CommandError("extra arguments supplied") + group = options['group'] + if group and not Group.objects.filter(name=group).count() == 1: + names = "', '".join(g['name'] for g in Group.objects.values('name')) + if names: + names = "'" + names + "'." + raise CommandError("Unknown group '" + group + "'. Valid group names are: " + names) + + UserModel = get_user_model() + order_by = getattr(settings, 'EXPORT_EMAILS_ORDER_BY', ['last_name', 'first_name', 'username', 'email']) + fields = getattr(settings, 'EXPORT_EMAILS_FIELDS', ['last_name', 'first_name', 'username', 'email']) + + qs = UserModel.objects.all().order_by(*order_by) + if group: + qs = qs.filter(groups__name=group).distinct() + qs = qs.values(*fields) + getattr(self, options['format'])(qs) + + def address(self, qs): + """ + Single entry per line in the format of: + "full name" ; + """ + self.stdout.write("\n".join('"%s" <%s>;' % (self.full_name(**ent), ent.get('email', '')) for ent in qs)) + self.stdout.write("\n") + + def emails(self, qs): + """ + Single entry with email only in the format of: + my@address.com, + """ + self.stdout.write(",\n".join(ent['email'] for ent in qs if ent.get('email'))) + self.stdout.write("\n") + + def google(self, qs): + """CSV format suitable for importing into google GMail""" + csvf = csv.writer(sys.stdout) + csvf.writerow(['Name', 'Email']) + for ent in qs: + csvf.writerow([self.full_name(**ent), ent.get('email', '')]) + + def linkedin(self, qs): + """ + CSV format suitable for importing into linkedin Groups. + perfect for pre-approving members of a linkedin group. + """ + csvf = csv.writer(sys.stdout) + csvf.writerow(['First Name', 'Last Name', 'Email']) + for ent in qs: + csvf.writerow([ent.get('first_name', ''), ent.get('last_name', ''), ent.get('email', '')]) + + def outlook(self, qs): + """CSV format suitable for importing into outlook""" + csvf = csv.writer(sys.stdout) + columns = ['Name', 'E-mail Address', 'Notes', 'E-mail 2 Address', 'E-mail 3 Address', + 'Mobile Phone', 'Pager', 'Company', 'Job Title', 'Home Phone', 'Home Phone 2', + 'Home Fax', 'Home Address', 'Business Phone', 'Business Phone 2', + 'Business Fax', 'Business Address', 'Other Phone', 'Other Fax', 'Other Address'] + csvf.writerow(columns) + empty = [''] * (len(columns) - 2) + for ent in qs: + csvf.writerow([self.full_name(**ent), ent.get('email', '')] + empty) + + def vcard(self, qs): + """VCARD format.""" + try: + import vobject + except ImportError: + print(self.style.ERROR("Please install vobject to use the vcard export format.")) + sys.exit(1) + + out = sys.stdout + for ent in qs: + card = vobject.vCard() + card.add('fn').value = self.full_name(**ent) + if ent.get('last_name') and ent.get('first_name'): + card.add('n').value = vobject.vcard.Name(ent['last_name'], ent['first_name']) + else: + # fallback to fullname, if both first and lastname are not declared + card.add('n').value = vobject.vcard.Name(self.full_name(**ent)) + if ent.get('email'): + emailpart = card.add('email') + emailpart.value = ent['email'] + emailpart.type_param = 'INTERNET' + + out.write(card.serialize()) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/find_template.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/find_template.py new file mode 100644 index 0000000..53bd4a4 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/find_template.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +import sys + +from django.core.management.base import LabelCommand +from django.template import TemplateDoesNotExist, loader + +from django_extensions.management.utils import signalcommand + + +class Command(LabelCommand): + help = "Finds the location of the given template by resolving its path" + args = "[template_path]" + label = 'template path' + + @signalcommand + def handle_label(self, template_path, **options): + try: + template = loader.get_template(template_path).template + except TemplateDoesNotExist: + sys.stderr.write("No template found\n") + else: + sys.stdout.write(self.style.SUCCESS((template.name))) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/generate_password.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/generate_password.py new file mode 100644 index 0000000..e523694 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/generate_password.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +try: + from django.contrib.auth.base_user import BaseUserManager +except ImportError: + from django.contrib.auth.models import BaseUserManager +from django.core.management.base import BaseCommand +from django_extensions.management.utils import signalcommand + + +class Command(BaseCommand): + help = "Generates a new password that can be used for a user password. This uses Django core's default password generator `BaseUserManager.make_random_password()`." + + requires_system_checks = False + + def add_arguments(self, parser): + parser.add_argument( + '--length', nargs='?', type=int, + help='Password length.') + + @signalcommand + def handle(self, *args, **options): + length = options['length'] + manager = BaseUserManager() + + if length: + return manager.make_random_password(length) + else: + return manager.make_random_password() diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/generate_secret_key.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/generate_secret_key.py new file mode 100644 index 0000000..f482324 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/generate_secret_key.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from django.core.management.base import BaseCommand +from django.core.management.utils import get_random_secret_key + +from django_extensions.management.utils import signalcommand + + +class Command(BaseCommand): + help = "Generates a new SECRET_KEY that can be used in a project settings file." + + requires_system_checks = False + + @signalcommand + def handle(self, *args, **options): + return get_random_secret_key() diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/graph_models.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/graph_models.py new file mode 100644 index 0000000..8cb4a57 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/graph_models.py @@ -0,0 +1,319 @@ +# -*- coding: utf-8 -*- +import sys +import json +import os +import tempfile + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from django.template import loader + +from django_extensions.management.modelviz import ModelGraph, generate_dot +from django_extensions.management.utils import signalcommand + +try: + import pygraphviz + HAS_PYGRAPHVIZ = True +except ImportError: + HAS_PYGRAPHVIZ = False + +try: + try: + import pydotplus as pydot + except ImportError: + import pydot + HAS_PYDOT = True +except ImportError: + HAS_PYDOT = False + + +class Command(BaseCommand): + help = "Creates a GraphViz dot file for the specified app names. You can pass multiple app names and they will all be combined into a single model. Output is usually directed to a dot file." + + can_import_settings = True + + def __init__(self, *args, **kwargs): + """ + Allow defaults for arguments to be set in settings.GRAPH_MODELS. + + Each argument in self.arguments is a dict where the key is the + space-separated args and the value is our kwarg dict. + + The default from settings is keyed as the long arg name with '--' + removed and any '-' replaced by '_'. For example, the default value for + --disable-fields can be set in settings.GRAPH_MODELS['disable_fields']. + """ + self.arguments = { + '--pygraphviz': { + 'action': 'store_true', + 'default': False, + 'dest': 'pygraphviz', + 'help': 'Output graph data as image using PyGraphViz.', + }, + '--pydot': { + 'action': 'store_true', + 'default': False, + 'dest': 'pydot', + 'help': 'Output graph data as image using PyDot(Plus).', + }, + '--dot': { + 'action': 'store_true', + 'default': False, + 'dest': 'dot', + 'help': 'Output graph data as raw DOT (graph description language) text data.', + }, + '--json': { + 'action': 'store_true', + 'default': False, + 'dest': 'json', + 'help': 'Output graph data as JSON', + }, + '--disable-fields -d': { + 'action': 'store_true', + 'default': False, + 'dest': 'disable_fields', + 'help': 'Do not show the class member fields', + }, + '--disable-abstract-fields': { + 'action': 'store_true', + 'default': False, + 'dest': 'disable_abstract_fields', + 'help': 'Do not show the class member fields that were inherited', + }, + '--group-models -g': { + 'action': 'store_true', + 'default': False, + 'dest': 'group_models', + 'help': 'Group models together respective to their application', + }, + '--all-applications -a': { + 'action': 'store_true', + 'default': False, + 'dest': 'all_applications', + 'help': 'Automatically include all applications from INSTALLED_APPS', + }, + '--output -o': { + 'action': 'store', + 'dest': 'outputfile', + 'help': 'Render output file. Type of output dependend on file extensions. Use png or jpg to render graph to image.', + }, + '--layout -l': { + 'action': 'store', + 'dest': 'layout', + 'default': 'dot', + 'help': 'Layout to be used by GraphViz for visualization. Layouts: circo dot fdp neato nop nop1 nop2 twopi', + }, + '--theme -t': { + 'action': 'store', + 'dest': 'theme', + 'default': 'django2018', + 'help': 'Theme to use. Supplied are \'original\' and \'django2018\'. You can create your own by creating dot templates in \'django_extentions/graph_models/themename/\' template directory.', + }, + '--verbose-names -n': { + 'action': 'store_true', + 'default': False, + 'dest': 'verbose_names', + 'help': 'Use verbose_name of models and fields', + }, + '--language -L': { + 'action': 'store', + 'dest': 'language', + 'help': 'Specify language used for verbose_name localization', + }, + '--exclude-columns -x': { + 'action': 'store', + 'dest': 'exclude_columns', + 'help': 'Exclude specific column(s) from the graph. Can also load exclude list from file.', + }, + '--exclude-models -X': { + 'action': 'store', + 'dest': 'exclude_models', + 'help': 'Exclude specific model(s) from the graph. Can also load exclude list from file. Wildcards (*) are allowed.', + }, + '--include-models -I': { + 'action': 'store', + 'dest': 'include_models', + 'help': 'Restrict the graph to specified models. Wildcards (*) are allowed.', + }, + '--inheritance -e': { + 'action': 'store_true', + 'default': True, + 'dest': 'inheritance', + 'help': 'Include inheritance arrows (default)', + }, + '--no-inheritance -E': { + 'action': 'store_false', + 'default': False, + 'dest': 'inheritance', + 'help': 'Do not include inheritance arrows', + }, + '--hide-relations-from-fields -R': { + 'action': 'store_false', + 'default': True, + 'dest': 'relations_as_fields', + 'help': 'Do not show relations as fields in the graph.', + }, + '--disable-sort-fields -S': { + 'action': 'store_false', + 'default': True, + 'dest': 'sort_fields', + 'help': 'Do not sort fields', + }, + '--hide-edge-labels': { + 'action': 'store_true', + 'default': False, + 'dest': 'hide_edge_labels', + 'help': 'Do not showrelations labels in the graph.', + }, + '--arrow-shape': { + 'action': 'store', + 'default': 'dot', + 'dest': 'arrow_shape', + 'choices': ['box', 'crow', 'curve', 'icurve', 'diamond', 'dot', 'inv', 'none', 'normal', 'tee', 'vee'], + 'help': 'Arrow shape to use for relations. Default is dot. Available shapes: box, crow, curve, icurve, diamond, dot, inv, none, normal, tee, vee.', + } + } + + defaults = getattr(settings, 'GRAPH_MODELS', None) + + if defaults: + for argument in self.arguments: + arg_split = argument.split(' ') + setting_opt = arg_split[0].lstrip('-').replace('-', '_') + if setting_opt in defaults: + self.arguments[argument]['default'] = defaults[setting_opt] + + super().__init__(*args, **kwargs) + + def add_arguments(self, parser): + """Unpack self.arguments for parser.add_arguments.""" + parser.add_argument('app_label', nargs='*') + for argument in self.arguments: + parser.add_argument(*argument.split(' '), **self.arguments[argument]) + + @signalcommand + def handle(self, *args, **options): + args = options['app_label'] + if not args and not options['all_applications']: + raise CommandError("need one or more arguments for appname") + + # Determine output format based on options, file extension, and library + # availability. + outputfile = options.get("outputfile") or "" + _, outputfile_ext = os.path.splitext(outputfile) + outputfile_ext = outputfile_ext.lower() + output_opts_names = ['pydot', 'pygraphviz', 'json', 'dot'] + output_opts = {k: v for k, v in options.items() if k in output_opts_names} + output_opts_count = sum(output_opts.values()) + if output_opts_count > 1: + raise CommandError("Only one of %s can be set." % ", ".join(["--%s" % opt for opt in output_opts_names])) + + if output_opts_count == 1: + output = next(key for key, val in output_opts.items() if val) + elif not outputfile: + # When neither outputfile nor a output format option are set, + # default to printing .dot format to stdout. Kept for backward + # compatibility. + output = "dot" + elif outputfile_ext == ".dot": + output = "dot" + elif outputfile_ext == ".json": + output = "json" + elif HAS_PYGRAPHVIZ: + output = "pygraphviz" + elif HAS_PYDOT: + output = "pydot" + else: + raise CommandError("Neither pygraphviz nor pydotplus could be found to generate the image. To generate text output, use the --json or --dot options.") + + # Consistency check: Abort if --pygraphviz or --pydot options are set + # but no outputfile is specified. Before 2.1.4 this silently fell back + # to printind .dot format to stdout. + if output in ["pydot", "pygraphviz"] and not outputfile: + raise CommandError("An output file (--output) must be specified when --pydot or --pygraphviz are set.") + + cli_options = ' '.join(sys.argv[2:]) + graph_models = ModelGraph(args, cli_options=cli_options, **options) + graph_models.generate_graph_data() + + if output == "json": + graph_data = graph_models.get_graph_data(as_json=True) + return self.render_output_json(graph_data, outputfile) + + graph_data = graph_models.get_graph_data(as_json=False) + + theme = options['theme'] + template_name = os.path.join('django_extensions', 'graph_models', theme, 'digraph.dot') + template = loader.get_template(template_name) + + dotdata = generate_dot(graph_data, template=template) + + if output == "pygraphviz": + return self.render_output_pygraphviz(dotdata, **options) + if output == "pydot": + return self.render_output_pydot(dotdata, **options) + self.print_output(dotdata, outputfile) + + def print_output(self, dotdata, output_file=None): + """Write model data to file or stdout in DOT (text) format.""" + if isinstance(dotdata, bytes): + dotdata = dotdata.decode() + + if output_file: + with open(output_file, 'wt') as dot_output_f: + dot_output_f.write(dotdata) + else: + self.stdout.write(dotdata) + + def render_output_json(self, graph_data, output_file=None): + """Write model data to file or stdout in JSON format.""" + if output_file: + with open(output_file, 'wt') as json_output_f: + json.dump(graph_data, json_output_f) + else: + self.stdout.write(json.dumps(graph_data)) + + def render_output_pygraphviz(self, dotdata, **kwargs): + """Render model data as image using pygraphviz.""" + if not HAS_PYGRAPHVIZ: + raise CommandError("You need to install pygraphviz python module") + + version = pygraphviz.__version__.rstrip("-svn") + try: + if tuple(int(v) for v in version.split('.')) < (0, 36): + # HACK around old/broken AGraph before version 0.36 (ubuntu ships with this old version) + tmpfile = tempfile.NamedTemporaryFile() + tmpfile.write(dotdata) + tmpfile.seek(0) + dotdata = tmpfile.name + except ValueError: + pass + + graph = pygraphviz.AGraph(dotdata) + graph.layout(prog=kwargs['layout']) + graph.draw(kwargs['outputfile']) + + def render_output_pydot(self, dotdata, **kwargs): + """Render model data as image using pydot.""" + if not HAS_PYDOT: + raise CommandError("You need to install pydot python module") + + graph = pydot.graph_from_dot_data(dotdata) + if not graph: + raise CommandError("pydot returned an error") + if isinstance(graph, (list, tuple)): + if len(graph) > 1: + sys.stderr.write("Found more then one graph, rendering only the first one.\n") + graph = graph[0] + + output_file = kwargs['outputfile'] + formats = [ + 'bmp', 'canon', 'cmap', 'cmapx', 'cmapx_np', 'dot', 'dia', 'emf', + 'em', 'fplus', 'eps', 'fig', 'gd', 'gd2', 'gif', 'gv', 'imap', + 'imap_np', 'ismap', 'jpe', 'jpeg', 'jpg', 'metafile', 'pdf', + 'pic', 'plain', 'plain-ext', 'png', 'pov', 'ps', 'ps2', 'svg', + 'svgz', 'tif', 'tiff', 'tk', 'vml', 'vmlz', 'vrml', 'wbmp', 'xdot', + ] + ext = output_file[output_file.rfind('.') + 1:] + format_ = ext if ext in formats else 'raw' + graph.write(output_file, format=format_) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/list_model_info.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/list_model_info.py new file mode 100644 index 0000000..15e067f --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/list_model_info.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- +# Author: OmenApps. http://www.omenapps.com +import inspect + +from django.apps import apps as django_apps +from django.conf import settings +from django.core.management.base import BaseCommand +from django.db import connection +from django_extensions.management.color import color_style +from django_extensions.management.utils import signalcommand + +TAB = " " +HALFTAB = " " + + +class Command(BaseCommand): + """A simple management command which lists model fields and methods.""" + + help = "List out the fields and methods for each model" + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument("--field-class", action="store_true", default=None, help="show class name of field.") + parser.add_argument("--db-type", action="store_true", default=None, help="show database column type of field.") + parser.add_argument("--signature", action="store_true", default=None, help="show the signature of method.") + parser.add_argument( + "--all-methods", action="store_true", default=None, help="list all methods, including private and default." + ) + parser.add_argument( + "--model", + nargs="?", + type=str, + default=None, + help="list the details for a single model. Input should be in the form appname.Modelname", + ) + + def list_model_info(self, options): + + style = color_style() + INFO = getattr(style, "INFO", lambda x: x) + WARN = getattr(style, "WARN", lambda x: x) + BOLD = getattr(style, "BOLD", lambda x: x) + + FIELD_CLASS = ( + True if options.get("field_class", None) is not None else getattr(settings, "MODEL_INFO_FIELD_CLASS", False) + ) + DB_TYPE = True if options.get("db_type", None) is not None else getattr(settings, "MODEL_INFO_DB_TYPE", False) + SIGNATURE = ( + True if options.get("signature", None) is not None else getattr(settings, "MODEL_INFO_SIGNATURE", False) + ) + ALL_METHODS = ( + True if options.get("all_methods", None) is not None else getattr(settings, "MODEL_INFO_ALL_METHODS", False) + ) + MODEL = ( + options.get("model") + if options.get("model", None) is not None + else getattr(settings, "MODEL_INFO_MODEL", False) + ) + + default_methods = [ + "check", + "clean", + "clean_fields", + "date_error_message", + "delete", + "from_db", + "full_clean", + "get_absolute_url", + "get_deferred_fields", + "prepare_database_save", + "refresh_from_db", + "save", + "save_base", + "serializable_value", + "unique_error_message", + "validate_unique", + ] + + if MODEL: + model_list = [django_apps.get_model(MODEL)] + else: + model_list = sorted( + django_apps.get_models(), key=lambda x: (x._meta.app_label, x._meta.object_name), reverse=False + ) + for model in model_list: + self.stdout.write(INFO(model._meta.app_label + "." + model._meta.object_name)) + self.stdout.write(BOLD(HALFTAB + "Fields:")) + + for field in model._meta.get_fields(): + field_info = TAB + field.name + " -" + + if FIELD_CLASS: + try: + field_info += " " + field.__class__.__name__ + except TypeError: + field_info += (WARN(" TypeError (field_class)")) + except AttributeError: + field_info += (WARN(" AttributeError (field_class)")) + if FIELD_CLASS and DB_TYPE: + field_info += "," + if DB_TYPE: + try: + field_info += " " + field.db_type(connection=connection) + except TypeError: + field_info += (WARN(" TypeError (db_type)")) + except AttributeError: + field_info += (WARN(" AttributeError (db_type)")) + + self.stdout.write(field_info) + + if ALL_METHODS: + self.stdout.write(BOLD(HALFTAB + "Methods (all):")) + else: + self.stdout.write(BOLD(HALFTAB + "Methods (non-private/internal):")) + + for method_name in dir(model): + try: + method = getattr(model, method_name) + if ALL_METHODS: + if callable(method) and not method_name[0].isupper(): + if SIGNATURE: + signature = inspect.signature(method) + else: + signature = "()" + self.stdout.write(TAB + method_name + str(signature)) + else: + if ( + callable(method) + and not method_name.startswith("_") + and method_name not in default_methods + and not method_name[0].isupper() + ): + if SIGNATURE: + signature = inspect.signature(method) + else: + signature = "()" + self.stdout.write(TAB + method_name + str(signature)) + except AttributeError: + self.stdout.write(TAB + method_name + WARN(" - AttributeError")) + except ValueError: + self.stdout.write(TAB + method_name + WARN(" - ValueError (could not identify signature)")) + + self.stdout.write("\n") + + self.stdout.write(INFO("Total Models Listed: %d" % len(model_list))) + + @signalcommand + def handle(self, *args, **options): + self.list_model_info(options) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/list_signals.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/list_signals.py new file mode 100644 index 0000000..c41aa6f --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/list_signals.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +# Based on https://gist.github.com/voldmar/1264102 +# and https://gist.github.com/runekaagaard/2eecf0a8367959dc634b7866694daf2c + +import gc +import inspect +import weakref +from collections import defaultdict + +from django.apps import apps +from django.core.management.base import BaseCommand +from django.db.models.signals import ( + ModelSignal, pre_init, post_init, pre_save, post_save, pre_delete, + post_delete, m2m_changed, pre_migrate, post_migrate +) +from django.utils.encoding import force_str + + +MSG = '{module}.{name} #{line}' + +SIGNAL_NAMES = { + pre_init: 'pre_init', + post_init: 'post_init', + pre_save: 'pre_save', + post_save: 'post_save', + pre_delete: 'pre_delete', + post_delete: 'post_delete', + m2m_changed: 'm2m_changed', + pre_migrate: 'pre_migrate', + post_migrate: 'post_migrate', +} + + +class Command(BaseCommand): + help = 'List all signals by model and signal type' + + def handle(self, *args, **options): + all_models = apps.get_models(include_auto_created=True, include_swapped=True) + model_lookup = {id(m): m for m in all_models} + + signals = [obj for obj in gc.get_objects() if isinstance(obj, ModelSignal)] + models = defaultdict(lambda: defaultdict(list)) + + for signal in signals: + signal_name = SIGNAL_NAMES.get(signal, 'unknown') + for receiver in signal.receivers: + lookup, receiver = receiver + if isinstance(receiver, weakref.ReferenceType): + receiver = receiver() + if receiver is None: + continue + receiver_id, sender_id = lookup + + model = model_lookup.get(sender_id, '_unknown_') + if model: + models[model][signal_name].append(MSG.format( + name=receiver.__name__, + module=receiver.__module__, + line=inspect.getsourcelines(receiver)[1], + path=inspect.getsourcefile(receiver)) + ) + + output = [] + for key in sorted(models.keys(), key=str): + verbose_name = force_str(key._meta.verbose_name) + output.append('{}.{} ({})'.format( + key.__module__, key.__name__, verbose_name)) + for signal_name in sorted(models[key].keys()): + lines = models[key][signal_name] + output.append(' {}'.format(signal_name)) + for line in lines: + output.append(' {}'.format(line)) + + return '\n'.join(output) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/mail_debug.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/mail_debug.py new file mode 100644 index 0000000..bf1c81e --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/mail_debug.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +import asyncore +import sys +from logging import getLogger +from smtpd import SMTPServer + +from django.core.management.base import BaseCommand, CommandError + +from django_extensions.management.utils import setup_logger, signalcommand + +logger = getLogger(__name__) + + +class ExtensionDebuggingServer(SMTPServer): + """Duplication of smtpd.DebuggingServer, but using logging instead of print.""" + + # Do something with the gathered message + def process_message(self, peer, mailfrom, rcpttos, data, **kwargs): + """Output will be sent to the module logger at INFO level.""" + inheaders = 1 + lines = data.split('\n') + logger.info('---------- MESSAGE FOLLOWS ----------') + for line in lines: + # headers first + if inheaders and not line: + logger.info('X-Peer: %s' % peer[0]) + inheaders = 0 + logger.info(line) + logger.info('------------ END MESSAGE ------------') + + +class Command(BaseCommand): + help = "Starts a test mail server for development." + args = '[optional port number or ippaddr:port]' + + requires_system_checks = False + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--output', dest='output_file', default=None, + help='Specifies an output file to send a copy of all messages (not flushed immediately).' + ) + parser.add_argument( + '--use-settings', dest='use_settings', + action='store_true', default=False, + help='Uses EMAIL_HOST and HOST_PORT from Django settings.' + ) + + @signalcommand + def handle(self, addrport='', *args, **options): + if not addrport: + if options['use_settings']: + from django.conf import settings + addr = getattr(settings, 'EMAIL_HOST', '') + port = str(getattr(settings, 'EMAIL_PORT', '1025')) + else: + addr = '' + port = '1025' + else: + try: + addr, port = addrport.split(':') + except ValueError: + addr, port = '', addrport + if not addr: + addr = '127.0.0.1' + + if not port.isdigit(): + raise CommandError("%r is not a valid port number." % port) + else: + port = int(port) + + # Add console handler + setup_logger(logger, stream=self.stdout, filename=options['output_file']) + + def inner_run(): + quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C' + print("Now accepting mail at %s:%s -- use %s to quit" % (addr, port, quit_command)) + ExtensionDebuggingServer((addr, port), None, decode_data=True) + asyncore.loop() + + try: + inner_run() + except KeyboardInterrupt: + pass diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/merge_model_instances.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/merge_model_instances.py new file mode 100644 index 0000000..e53afdc --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/merge_model_instances.py @@ -0,0 +1,222 @@ +# -*- coding: utf-8 -*- +from django.apps import apps +from django.contrib.contenttypes.fields import GenericForeignKey +from django.core.management import BaseCommand +from django.db import transaction + +from django_extensions.management.utils import signalcommand + + +def get_model_to_deduplicate(): + models = apps.get_models() + iterator = 1 + for model in models: + print("%s. %s" % (iterator, model.__name__)) + iterator += 1 + model_choice = int(input("Enter the number of the model you would like to de-duplicate:")) + model_to_deduplicate = models[model_choice - 1] + return model_to_deduplicate + + +def get_field_names(model): + fields = [field.name for field in model._meta.get_fields()] + iterator = 1 + for field in fields: + print("%s. %s" % (iterator, field)) + iterator += 1 + validated = False + while not validated: + first_field = int(input("Enter the number of the (first) field you would like to de-duplicate.")) + if first_field in range(1, iterator): + validated = True + else: + print("Invalid input. Please try again.") + fields_to_deduplicate = [fields[first_field - 1]] + + done = False + while not done: + available_fields = [ + f for f in fields if f not in fields_to_deduplicate + ] + iterator = 1 + for field in available_fields: + print("%s. %s" % (iterator, field)) + iterator += 1 + print("C. Done adding fields.") + + validated = False + while not validated: + print("You are currently deduplicating on the following fields:") + print('\n'.join(fields_to_deduplicate) + '\n') + + additional_field = input(""" + Enter the number of the field you would like to de-duplicate. + If you have entered all fields, enter C to continue. + """) + if additional_field == "C": + done = True + validated = True + elif int(additional_field) in list(range(1, len(available_fields) + 1)): + fields_to_deduplicate += [available_fields[int(additional_field) - 1]] + validated = True + else: + print("Invalid input. Please try again.") + + return fields_to_deduplicate + + +def keep_first_or_last_instance(): + while True: + first_or_last = input(""" + Do you want to keep the first or last duplicate instance? + Enter "first" or "last" to continue. + """) + if first_or_last in ["first", "last"]: + return first_or_last + + +def get_generic_fields(): + """Return a list of all GenericForeignKeys in all models.""" + generic_fields = [] + for model in apps.get_models(): + for field_name, field in model.__dict__.items(): + if isinstance(field, GenericForeignKey): + generic_fields.append(field) + return generic_fields + + +class Command(BaseCommand): + help = """ + Removes duplicate model instances based on a specified + model and field name(s). + + Makes sure that any OneToOne, ForeignKey, or ManyToMany relationships + attached to a deleted model(s) get reattached to the remaining model. + + Based on the following: + https://djangosnippets.org/snippets/2283/ + https://stackoverflow.com/a/41291137/2532070 + https://gist.github.com/edelvalle/01886b6f79ba0c4dce66 + """ + + @signalcommand + def handle(self, *args, **options): + model = get_model_to_deduplicate() + field_names = get_field_names(model) + first_or_last = keep_first_or_last_instance() + total_deleted_objects_count = 0 + for instance in model.objects.all(): + kwargs = {} + for field_name in field_names: + instance_field_value = instance.__getattribute__(field_name) + kwargs.update({ + field_name: instance_field_value + }) + try: + model.objects.get(**kwargs) + except model.MultipleObjectsReturned: + instances = model.objects.filter(**kwargs) + if first_or_last == "first": + primary_object = instances.first() + alias_objects = instances.exclude(pk=primary_object.pk) + elif first_or_last == "last": + primary_object = instances.last() + alias_objects = instances.exclude(pk=primary_object.pk) + + primary_object, deleted_objects, deleted_objects_count = self.merge_model_instances(primary_object, alias_objects) + total_deleted_objects_count += deleted_objects_count + + print("Successfully deleted {} model instances.".format(total_deleted_objects_count)) + + @transaction.atomic() + def merge_model_instances(self, primary_object, alias_objects): + """ + Merge several model instances into one, the `primary_object`. + Use this function to merge model objects and migrate all of the related + fields from the alias objects the primary object. + """ + generic_fields = get_generic_fields() + + # get related fields + related_fields = list(filter( + lambda x: x.is_relation is True, + primary_object._meta.get_fields())) + + many_to_many_fields = list(filter( + lambda x: x.many_to_many is True, related_fields)) + + related_fields = list(filter( + lambda x: x.many_to_many is False, related_fields)) + + # Loop through all alias objects and migrate their references to the + # primary object + deleted_objects = [] + deleted_objects_count = 0 + for alias_object in alias_objects: + # Migrate all foreign key references from alias object to primary + # object. + for many_to_many_field in many_to_many_fields: + alias_varname = many_to_many_field.name + related_objects = getattr(alias_object, alias_varname) + for obj in related_objects.all(): + try: + # Handle regular M2M relationships. + getattr(alias_object, alias_varname).remove(obj) + getattr(primary_object, alias_varname).add(obj) + except AttributeError: + # Handle M2M relationships with a 'through' model. + # This does not delete the 'through model. + # TODO: Allow the user to delete a duplicate 'through' model. + through_model = getattr(alias_object, alias_varname).through + kwargs = { + many_to_many_field.m2m_reverse_field_name(): obj, + many_to_many_field.m2m_field_name(): alias_object, + } + through_model_instances = through_model.objects.filter(**kwargs) + for instance in through_model_instances: + # Re-attach the through model to the primary_object + setattr( + instance, + many_to_many_field.m2m_field_name(), + primary_object) + instance.save() + # TODO: Here, try to delete duplicate instances that are + # disallowed by a unique_together constraint + + for related_field in related_fields: + if related_field.one_to_many: + alias_varname = related_field.get_accessor_name() + related_objects = getattr(alias_object, alias_varname) + for obj in related_objects.all(): + field_name = related_field.field.name + setattr(obj, field_name, primary_object) + obj.save() + elif related_field.one_to_one or related_field.many_to_one: + alias_varname = related_field.name + related_object = getattr(alias_object, alias_varname) + primary_related_object = getattr(primary_object, alias_varname) + if primary_related_object is None: + setattr(primary_object, alias_varname, related_object) + primary_object.save() + elif related_field.one_to_one: + self.stdout.write("Deleted {} with id {}\n".format( + related_object, related_object.id)) + related_object.delete() + + for field in generic_fields: + filter_kwargs = {} + filter_kwargs[field.fk_field] = alias_object._get_pk_val() + filter_kwargs[field.ct_field] = field.get_content_type(alias_object) + related_objects = field.model.objects.filter(**filter_kwargs) + for generic_related_object in related_objects: + setattr(generic_related_object, field.name, primary_object) + generic_related_object.save() + + if alias_object.id: + deleted_objects += [alias_object] + self.stdout.write("Deleted {} with id {}\n".format( + alias_object, alias_object.id)) + alias_object.delete() + deleted_objects_count += 1 + + return primary_object, deleted_objects, deleted_objects_count diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/notes.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/notes.py new file mode 100644 index 0000000..194f37e --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/notes.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +import os +import re + +from django.conf import settings +from django.core.management.base import BaseCommand + +from django_extensions.compat import get_template_setting +from django_extensions.management.utils import signalcommand + +ANNOTATION_RE = re.compile(r"\{?#[\s]*?(TODO|FIXME|BUG|HACK|WARNING|NOTE|XXX)[\s:]?(.+)") +ANNOTATION_END_RE = re.compile(r"(.*)#\}(.*)") + + +class Command(BaseCommand): + help = 'Show all annotations like TODO, FIXME, BUG, HACK, WARNING, NOTE or XXX in your py and HTML files.' + label = 'annotation tag (TODO, FIXME, BUG, HACK, WARNING, NOTE, XXX)' + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--tag', + dest='tag', + help='Search for specific tags only', + action='append' + ) + + @signalcommand + def handle(self, *args, **options): + # don't add django internal code + apps = [app.replace(".", "/") for app in filter(lambda app: not app.startswith('django.contrib'), settings.INSTALLED_APPS)] + template_dirs = get_template_setting('DIRS', []) + base_dir = getattr(settings, 'BASE_DIR') + if template_dirs: + apps += template_dirs + for app_dir in apps: + if base_dir: + app_dir = os.path.join(base_dir, app_dir) + for top, dirs, files in os.walk(app_dir): + for fn in files: + if os.path.splitext(fn)[1] in ('.py', '.html'): + fpath = os.path.join(top, fn) + annotation_lines = [] + with open(fpath, 'r') as fd: + i = 0 + for line in fd.readlines(): + i += 1 + if ANNOTATION_RE.search(line): + tag, msg = ANNOTATION_RE.findall(line)[0] + if options['tag']: + if tag not in map(str.upper, map(str, options['tag'])): + break + + if ANNOTATION_END_RE.search(msg.strip()): + msg = ANNOTATION_END_RE.findall(msg.strip())[0][0] + + annotation_lines.append("[%3s] %-5s %s" % (i, tag, msg.strip())) + if annotation_lines: + self.stdout.write("%s:" % fpath) + for annotation in annotation_lines: + self.stdout.write(" * %s" % annotation) + self.stdout.write("") diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/pipchecker.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/pipchecker.py new file mode 100644 index 0000000..0a8724e --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/pipchecker.py @@ -0,0 +1,326 @@ +# -*- coding: utf-8 -*- +import json +import os +import re +from distutils.version import LooseVersion +from urllib.parse import urlparse +from urllib.error import HTTPError +from urllib.request import Request, urlopen +from xmlrpc.client import ServerProxy, Fault + +import pip +from time import sleep +from django.core.management.base import BaseCommand, CommandError +from django_extensions.management.color import color_style +from django_extensions.management.utils import signalcommand +from pip._internal.req import InstallRequirement + +if LooseVersion(pip.__version__) >= LooseVersion('19.0'): + from pip._internal.req.constructors import install_req_from_line # noqa + +try: + try: + from pip._internal.network.session import PipSession + except ImportError: + from pip._internal.download import PipSession + from pip._internal.req.req_file import parse_requirements + from pip._internal.utils.misc import get_installed_distributions +except ImportError: + # pip < 10 + try: + from pip import get_installed_distributions + from pip.download import PipSession + from pip.req import parse_requirements + except ImportError: + raise CommandError("Pip version 6 or higher is required") + +try: + import requests + HAS_REQUESTS = True +except ImportError: + HAS_REQUESTS = False + + +class Command(BaseCommand): + help = "Scan pip requirement files for out-of-date packages." + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + "-t", "--github-api-token", action="store", + dest="github_api_token", help="A github api authentication token." + ) + parser.add_argument( + "-r", "--requirement", action="append", dest="requirements", + default=[], metavar="FILENAME", + help="Check all the packages listed in the given requirements " + "file. This option can be used multiple times." + ), + parser.add_argument( + "-n", "--newer", action="store_true", dest="show_newer", + help="Also show when newer version then available is installed." + ) + + @signalcommand + def handle(self, *args, **options): + self.style = color_style() + + self.options = options + if options["requirements"]: + req_files = options["requirements"] + elif os.path.exists("requirements.txt"): + req_files = ["requirements.txt"] + elif os.path.exists("requirements"): + req_files = [ + "requirements/{0}".format(f) for f in os.listdir("requirements") + if os.path.isfile(os.path.join("requirements", f)) and f.lower().endswith(".txt") + ] + elif os.path.exists("requirements-dev.txt"): + req_files = ["requirements-dev.txt"] + elif os.path.exists("requirements-prod.txt"): + req_files = ["requirements-prod.txt"] + else: + raise CommandError("Requirements file(s) not found") + + self.reqs = {} + with PipSession() as session: + for filename in req_files: + for req in parse_requirements(filename, session=session): + if not isinstance(req, InstallRequirement): + req = install_req_from_line(req.requirement) + name = req.name if req.name else req.link.filename + + # url attribute changed to link in pip version 6.1.0 and above + if LooseVersion(pip.__version__) > LooseVersion('6.0.8'): + self.reqs[name] = { + "pip_req": req, + "url": req.link, + } + else: + self.reqs[name] = { + "pip_req": req, + "url": req.url, + } + + if options["github_api_token"]: + self.github_api_token = options["github_api_token"] + elif os.environ.get("GITHUB_API_TOKEN"): + self.github_api_token = os.environ.get("GITHUB_API_TOKEN") + else: + self.github_api_token = None # only 50 requests per hour + + self.check_pypi() + if HAS_REQUESTS: + self.check_github() + else: + self.stdout.write(self.style.ERROR("Cannot check github urls. The requests library is not installed. ( pip install requests )")) + self.check_other() + + def _urlopen_as_json(self, url, headers=None): + """Shorcut for return contents as json""" + req = Request(url, headers=headers) + return json.loads(urlopen(req).read()) + + def _is_stable(self, version): + return not re.search(r'([ab]|rc|dev)\d+$', str(version)) + + def _available_version(self, dist_version, available): + if self._is_stable(dist_version): + stable = [v for v in available if self._is_stable(LooseVersion(v))] + if stable: + return LooseVersion(stable[0]) + + return LooseVersion(available[0]) if available else None + + def check_pypi(self): + """If the requirement is frozen to pypi, check for a new version.""" + for dist in get_installed_distributions(): + name = dist.project_name + if name in self.reqs.keys(): + self.reqs[name]["dist"] = dist + + pypi = ServerProxy("https://pypi.python.org/pypi") + for name, req in list(self.reqs.items()): + if req["url"]: + continue # skipping github packages. + elif "dist" in req: + dist = req["dist"] + dist_version = LooseVersion(dist.version) + retry = True + available = None + while retry: + try: + available = pypi.package_releases(req["pip_req"].name, True) or pypi.package_releases(req["pip_req"].name.replace('-', '_'), True) + retry = False + except Fault as err: + self.stdout.write(err.faultString) + self.stdout.write("Retrying in 60 seconds!") + sleep(60) + + available_version = self._available_version(dist_version, available) + + if not available_version: + msg = self.style.WARN("release is not on pypi (check capitalization and/or --extra-index-url)") + elif self.options['show_newer'] and dist_version > available_version: + msg = self.style.INFO("{0} available (newer installed)".format(available_version)) + elif available_version > dist_version: + msg = self.style.INFO("{0} available".format(available_version)) + else: + msg = "up to date" + del self.reqs[name] + continue + pkg_info = self.style.BOLD("{dist.project_name} {dist.version}".format(dist=dist)) + else: + msg = "not installed" + pkg_info = name + self.stdout.write("{pkg_info:40} {msg}".format(pkg_info=pkg_info, msg=msg)) + del self.reqs[name] + + def check_github(self): + """ + If the requirement is frozen to a github url, check for new commits. + + API Tokens + ---------- + For more than 50 github api calls per hour, pipchecker requires + authentication with the github api by settings the environemnt + variable ``GITHUB_API_TOKEN`` or setting the command flag + --github-api-token='mytoken'``. + + To create a github api token for use at the command line:: + curl -u 'rizumu' -d '{"scopes":["repo"], "note":"pipchecker"}' https://api.github.com/authorizations + + For more info on github api tokens: + https://help.github.com/articles/creating-an-oauth-token-for-command-line-use + http://developer.github.com/v3/oauth/#oauth-authorizations-api + + Requirement Format + ------------------ + Pipchecker gets the sha of frozen repo and checks if it is + found at the head of any branches. If it is not found then + the requirement is considered to be out of date. + + Therefore, freezing at the commit hash will provide the expected + results, but if freezing at a branch or tag name, pipchecker will + not be able to determine with certainty if the repo is out of date. + + Freeze at the commit hash (sha):: + git+git://github.com/django/django.git@393c268e725f5b229ecb554f3fac02cfc250d2df#egg=Django + https://github.com/django/django/archive/393c268e725f5b229ecb554f3fac02cfc250d2df.tar.gz#egg=Django + https://github.com/django/django/archive/393c268e725f5b229ecb554f3fac02cfc250d2df.zip#egg=Django + + Freeze with a branch name:: + git+git://github.com/django/django.git@master#egg=Django + https://github.com/django/django/archive/master.tar.gz#egg=Django + https://github.com/django/django/archive/master.zip#egg=Django + + Freeze with a tag:: + git+git://github.com/django/django.git@1.5b2#egg=Django + https://github.com/django/django/archive/1.5b2.tar.gz#egg=Django + https://github.com/django/django/archive/1.5b2.zip#egg=Django + + Do not freeze:: + git+git://github.com/django/django.git#egg=Django + + """ + for name, req in list(self.reqs.items()): + req_url = req["url"] + if not req_url: + continue + req_url = str(req_url) + if req_url.startswith("git") and "github.com/" not in req_url: + continue + if req_url.endswith((".tar.gz", ".tar.bz2", ".zip")): + continue + + headers = { + "content-type": "application/json", + } + if self.github_api_token: + headers["Authorization"] = "token {0}".format(self.github_api_token) + try: + path_parts = urlparse(req_url).path.split("#", 1)[0].strip("/").rstrip("/").split("/") + + if len(path_parts) == 2: + user, repo = path_parts + + elif 'archive' in path_parts: + # Supports URL of format: + # https://github.com/django/django/archive/master.tar.gz#egg=Django + # https://github.com/django/django/archive/master.zip#egg=Django + user, repo = path_parts[:2] + repo += '@' + path_parts[-1].replace('.tar.gz', '').replace('.zip', '') + + else: + self.style.ERROR("\nFailed to parse %r\n" % (req_url, )) + continue + except (ValueError, IndexError) as e: + self.stdout.write(self.style.ERROR("\nFailed to parse %r: %s\n" % (req_url, e))) + continue + + try: + test_auth = requests.get("https://api.github.com/django/", headers=headers).json() + except HTTPError as e: + self.stdout.write("\n%s\n" % str(e)) + return + + if "message" in test_auth and test_auth["message"] == "Bad credentials": + self.stdout.write(self.style.ERROR("\nGithub API: Bad credentials. Aborting!\n")) + return + elif "message" in test_auth and test_auth["message"].startswith("API Rate Limit Exceeded"): + self.stdout.write(self.style.ERROR("\nGithub API: Rate Limit Exceeded. Aborting!\n")) + return + + frozen_commit_sha = None + if ".git" in repo: + repo_name, frozen_commit_full = repo.split(".git") + if frozen_commit_full.startswith("@"): + frozen_commit_sha = frozen_commit_full[1:] + elif "@" in repo: + repo_name, frozen_commit_sha = repo.split("@") + + if frozen_commit_sha is None: + msg = self.style.ERROR("repo is not frozen") + + if frozen_commit_sha: + branch_url = "https://api.github.com/repos/{0}/{1}/branches".format(user, repo_name) + branch_data = requests.get(branch_url, headers=headers).json() + + frozen_commit_url = "https://api.github.com/repos/{0}/{1}/commits/{2}".format( + user, repo_name, frozen_commit_sha + ) + frozen_commit_data = requests.get(frozen_commit_url, headers=headers).json() + + if "message" in frozen_commit_data and frozen_commit_data["message"] == "Not Found": + msg = self.style.ERROR("{0} not found in {1}. Repo may be private.".format(frozen_commit_sha[:10], name)) + elif frozen_commit_data["sha"] in [branch["commit"]["sha"] for branch in branch_data]: + msg = self.style.BOLD("up to date") + else: + msg = self.style.INFO("{0} is not the head of any branch".format(frozen_commit_data["sha"][:10])) + + if "dist" in req: + pkg_info = "{dist.project_name} {dist.version}".format(dist=req["dist"]) + elif frozen_commit_sha is None: + pkg_info = name + else: + pkg_info = "{0} {1}".format(name, frozen_commit_sha[:10]) + self.stdout.write("{pkg_info:40} {msg}".format(pkg_info=pkg_info, msg=msg)) + del self.reqs[name] + + def check_other(self): + """ + If the requirement is frozen somewhere other than pypi or github, skip. + + If you have a private pypi or use --extra-index-url, consider contributing + support here. + """ + if self.reqs: + self.stdout.write(self.style.ERROR("\nOnly pypi and github based requirements are supported:")) + for name, req in self.reqs.items(): + if "dist" in req: + pkg_info = "{dist.project_name} {dist.version}".format(dist=req["dist"]) + elif "url" in req: + pkg_info = "{url}".format(url=req["url"]) + else: + pkg_info = "unknown package" + self.stdout.write(self.style.BOLD("{pkg_info:40} is not a pypi or github requirement".format(pkg_info=pkg_info))) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/print_settings.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/print_settings.py new file mode 100644 index 0000000..969bf01 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/print_settings.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +""" +print_settings +============== + +Django command similar to 'diffsettings' but shows all active Django settings. +""" + +import fnmatch +import json + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError + +from django_extensions.management.utils import signalcommand + + +class Command(BaseCommand): + help = "Print the active Django settings." + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + 'setting', + nargs='*', + help='Specifies setting to be printed.' + ) + parser.add_argument( + '-f', '--fail', + action='store_true', + dest='fail', + help='Fail if invalid setting name is given.' + ) + parser.add_argument( + '--format', + default='simple', + dest='format', + help='Specifies output format.' + ) + parser.add_argument( + '--indent', + default=4, + dest='indent', + type=int, + help='Specifies indent level for JSON and YAML' + ) + + @signalcommand + def handle(self, *args, **options): + setting_names = options['setting'] + settings_dct = {k: getattr(settings, k) for k in dir(settings) if k.isupper()} + + if setting_names: + settings_dct = { + key: value for key, value in settings_dct.items() + if any(fnmatch.fnmatchcase(key, setting_name) for setting_name in setting_names) + } + + if options['fail']: + for setting_name in setting_names: + if not any(fnmatch.fnmatchcase(key, setting_name) for key in settings_dct.keys()): + raise CommandError('%s not found in settings.' % setting_name) + + output_format = options['format'] + indent = options['indent'] + + if output_format == 'json': + print(json.dumps(settings_dct, indent=indent)) + elif output_format == 'yaml': + import yaml # requires PyYAML + print(yaml.dump(settings_dct, indent=indent)) + elif output_format == 'pprint': + from pprint import pprint + pprint(settings_dct) + elif output_format == 'text': + for key, value in settings_dct.items(): + print("%s = %s" % (key, value)) + elif output_format == 'value': + for value in settings_dct.values(): + print(value) + else: + for key, value in settings_dct.items(): + print('%-40s = %r' % (key, value)) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/print_user_for_session.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/print_user_for_session.py new file mode 100644 index 0000000..e12d839 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/print_user_for_session.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +import importlib + +from django.conf import settings +from django.contrib.auth import load_backend, BACKEND_SESSION_KEY, SESSION_KEY +from django.contrib.sessions.backends.base import VALID_KEY_CHARS +from django.core.management.base import BaseCommand, CommandError +from django_extensions.management.utils import signalcommand + + +class Command(BaseCommand): + help = ("print the user information for the provided session key. " + "this is very helpful when trying to track down the person who " + "experienced a site crash.") + + def add_arguments(self, parser): + parser.add_argument('session_id', nargs='+', type=str, + help='user session id') + + @signalcommand + def handle(self, *args, **options): + + key = options['session_id'][0] + + if not set(key).issubset(set(VALID_KEY_CHARS)): + raise CommandError("malformed session key") + + engine = importlib.import_module(settings.SESSION_ENGINE) + + if not engine.SessionStore().exists(key): + print("Session Key does not exist. Expired?") + return + + session = engine.SessionStore(key) + data = session.load() + + print('Session to Expire: %s' % session.get_expiry_date()) + print('Raw Data: %s' % data) + uid = data.get(SESSION_KEY, None) + backend_path = data.get(BACKEND_SESSION_KEY, None) + + if backend_path is None: + print('No authentication backend associated with session') + return + + if uid is None: + print('No user associated with session') + return + + print(u"User id: %s" % uid) + + backend = load_backend(backend_path) + user = backend.get_user(user_id=uid) + if user is None: + print("No user associated with that id.") + return + + # use django standrd api for reporting + print("full name: %s" % user.get_full_name()) + print("short name: %s" % user.get_short_name()) + print("username: %s" % user.get_username()) + if hasattr(user, 'email'): + print("email: %s" % user.email) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/reset_db.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/reset_db.py new file mode 100644 index 0000000..bca8247 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/reset_db.py @@ -0,0 +1,195 @@ +# -*- coding: utf-8 -*- +""" +reset_db command + +originally from http://www.djangosnippets.org/snippets/828/ by dnordberg +""" +import os +import logging +import warnings + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from django.db import DEFAULT_DB_ALIAS + +from django_extensions.settings import SQLITE_ENGINES, POSTGRESQL_ENGINES, MYSQL_ENGINES +from django_extensions.management.mysql import parse_mysql_cnf +from django_extensions.management.utils import signalcommand +from django_extensions.utils.deprecation import RemovedInNextVersionWarning + + +class Command(BaseCommand): + help = "Resets the database for this project." + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--noinput', action='store_false', + dest='interactive', default=True, + help='Tells Django to NOT prompt the user for input of any kind.' + ) + parser.add_argument( + '--no-utf8', action='store_true', dest='no_utf8_support', + default=False, + help='Tells Django to not create a UTF-8 charset database' + ) + parser.add_argument( + '-U', '--user', action='store', dest='user', default=None, + help='Use another user for the database than defined in settings.py' + ) + parser.add_argument( + '-O', '--owner', action='store', dest='owner', default=None, + help='Use another owner for creating the database than the user defined in settings or via --user' + ) + parser.add_argument( + '-P', '--password', action='store', dest='password', default=None, + help='Use another password for the database than defined in settings.py' + ) + parser.add_argument( + '-D', '--dbname', action='store', dest='dbname', default=None, + help='Use another database name than defined in settings.py' + ) + parser.add_argument( + '-R', '--router', action='store', dest='router', default=DEFAULT_DB_ALIAS, + help='Use this router-database other than defined in settings.py' + ) + parser.add_argument( + '--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to run command for. Defaults to the "%s" database.' % DEFAULT_DB_ALIAS, + ) + parser.add_argument( + '-c', '--close-sessions', action='store_true', dest='close_sessions', default=False, + help='Close database connections before dropping database (PostgreSQL only)' + ) + + @signalcommand + def handle(self, *args, **options): + """ + Reset the database for this project. + + Note: Transaction wrappers are in reverse as a work around for + autocommit, anybody know how to do this the right way? + """ + database = options['database'] + if options['router'] != DEFAULT_DB_ALIAS: + warnings.warn("--router is deprecated. You should use --database.", RemovedInNextVersionWarning, stacklevel=2) + database = options['router'] + + dbinfo = settings.DATABASES.get(database) + if dbinfo is None: + raise CommandError("Unknown database %s" % database) + + engine = dbinfo.get('ENGINE') + + user = password = database_name = database_host = database_port = '' + if engine == 'mysql': + (user, password, database_name, database_host, database_port) = parse_mysql_cnf(dbinfo) + + user = options['user'] or dbinfo.get('USER') or user + password = options['password'] or dbinfo.get('PASSWORD') or password + owner = options['owner'] or user + + database_name = options['dbname'] or dbinfo.get('NAME') or database_name + if database_name == '': + raise CommandError("You need to specify DATABASE_NAME in your Django settings file.") + + database_host = dbinfo.get('HOST') or database_host + database_port = dbinfo.get('PORT') or database_port + + verbosity = options["verbosity"] + if options['interactive']: + confirm = input(""" +You have requested a database reset. +This will IRREVERSIBLY DESTROY +ALL data in the database "%s". +Are you sure you want to do this? + +Type 'yes' to continue, or 'no' to cancel: """ % (database_name,)) + else: + confirm = 'yes' + + if confirm != 'yes': + print("Reset cancelled.") + return + + if engine in SQLITE_ENGINES: + try: + logging.info("Unlinking %s database", engine) + os.unlink(database_name) + except OSError: + pass + elif engine in MYSQL_ENGINES: + import MySQLdb as Database + kwargs = { + 'user': user, + 'passwd': password, + } + if database_host.startswith('/'): + kwargs['unix_socket'] = database_host + else: + kwargs['host'] = database_host + + if database_port: + kwargs['port'] = int(database_port) + + connection = Database.connect(**kwargs) + drop_query = 'DROP DATABASE IF EXISTS `%s`' % database_name + utf8_support = '' if options['no_utf8_support'] else 'CHARACTER SET utf8' + create_query = 'CREATE DATABASE `%s` %s' % (database_name, utf8_support) + logging.info('Executing... "%s"', drop_query) + connection.query(drop_query) + logging.info('Executing... "%s"', create_query) + connection.query(create_query.strip()) + elif engine in POSTGRESQL_ENGINES: + import psycopg2 as Database # NOQA + + conn_params = {'database': 'template1'} + if user: + conn_params['user'] = user + if password: + conn_params['password'] = password + if database_host: + conn_params['host'] = database_host + if database_port: + conn_params['port'] = database_port + + connection = Database.connect(**conn_params) + connection.set_isolation_level(0) # autocommit false + cursor = connection.cursor() + + if options['close_sessions']: + close_sessions_query = """ + SELECT pg_terminate_backend(pg_stat_activity.pid) + FROM pg_stat_activity + WHERE pg_stat_activity.datname = '%s'; + """ % database_name + logging.info('Executing... "%s"', close_sessions_query.strip()) + try: + cursor.execute(close_sessions_query) + except Database.ProgrammingError as e: + logging.exception("Error: %s", str(e)) + + drop_query = "DROP DATABASE \"%s\";" % database_name + logging.info('Executing... "%s"', drop_query) + try: + cursor.execute(drop_query) + except Database.ProgrammingError as e: + logging.exception("Error: %s", str(e)) + + create_query = "CREATE DATABASE \"%s\"" % database_name + if owner: + create_query += " WITH OWNER = \"%s\" " % owner + create_query += " ENCODING = 'UTF8'" + + if settings.DEFAULT_TABLESPACE: + create_query += ' TABLESPACE = %s;' % settings.DEFAULT_TABLESPACE + else: + create_query += ';' + + logging.info('Executing... "%s"', create_query) + cursor.execute(create_query) + else: + raise CommandError("Unknown database engine %s" % engine) + + if verbosity >= 2 or options['interactive']: + print("Reset successful.") diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/reset_schema.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/reset_schema.py new file mode 100644 index 0000000..95b5673 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/reset_schema.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +""" +Recreates the public schema for current database (PostgreSQL only). +Useful for Docker environments where you need to reset database +schema while there are active connections. +""" + +import warnings + +from django.core.management import BaseCommand, CommandError +from django.db import DEFAULT_DB_ALIAS +from django.db import connections +from django.conf import settings + +from django_extensions.settings import POSTGRESQL_ENGINES +from django_extensions.utils.deprecation import RemovedInNextVersionWarning + + +class Command(BaseCommand): + """`reset_schema` command implementation.""" + + help = "Recreates the public schema for this project." + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--noinput', action='store_false', + dest='interactive', default=True, + help='Tells Django to NOT prompt the user for input of any kind.' + ) + parser.add_argument( + '-R', '--router', action='store', dest='router', default=DEFAULT_DB_ALIAS, + help='Use this router-database instead of the one defined in settings.py' + ) + parser.add_argument( + '--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to run command for. Defaults to the "%s" database.' % DEFAULT_DB_ALIAS, + ) + parser.add_argument( + '-S', '--schema', action='store', dest='schema', default='public', + help='Drop this schema instead of "public"' + ) + + def handle(self, *args, **options): + database = options['database'] + if options['router'] != DEFAULT_DB_ALIAS: + warnings.warn("--router is deprecated. You should use --database.", RemovedInNextVersionWarning, stacklevel=2) + database = options['router'] + + dbinfo = settings.DATABASES.get(database) + if dbinfo is None: + raise CommandError("Unknown database %s" % database) + + engine = dbinfo.get('ENGINE') + if engine not in POSTGRESQL_ENGINES: + raise CommandError('This command can be used only with PostgreSQL databases.') + + database_name = dbinfo['NAME'] + + schema = options['schema'] + + if options['interactive']: + confirm = input(""" +You have requested a database schema reset. +This will IRREVERSIBLY DESTROY ALL data +in the "{}" schema of database "{}". +Are you sure you want to do this? + +Type 'yes' to continue, or 'no' to cancel: """.format(schema, database_name)) + else: + confirm = 'yes' + + if confirm != 'yes': + print("Reset cancelled.") + return + + with connections[database].cursor() as cursor: + cursor.execute("DROP SCHEMA {} CASCADE".format(schema)) + cursor.execute("CREATE SCHEMA {}".format(schema)) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/runjob.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/runjob.py new file mode 100644 index 0000000..cf1163e --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/runjob.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +import logging + +from django.core.management.base import BaseCommand + +from django_extensions.management.jobs import get_job, print_jobs +from django_extensions.management.utils import setup_logger, signalcommand + +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + help = "Run a single maintenance job." + missing_args_message = "test" + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument('app_name', nargs='?') + parser.add_argument('job_name', nargs='?') + parser.add_argument( + '--list', '-l', action="store_true", dest="list_jobs", + default=False, help="List all jobs with their description" + ) + + def runjob(self, app_name, job_name, options): + verbosity = options["verbosity"] + if verbosity > 1: + logger.info("Executing job: %s (app: %s)", job_name, app_name) + try: + job = get_job(app_name, job_name) + except KeyError: + if app_name: + logger.error("Error: Job %s for applabel %s not found", job_name, app_name) + else: + logger.error("Error: Job %s not found", job_name) + logger.info("Use -l option to view all the available jobs") + return + try: + job().execute() + except Exception: + logger.exception("ERROR OCCURED IN JOB: %s (APP: %s)", job_name, app_name) + + @signalcommand + def handle(self, *args, **options): + app_name = options['app_name'] + job_name = options['job_name'] + + # hack since we are using job_name nargs='?' for -l to work + if app_name and not job_name: + job_name = app_name + app_name = None + + setup_logger(logger, self.stdout) + + if options['list_jobs']: + print_jobs(only_scheduled=False, show_when=True, show_appname=True) + else: + self.runjob(app_name, job_name, options) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/runjobs.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/runjobs.py new file mode 100644 index 0000000..ecddc07 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/runjobs.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +import logging + +from django.apps import apps +from django.core.management.base import BaseCommand + +from django_extensions.management.jobs import get_jobs, print_jobs +from django_extensions.management.utils import setup_logger, signalcommand + +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + help = "Runs scheduled maintenance jobs." + + when_options = ['minutely', 'quarter_hourly', 'hourly', 'daily', 'weekly', 'monthly', 'yearly'] + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + 'when', nargs='?', + help="options: %s" % ', '.join(self.when_options) + ) + parser.add_argument( + '--list', '-l', action="store_true", dest="list_jobs", + default=False, help="List all jobs with their description" + ) + + def usage_msg(self): + print("%s Please specify: %s" % (self.help, ', '.join(self.when_options))) + + def runjobs(self, when, options): + verbosity = options["verbosity"] + jobs = get_jobs(when, only_scheduled=True) + for app_name, job_name in sorted(jobs.keys()): + job = jobs[(app_name, job_name)] + if verbosity > 1: + logger.info("Executing %s job: %s (app: %s)", when, job_name, app_name) + try: + job().execute() + except Exception: + logger.exception("ERROR OCCURED IN JOB: %s (APP: %s)", job_name, app_name) + + def runjobs_by_signals(self, when, options): + """ Run jobs from the signals """ + # Thanks for Ian Holsman for the idea and code + from django_extensions.management import signals + from django.conf import settings + + verbosity = options["verbosity"] + for app_name in settings.INSTALLED_APPS: + try: + __import__(app_name + '.management', '', '', ['']) + except ImportError: + pass + + for app in (app.models_module for app in apps.get_app_configs() if app.models_module): + if verbosity > 1: + app_name = '.'.join(app.__name__.rsplit('.')[:-1]) + print("Sending %s job signal for: %s" % (when, app_name)) + if when == 'minutely': + signals.run_minutely_jobs.send(sender=app, app=app) + elif when == 'quarter_hourly': + signals.run_quarter_hourly_jobs.send(sender=app, app=app) + elif when == 'hourly': + signals.run_hourly_jobs.send(sender=app, app=app) + elif when == 'daily': + signals.run_daily_jobs.send(sender=app, app=app) + elif when == 'weekly': + signals.run_weekly_jobs.send(sender=app, app=app) + elif when == 'monthly': + signals.run_monthly_jobs.send(sender=app, app=app) + elif when == 'yearly': + signals.run_yearly_jobs.send(sender=app, app=app) + + @signalcommand + def handle(self, *args, **options): + when = options['when'] + + setup_logger(logger, self.stdout) + + if options['list_jobs']: + print_jobs(when, only_scheduled=True, show_when=True, show_appname=True) + elif when in self.when_options: + self.runjobs(when, options) + self.runjobs_by_signals(when, options) + else: + self.usage_msg() diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/runprofileserver.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/runprofileserver.py new file mode 100644 index 0000000..9859fb6 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/runprofileserver.py @@ -0,0 +1,291 @@ +# -*- coding: utf-8 -*- +""" +runprofileserver.py + + Starts a lightweight Web server with profiling enabled. + +Credits for kcachegrind support taken from lsprofcalltree.py go to: + David Allouche + Jp Calderone & Itamar Shtull-Trauring + Johan Dahlin +""" + +import sys +from datetime import datetime + +from django.conf import settings +from django.contrib.staticfiles.handlers import StaticFilesHandler +from django.core.management.base import BaseCommand, CommandError +from django.core.servers.basehttp import get_internal_wsgi_application + +from django_extensions.management.utils import signalcommand + +USE_STATICFILES = 'django.contrib.staticfiles' in settings.INSTALLED_APPS + + +class KCacheGrind: + def __init__(self, profiler): + self.data = profiler.getstats() + self.out_file = None + + def output(self, out_file): + self.out_file = out_file + self.out_file.write('events: Ticks\n') + self._print_summary() + for entry in self.data: + self._entry(entry) + + def _print_summary(self): + max_cost = 0 + for entry in self.data: + totaltime = int(entry.totaltime * 1000) + max_cost = max(max_cost, totaltime) + self.out_file.write('summary: %d\n' % (max_cost,)) + + def _entry(self, entry): + out_file = self.out_file + + code = entry.code + if isinstance(code, str): + out_file.write('fn=%s\n' % code) + else: + out_file.write('fl=%s\n' % code.co_filename) + out_file.write('fn=%s\n' % code.co_name) + + inlinetime = int(entry.inlinetime * 1000) + if isinstance(code, str): + out_file.write('0 %s\n' % inlinetime) + else: + out_file.write('%d %d\n' % (code.co_firstlineno, inlinetime)) + + # recursive calls are counted in entry.calls + if entry.calls: + calls = entry.calls + else: + calls = [] + + if isinstance(code, str): + lineno = 0 + else: + lineno = code.co_firstlineno + + for subentry in calls: + self._subentry(lineno, subentry) + out_file.write("\n") + + def _subentry(self, lineno, subentry): + out_file = self.out_file + code = subentry.code + if isinstance(code, str): + out_file.write('cfn=%s\n' % code) + out_file.write('calls=%d 0\n' % (subentry.callcount,)) + else: + out_file.write('cfl=%s\n' % code.co_filename) + out_file.write('cfn=%s\n' % code.co_name) + out_file.write('calls=%d %d\n' % (subentry.callcount, code.co_firstlineno)) + + totaltime = int(subentry.totaltime * 1000) + out_file.write('%d %d\n' % (lineno, totaltime)) + + +class Command(BaseCommand): + help = "Starts a lightweight Web server with profiling enabled." + args = '[optional port number, or ipaddr:port]' + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + 'addrport', nargs='?', + help='Optional port number, or ipaddr:port' + ) + parser.add_argument( + '--noreload', action='store_false', dest='use_reloader', + default=True, + help='Tells Django to NOT use the auto-reloader.') + parser.add_argument( + '--nothreading', action='store_false', dest='use_threading', default=True, + help='Tells Django to NOT use threading.', + ) + parser.add_argument( + '--prof-path', dest='prof_path', default='/tmp', + help='Specifies the directory which to save profile information ' + 'in.' + ) + parser.add_argument( + '--prof-file', dest='prof_file', + default='{path}.{duration:06d}ms.{time}', + help='Set filename format, default if ' + '"{path}.{duration:06d}ms.{time}".' + ) + parser.add_argument( + '--nomedia', action='store_true', dest='no_media', default=False, + help='Do not profile MEDIA_URL' + ) + parser.add_argument( + '--use-cprofile', action='store_true', dest='use_cprofile', + default=False, + help='Use cProfile if available, this is disabled per default ' + 'because of incompatibilities.' + ) + parser.add_argument( + '--kcachegrind', action='store_true', dest='use_lsprof', + default=False, + help='Create kcachegrind compatible lsprof files, this requires ' + 'and automatically enables cProfile.' + ) + + if USE_STATICFILES: + parser.add_argument( + '--nostatic', action="store_false", dest='use_static_handler', + default=True, + help='Tells Django to NOT automatically serve static files ' + 'at STATIC_URL.') + parser.add_argument( + '--insecure', action="store_true", dest='insecure_serving', + default=False, + help='Allows serving static files even if DEBUG is False.') + + @signalcommand + def handle(self, addrport='', *args, **options): + import django + import socket + import errno + from django.core.servers.basehttp import run + + if not addrport: + addr = '' + port = '8000' + else: + try: + addr, port = addrport.split(':') + except ValueError: + addr, port = '', addrport + if not addr: + addr = '127.0.0.1' + + if not port.isdigit(): + raise CommandError("%r is not a valid port number." % port) + + use_reloader = options['use_reloader'] + shutdown_message = options.get('shutdown_message', '') + no_media = options['no_media'] + quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C' + + def inner_run(): + import os + import time + try: + import hotshot + HAS_HOTSHOT = True + except ImportError: + HAS_HOTSHOT = False # python 3.x + USE_CPROFILE = options['use_cprofile'] + USE_LSPROF = options['use_lsprof'] + if USE_LSPROF: + USE_CPROFILE = True + if USE_CPROFILE: + try: + import cProfile + USE_CPROFILE = True + except ImportError: + print("cProfile disabled, module cannot be imported!") + USE_CPROFILE = False + if USE_LSPROF and not USE_CPROFILE: + raise CommandError("Kcachegrind compatible output format required cProfile from Python 2.5") + + if not HAS_HOTSHOT and not USE_CPROFILE: + raise CommandError("Hotshot profile library not found. (and not using cProfile)") + + prof_path = options['prof_path'] + + prof_file = options['prof_file'] + if not prof_file.format(path='1', duration=2, time=3): + prof_file = '{path}.{duration:06d}ms.{time}' + print("Filename format is wrong. Default format used: '{path}.{duration:06d}ms.{time}'.") + + def get_exclude_paths(): + exclude_paths = [] + media_url = getattr(settings, 'MEDIA_URL', None) + if media_url: + exclude_paths.append(media_url) + static_url = getattr(settings, 'STATIC_URL', None) + if static_url: + exclude_paths.append(static_url) + return exclude_paths + + def make_profiler_handler(inner_handler): + def handler(environ, start_response): + path_info = environ['PATH_INFO'] + # when using something like a dynamic site middleware is could be necessary + # to refetch the exclude_paths every time since they could change per site. + if no_media and any(path_info.startswith(p) for p in get_exclude_paths()): + return inner_handler(environ, start_response) + path_name = path_info.strip("/").replace('/', '.') or "root" + profname = "%s.%d.prof" % (path_name, time.time()) + profname = os.path.join(prof_path, profname) + if USE_CPROFILE: + prof = cProfile.Profile() + else: + prof = hotshot.Profile(profname) + start = datetime.now() + try: + return prof.runcall(inner_handler, environ, start_response) + finally: + # seeing how long the request took is important! + elap = datetime.now() - start + elapms = elap.seconds * 1000.0 + elap.microseconds / 1000.0 + if USE_LSPROF: + kg = KCacheGrind(prof) + with open(profname, 'w') as f: + kg.output(f) + elif USE_CPROFILE: + prof.dump_stats(profname) + profname2 = prof_file.format(path=path_name, duration=int(elapms), time=int(time.time())) + profname2 = os.path.join(prof_path, "%s.prof" % profname2) + if not USE_CPROFILE: + prof.close() + os.rename(profname, profname2) + return handler + + print("Performing system checks...") + self.check(display_num_errors=True) + + print("\nDjango version %s, using settings %r" % (django.get_version(), settings.SETTINGS_MODULE)) + print("Development server is running at http://%s:%s/" % (addr, port)) + print("Quit the server with %s." % quit_command) + try: + handler = get_internal_wsgi_application() + if USE_STATICFILES: + use_static_handler = options['use_static_handler'] + insecure_serving = options['insecure_serving'] + if use_static_handler and (settings.DEBUG or insecure_serving): + handler = StaticFilesHandler(handler) + handler = make_profiler_handler(handler) + run(addr, int(port), handler, threading=options['use_threading']) + except socket.error as e: + # Use helpful error messages instead of ugly tracebacks. + ERRORS = { + errno.EACCES: "You don't have permission to access that port.", + errno.EADDRINUSE: "That port is already in use.", + errno.EADDRNOTAVAIL: "That IP address can't be assigned-to.", + } + try: + error_text = ERRORS[e.errno] + except (AttributeError, KeyError): + error_text = str(e) + sys.stderr.write(self.style.ERROR("Error: %s" % error_text) + '\n') + # Need to use an OS exit because sys.exit doesn't work in a thread + os._exit(1) + except KeyboardInterrupt: + if shutdown_message: + print(shutdown_message) + sys.exit(0) + if use_reloader: + try: + from django.utils.autoreload import run_with_reloader + run_with_reloader(inner_run) + except ImportError: + from django.utils import autoreload + autoreload.main(inner_run) + else: + inner_run() diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/runscript.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/runscript.py new file mode 100644 index 0000000..a673902 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/runscript.py @@ -0,0 +1,301 @@ +# -*- coding: utf-8 -*- +import os +import sys +import importlib +import inspect +import traceback + +from argparse import ArgumentTypeError + +from django.apps import apps +from django.conf import settings +from django.core.management.base import CommandError + +from django_extensions.management.email_notifications import EmailNotificationCommand +from django_extensions.management.utils import signalcommand + + +class DirPolicyChoices: + NONE = 'none' + EACH = 'each' + ROOT = 'root' + + +def check_is_directory(value): + if value is None or not os.path.isdir(value): + raise ArgumentTypeError("%s is not a directory!" % value) + return value + + +class BadCustomDirectoryException(Exception): + def __init__(self, value): + self.message = value + ' If --dir-policy is custom than you must set correct directory in ' \ + '--dir option or in settings.RUNSCRIPT_CHDIR' + + def __str__(self): + return self.message + + +class Command(EmailNotificationCommand): + help = 'Runs a script in django context.' + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.current_directory = os.getcwd() + self.last_exit_code = 0 + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument('script', nargs='+') + parser.add_argument( + '--fixtures', action='store_true', dest='infixtures', default=False, + help='Also look in app.fixtures subdir', + ) + parser.add_argument( + '--noscripts', action='store_true', dest='noscripts', default=False, + help='Do not look in app.scripts subdir', + ) + parser.add_argument( + '-s', '--silent', action='store_true', dest='silent', default=False, + help='Run silently, do not show errors and tracebacks. Also implies --continue-on-error.', + ) + parser.add_argument( + '-c', '--continue-on-error', action='store_true', dest='continue_on_error', default=False, + help='Continue executing other scripts even though one has failed. ' + 'It will print a traceback unless --no-traceback or --silent are given ' + 'The exit code used when terminating will always be 1.', + ) + parser.add_argument( + '--no-traceback', action='store_true', dest='no_traceback', default=False, + help='Do not show tracebacks', + ) + parser.add_argument( + '--script-args', nargs='*', type=str, + help='Space-separated argument list to be passed to the scripts. Note that the ' + 'same arguments will be passed to all named scripts.', + ) + parser.add_argument( + '--dir-policy', type=str, + choices=[DirPolicyChoices.NONE, DirPolicyChoices.EACH, DirPolicyChoices.ROOT], + help='Policy of selecting scripts execution directory: ' + 'none - start all scripts in current directory ' + 'each - start all scripts in their directories ' + 'root - start all scripts in BASE_DIR directory ', + ) + parser.add_argument( + '--chdir', type=check_is_directory, + help='If dir-policy option is set to custom, than this option determines script execution directory.', + ) + + @signalcommand + def handle(self, *args, **options): + self.check() + self.check_migrations() + + NOTICE = self.style.SQL_TABLE + NOTICE2 = self.style.SQL_FIELD + ERROR = self.style.ERROR + ERROR2 = self.style.NOTICE + + subdirs = [] + scripts = options['script'] + + if not options['noscripts']: + subdirs.append(getattr(settings, 'RUNSCRIPT_SCRIPT_DIR', 'scripts')) + if options['infixtures']: + subdirs.append('fixtures') + verbosity = options["verbosity"] + show_traceback = options['traceback'] + no_traceback = options['no_traceback'] + continue_on_error = options['continue_on_error'] + if no_traceback: + show_traceback = False + else: + show_traceback = True + silent = options['silent'] + if silent: + verbosity = 0 + continue_on_error = True + email_notifications = options['email_notifications'] + + if len(subdirs) < 1: + print(NOTICE("No subdirs to run left.")) + return + + if len(scripts) < 1: + print(ERROR("Script name required.")) + return + + def get_directory_from_chdir(): + directory = options['chdir'] or getattr(settings, 'RUNSCRIPT_CHDIR', None) + try: + check_is_directory(directory) + except ArgumentTypeError as e: + raise BadCustomDirectoryException(str(e)) + return directory + + def get_directory_basing_on_policy(script_module): + policy = options['dir_policy'] or getattr(settings, 'RUNSCRIPT_CHDIR_POLICY', DirPolicyChoices.NONE) + if policy == DirPolicyChoices.ROOT: + return settings.BASE_DIR + elif policy == DirPolicyChoices.EACH: + return os.path.dirname(inspect.getfile(script_module)) + else: + return self.current_directory + + def set_directory(script_module): + if options['chdir']: + directory = get_directory_from_chdir() + elif options['dir_policy']: + directory = get_directory_basing_on_policy(script_module) + elif getattr(settings, 'RUNSCRIPT_CHDIR', None): + directory = get_directory_from_chdir() + else: + directory = get_directory_basing_on_policy(script_module) + os.chdir(os.path.abspath(directory)) + + def run_script(mod, *script_args): + exit_code = None + try: + set_directory(mod) + exit_code = mod.run(*script_args) + if isinstance(exit_code, bool): + # convert boolean True to exit-code 0 and False to exit-code 1 + exit_code = 1 if exit_code else 0 + if isinstance(exit_code, int): + if exit_code != 0: + try: + raise CommandError("'%s' failed with exit code %s" % (mod.__name__, exit_code), returncode=exit_code) + except TypeError: + raise CommandError("'%s' failed with exit code %s" % (mod.__name__, exit_code)) + if email_notifications: + self.send_email_notification(notification_id=mod.__name__) + except Exception as e: + if isinstance(e, CommandError) and hasattr(e, 'returncode'): + exit_code = e.returncode + self.last_exit_code = exit_code if isinstance(exit_code, int) else 1 + if silent: + return + if verbosity > 0: + print(ERROR("Exception while running run() in '%s'" % mod.__name__)) + if continue_on_error: + if show_traceback: + traceback.print_exc() + return + if email_notifications: + self.send_email_notification(notification_id=mod.__name__, include_traceback=True) + + if no_traceback: + raise CommandError(repr(e)) + + raise + + def my_import(parent_package, module_name): + full_module_path = "%s.%s" % (parent_package, module_name) + if verbosity > 1: + print(NOTICE("Check for %s" % full_module_path)) + # Try importing the parent package first + try: + importlib.import_module(parent_package) + except ImportError as e: + if str(e).startswith('No module named'): + # No need to proceed if the parent package doesn't exist + return False + + try: + t = importlib.import_module(full_module_path) + except ImportError as e: + # The parent package exists, but the module doesn't + try: + if importlib.util.find_spec(full_module_path) is None: + return False + except Exception: + module_file = os.path.join(settings.BASE_DIR, *full_module_path.split('.')) + '.py' + if not os.path.isfile(module_file): + return False + + if silent: + return False + if show_traceback: + traceback.print_exc() + if verbosity > 0: + print(ERROR("Cannot import module '%s': %s." % (full_module_path, e))) + + return False + + if hasattr(t, "run"): + if verbosity > 1: + print(NOTICE2("Found script '%s' ..." % full_module_path)) + return t + else: + if verbosity > 1: + print(ERROR2("Found script '%s' but no run() function found." % full_module_path)) + + def find_modules_for_script(script): + """ Find script module which contains 'run' attribute """ + modules = [] + # first look in apps + for app in apps.get_app_configs(): + for subdir in subdirs: + mod = my_import("%s.%s" % (app.name, subdir), script) + if mod: + modules.append(mod) + # try direct import + if script.find(".") != -1: + parent, mod_name = script.rsplit(".", 1) + mod = my_import(parent, mod_name) + if mod: + modules.append(mod) + else: + # try app.DIR.script import + for subdir in subdirs: + mod = my_import(subdir, script) + if mod: + modules.append(mod) + + return modules + + if options['script_args']: + script_args = options['script_args'] + else: + script_args = [] + + # first pass to check if all scripts can be found + script_to_run = [] + for script in scripts: + script_modules = find_modules_for_script(script) + if not script_modules: + self.last_exit_code = 1 + if verbosity > 0 and not silent: + print(ERROR("No (valid) module for script '%s' found" % script)) + continue + script_to_run.extend(script_modules) + + if self.last_exit_code: + if verbosity < 2 and not silent: + print(ERROR("Try running with a higher verbosity level like: -v2 or -v3")) + if not continue_on_error: + script_to_run = [] + + for script_mod in script_to_run: + if verbosity > 1: + print(NOTICE2("Running script '%s' ..." % script_mod.__name__)) + run_script(script_mod, *script_args) + + if self.last_exit_code != 0: + if silent: + if hasattr(self, 'running_tests'): + return + sys.exit(self.last_exit_code) + + try: + raise CommandError("An error has occurred running scripts. See errors above.", returncode=self.last_exit_code) + except TypeError: + # Django < 3.1 fallback + if self.last_exit_code == 1: + # if exit_code is 1 we can still raise CommandError without returncode argument + raise CommandError("An error has occurred running scripts. See errors above.") + print(ERROR("An error has occurred running scripts. See errors above.")) + if hasattr(self, 'running_tests'): + return + sys.exit(self.last_exit_code) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/runserver_plus.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/runserver_plus.py new file mode 100644 index 0000000..3f69485 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/runserver_plus.py @@ -0,0 +1,487 @@ +# -*- coding: utf-8 -*- +import logging +import os +import re +import socket +import sys +import traceback +import webbrowser +import functools +from typing import Set + +import django +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError, SystemCheckError +from django.core.management.color import color_style +from django.core.servers.basehttp import get_internal_wsgi_application +from django.dispatch import Signal +from django.utils.autoreload import get_reloader +from django.views import debug as django_views_debug + +try: + if 'whitenoise.runserver_nostatic' in settings.INSTALLED_APPS: + USE_STATICFILES = False + else: + from django.contrib.staticfiles.handlers import StaticFilesHandler + USE_STATICFILES = True +except ImportError: + USE_STATICFILES = False + +try: + from werkzeug import run_simple + from werkzeug.debug import DebuggedApplication + from werkzeug.serving import WSGIRequestHandler as _WSGIRequestHandler + from werkzeug.serving import make_ssl_devcert + from werkzeug._internal import _log # type: ignore + from werkzeug import _reloader + HAS_WERKZEUG = True +except ImportError: + HAS_WERKZEUG = False + +try: + import OpenSSL # NOQA + HAS_OPENSSL = True +except ImportError: + HAS_OPENSSL = False + +from django_extensions.management.technical_response import null_technical_500_response +from django_extensions.management.utils import RedirectHandler, has_ipdb, setup_logger, signalcommand +from django_extensions.management.debug_cursor import monkey_patch_cursordebugwrapper + + +runserver_plus_started = Signal() +naiveip_re = re.compile(r"""^(?: +(?P + (?P\d{1,3}(?:\.\d{1,3}){3}) | # IPv4 address + (?P\[[a-fA-F0-9:]+\]) | # IPv6 address + (?P[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*) # FQDN +):)?(?P\d+)$""", re.X) +# 7-bit C1 ANSI sequences (https://stackoverflow.com/questions/14693701/how-can-i-remove-the-ansi-escape-sequences-from-a-string-in-python) +ansi_escape = re.compile(r''' + \x1B # ESC + (?: # 7-bit C1 Fe (except CSI) + [@-Z\\-_] + | # or [ for CSI, followed by a control sequence + \[ + [0-?]* # Parameter bytes + [ -/]* # Intermediate bytes + [@-~] # Final byte + ) +''', re.VERBOSE) +DEFAULT_PORT = "8000" +DEFAULT_POLLER_RELOADER_INTERVAL = getattr(settings, 'RUNSERVERPLUS_POLLER_RELOADER_INTERVAL', 1) +DEFAULT_POLLER_RELOADER_TYPE = getattr(settings, 'RUNSERVERPLUS_POLLER_RELOADER_TYPE', 'auto') + +logger = logging.getLogger(__name__) +_error_files = set() # type: Set[str] + + +if HAS_WERKZEUG: + # Monkey patch the reloader to support adding more files to extra_files + for name, reloader_loop_klass in _reloader.reloader_loops.items(): + class WrappedReloaderLoop(reloader_loop_klass): # type: ignore + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._extra_files = self.extra_files + + @property + def extra_files(self): + return self._extra_files.union(_error_files) + + @extra_files.setter + def extra_files(self, extra_files): + self._extra_files = extra_files + + _reloader.reloader_loops[name] = WrappedReloaderLoop + + +def gen_filenames(): + return get_reloader().watched_files() + + +def check_errors(fn): + # Inspired by https://github.com/django/django/blob/master/django/utils/autoreload.py + @functools.wraps(fn) + def wrapper(*args, **kwargs): + try: + return fn(*args, **kwargs) + except Exception: + _exception = sys.exc_info() + + _, ev, tb = _exception + + if getattr(ev, 'filename', None) is None: + # get the filename from the last item in the stack + filename = traceback.extract_tb(tb)[-1][0] + else: + filename = ev.filename + + if filename not in _error_files: + _error_files.add(filename) + + raise + + return wrapper + + +class Command(BaseCommand): + help = "Starts a lightweight Web server for development." + + # Validation is called explicitly each time the server is reloaded. + requires_system_checks = False + DEFAULT_CRT_EXTENSION = ".crt" + DEFAULT_KEY_EXTENSION = ".key" + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument('addrport', nargs='?', + help='Optional port number, or ipaddr:port') + parser.add_argument('--ipv6', '-6', action='store_true', dest='use_ipv6', default=False, + help='Tells Django to use a IPv6 address.') + parser.add_argument('--noreload', action='store_false', dest='use_reloader', default=True, + help='Tells Django to NOT use the auto-reloader.') + parser.add_argument('--browser', action='store_true', dest='open_browser', + help='Tells Django to open a browser.') + parser.add_argument('--nothreading', action='store_false', dest='threaded', + help='Do not run in multithreaded mode.') + parser.add_argument('--threaded', action='store_true', dest='threaded', + help='Run in multithreaded mode.') + parser.add_argument('--output', dest='output_file', default=None, + help='Specifies an output file to send a copy of all messages (not flushed immediately).') + parser.add_argument('--print-sql', action='store_true', default=False, + help="Print SQL queries as they're executed") + parser.add_argument('--print-sql-location', action='store_true', default=False, + help="Show location in code where SQL query generated from") + cert_group = parser.add_mutually_exclusive_group() + cert_group.add_argument('--cert', dest='cert_path', action="store", type=str, + help='Deprecated alias for --cert-file option.') + cert_group.add_argument('--cert-file', dest='cert_path', action="store", type=str, + help='SSL .crt file path. If not provided path from --key-file will be selected. ' + 'Either --cert-file or --key-file must be provided to use SSL.') + parser.add_argument('--key-file', dest='key_file_path', action="store", type=str, + help='SSL .key file path. If not provided path from --cert-file will be selected. ' + 'Either --cert-file or --key-file must be provided to use SSL.') + parser.add_argument('--extra-file', dest='extra_files', action="append", type=str, default=[], + help='auto-reload whenever the given file changes too (can be specified multiple times)') + parser.add_argument('--reloader-interval', dest='reloader_interval', action="store", type=int, default=DEFAULT_POLLER_RELOADER_INTERVAL, + help='After how many seconds auto-reload should scan for updates in poller-mode [default=%s]' % DEFAULT_POLLER_RELOADER_INTERVAL) + parser.add_argument('--reloader-type', dest='reloader_type', action="store", type=str, default=DEFAULT_POLLER_RELOADER_TYPE, + help='Werkzeug reloader type [options are auto, watchdog, or stat, default=%s]' % DEFAULT_POLLER_RELOADER_TYPE) + parser.add_argument('--pdb', action='store_true', dest='pdb', default=False, + help='Drop into pdb shell at the start of any view.') + parser.add_argument('--ipdb', action='store_true', dest='ipdb', default=False, + help='Drop into ipdb shell at the start of any view.') + parser.add_argument('--pm', action='store_true', dest='pm', default=False, + help='Drop into (i)pdb shell if an exception is raised in a view.') + parser.add_argument('--startup-messages', dest='startup_messages', action="store", default='reload', + help='When to show startup messages: reload [default], once, always, never.') + parser.add_argument('--keep-meta-shutdown', dest='keep_meta_shutdown_func', action='store_true', default=False, + help="Keep request.META['werkzeug.server.shutdown'] function which is automatically removed " + "because Django debug pages tries to call the function and unintentionally shuts down " + "the Werkzeug server.") + parser.add_argument("--nopin", dest="nopin", action="store_true", default=False, + help="Disable the PIN in werkzeug. USE IT WISELY!") + + if USE_STATICFILES: + parser.add_argument('--nostatic', action="store_false", dest='use_static_handler', default=True, + help='Tells Django to NOT automatically serve static files at STATIC_URL.') + parser.add_argument('--insecure', action="store_true", dest='insecure_serving', default=False, + help='Allows serving static files even if DEBUG is False.') + + @signalcommand + def handle(self, *args, **options): + addrport = options['addrport'] + startup_messages = options['startup_messages'] + if startup_messages == "reload": + self.show_startup_messages = os.environ.get('RUNSERVER_PLUS_SHOW_MESSAGES') + elif startup_messages == "once": + self.show_startup_messages = not os.environ.get('RUNSERVER_PLUS_SHOW_MESSAGES') + elif startup_messages == "never": + self.show_startup_messages = False + else: + self.show_startup_messages = True + + os.environ['RUNSERVER_PLUS_SHOW_MESSAGES'] = '1' + + setup_logger(logger, self.stderr, filename=options['output_file']) # , fmt="[%(name)s] %(message)s") + logredirect = RedirectHandler(__name__) + + # Redirect werkzeug log items + werklogger = logging.getLogger('werkzeug') + werklogger.setLevel(logging.INFO) + werklogger.addHandler(logredirect) + werklogger.propagate = False + + pdb_option = options['pdb'] + ipdb_option = options['ipdb'] + pm = options['pm'] + try: + from django_pdb.middleware import PdbMiddleware + except ImportError: + if pdb_option or ipdb_option or pm: + raise CommandError("django-pdb is required for --pdb, --ipdb and --pm options. Please visit https://pypi.python.org/pypi/django-pdb or install via pip. (pip install django-pdb)") + pm = False + else: + # Add pdb middleware if --pdb is specified or if in DEBUG mode + if (pdb_option or ipdb_option or settings.DEBUG): + middleware = 'django_pdb.middleware.PdbMiddleware' + settings_middleware = getattr(settings, 'MIDDLEWARE', None) or settings.MIDDLEWARE_CLASSES + + if middleware not in settings_middleware: + if isinstance(settings_middleware, tuple): + settings_middleware += (middleware,) + else: + settings_middleware += [middleware] + + # If --pdb is specified then always break at the start of views. + # Otherwise break only if a 'pdb' query parameter is set in the url + if pdb_option: + PdbMiddleware.always_break = 'pdb' + elif ipdb_option: + PdbMiddleware.always_break = 'ipdb' + + def postmortem(request, exc_type, exc_value, tb): + if has_ipdb(): + import ipdb + p = ipdb + else: + import pdb + p = pdb + print("Exception occured: %s, %s" % (exc_type, exc_value), file=sys.stderr) + p.post_mortem(tb) + + # usurp django's handler + django_views_debug.technical_500_response = postmortem if pm else null_technical_500_response + + self.use_ipv6 = options['use_ipv6'] + if self.use_ipv6 and not socket.has_ipv6: + raise CommandError('Your Python does not support IPv6.') + self._raw_ipv6 = False + if not addrport: + try: + addrport = settings.RUNSERVERPLUS_SERVER_ADDRESS_PORT + except AttributeError: + pass + if not addrport: + self.addr = '' + self.port = DEFAULT_PORT + else: + m = re.match(naiveip_re, addrport) + if m is None: + raise CommandError('"%s" is not a valid port number ' + 'or address:port pair.' % addrport) + self.addr, _ipv4, _ipv6, _fqdn, self.port = m.groups() + if not self.port.isdigit(): + raise CommandError("%r is not a valid port number." % + self.port) + if self.addr: + if _ipv6: + self.addr = self.addr[1:-1] + self.use_ipv6 = True + self._raw_ipv6 = True + elif self.use_ipv6 and not _fqdn: + raise CommandError('"%s" is not a valid IPv6 address.' + % self.addr) + if not self.addr: + self.addr = '::1' if self.use_ipv6 else '127.0.0.1' + self._raw_ipv6 = True + + with monkey_patch_cursordebugwrapper(print_sql=options["print_sql"], print_sql_location=options["print_sql_location"], logger=logger.info, confprefix="RUNSERVER_PLUS"): + self.inner_run(options) + + def get_handler(self, *args, **options): + """Return the default WSGI handler for the runner.""" + return get_internal_wsgi_application() + + def get_error_handler(self, exc, **options): + def application(env, start_response): + if isinstance(exc, SystemCheckError): + error_message = ansi_escape.sub('', str(exc)) + raise SystemCheckError(error_message) + + raise exc + + return application + + def inner_run(self, options): + if not HAS_WERKZEUG: + raise CommandError("Werkzeug is required to use runserver_plus. Please visit http://werkzeug.pocoo.org/ or install via pip. (pip install Werkzeug)") + + # Set colored output + if settings.DEBUG: + try: + set_werkzeug_log_color() + except Exception: # We are dealing with some internals, anything could go wrong + if self.show_startup_messages: + print("Wrapping internal werkzeug logger for color highlighting has failed!") + + class WSGIRequestHandler(_WSGIRequestHandler): + def make_environ(self): + environ = super().make_environ() + if not options['keep_meta_shutdown_func']: + del environ['werkzeug.server.shutdown'] + return environ + + threaded = options['threaded'] + use_reloader = options['use_reloader'] + open_browser = options['open_browser'] + quit_command = 'CONTROL-C' if sys.platform != 'win32' else 'CTRL-BREAK' + reloader_interval = options['reloader_interval'] + reloader_type = options['reloader_type'] + self.extra_files = set(options['extra_files']) + + self.nopin = options['nopin'] + + if self.show_startup_messages: + print("Performing system checks...\n") + + try: + check_errors(self.check)(display_num_errors=self.show_startup_messages) + check_errors(self.check_migrations)() + handler = check_errors(self.get_handler)(**options) + except Exception as exc: + self.stderr.write("Error occurred during checks: %r" % exc, ending="\n\n") + handler = self.get_error_handler(exc, **options) + + if USE_STATICFILES: + use_static_handler = options['use_static_handler'] + insecure_serving = options['insecure_serving'] + if use_static_handler and (settings.DEBUG or insecure_serving): + handler = StaticFilesHandler(handler) + + if options["cert_path"] or options["key_file_path"]: + if not HAS_OPENSSL: + raise CommandError("Python OpenSSL Library is " + "required to use runserver_plus with ssl support. " + "Install via pip (pip install pyOpenSSL).") + + certfile, keyfile = self.determine_ssl_files_paths(options) + dir_path, root = os.path.split(certfile) + root, _ = os.path.splitext(root) + try: + if os.path.exists(certfile) and os.path.exists(keyfile): + ssl_context = (certfile, keyfile) + else: # Create cert, key files ourselves. + ssl_context = make_ssl_devcert(os.path.join(dir_path, root), host='localhost') + except ImportError: + if self.show_startup_messages: + print("Werkzeug version is less than 0.9, trying adhoc certificate.") + ssl_context = "adhoc" + else: + ssl_context = None + + bind_url = "%s://%s:%s/" % ( + "https" if ssl_context else "http", self.addr if not self._raw_ipv6 else '[%s]' % self.addr, self.port) + + if self.show_startup_messages: + print("\nDjango version %s, using settings %r" % (django.get_version(), settings.SETTINGS_MODULE)) + print("Development server is running at %s" % (bind_url,)) + print("Using the Werkzeug debugger (http://werkzeug.pocoo.org/)") + print("Quit the server with %s." % quit_command) + + if open_browser: + webbrowser.open(bind_url) + + if use_reloader and settings.USE_I18N: + self.extra_files |= set(filter(lambda filename: str(filename).endswith('.mo'), gen_filenames())) + + if getattr(settings, 'RUNSERVER_PLUS_EXTRA_FILES', []): + self.extra_files |= set(settings.RUNSERVER_PLUS_EXTRA_FILES) + + # Werkzeug needs to be clued in its the main instance if running + # without reloader or else it won't show key. + # https://git.io/vVIgo + if not use_reloader: + os.environ['WERKZEUG_RUN_MAIN'] = 'true' + + # Don't run a second instance of the debugger / reloader + # See also: https://github.com/django-extensions/django-extensions/issues/832 + if os.environ.get('WERKZEUG_RUN_MAIN') != 'true': + if self.nopin: + os.environ['WERKZEUG_DEBUG_PIN'] = 'off' + handler = DebuggedApplication(handler, True) + + runserver_plus_started.send(sender=self) + run_simple( + self.addr, + int(self.port), + handler, + use_reloader=use_reloader, + use_debugger=True, + extra_files=self.extra_files, + reloader_interval=reloader_interval, + reloader_type=reloader_type, + threaded=threaded, + request_handler=WSGIRequestHandler, + ssl_context=ssl_context, + ) + + @classmethod + def determine_ssl_files_paths(cls, options): + key_file_path = options.get('key_file_path') or "" + cert_path = options.get('cert_path') or "" + cert_file = cls._determine_path_for_file(cert_path, key_file_path, cls.DEFAULT_CRT_EXTENSION) + key_file = cls._determine_path_for_file(key_file_path, cert_path, cls.DEFAULT_KEY_EXTENSION) + return cert_file, key_file + + @classmethod + def _determine_path_for_file(cls, current_file_path, other_file_path, expected_extension): + directory = cls._get_directory_basing_on_file_paths(current_file_path, other_file_path) + file_name = cls._get_file_name(current_file_path) or cls._get_file_name(other_file_path) + extension = cls._get_extension(current_file_path) or expected_extension + return os.path.join(directory, file_name + extension) + + @classmethod + def _get_directory_basing_on_file_paths(cls, current_file_path, other_file_path): + return cls._get_directory(current_file_path) or cls._get_directory(other_file_path) or os.getcwd() + + @classmethod + def _get_directory(cls, file_path): + return os.path.split(file_path)[0] + + @classmethod + def _get_file_name(cls, file_path): + return os.path.splitext(os.path.split(file_path)[1])[0] + + @classmethod + def _get_extension(cls, file_path): + return os.path.splitext(file_path)[1] + + +def set_werkzeug_log_color(): + """Try to set color to the werkzeug log.""" + _style = color_style() + _orig_log = _WSGIRequestHandler.log + + def werk_log(self, type, message, *args): + try: + msg = '%s - - [%s] %s' % ( + self.address_string(), + self.log_date_time_string(), + message % args, + ) + http_code = str(args[1]) + except Exception: + return _orig_log(type, message, *args) + + # Utilize terminal colors, if available + if http_code[0] == '2': + # Put 2XX first, since it should be the common case + msg = _style.HTTP_SUCCESS(msg) + elif http_code[0] == '1': + msg = _style.HTTP_INFO(msg) + elif http_code == '304': + msg = _style.HTTP_NOT_MODIFIED(msg) + elif http_code[0] == '3': + msg = _style.HTTP_REDIRECT(msg) + elif http_code == '404': + msg = _style.HTTP_NOT_FOUND(msg) + elif http_code[0] == '4': + msg = _style.HTTP_BAD_REQUEST(msg) + else: + # Any 5XX, or any other response + msg = _style.HTTP_SERVER_ERROR(msg) + + _log(type, msg) + + _WSGIRequestHandler.log = werk_log diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/set_default_site.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/set_default_site.py new file mode 100644 index 0000000..295d0aa --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/set_default_site.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +import socket + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError + +from django_extensions.management.utils import signalcommand + + +class Command(BaseCommand): + help = "Set parameters of the default django.contrib.sites Site" + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--name', dest='site_name', default=None, + help='Use this as site name.' + ) + parser.add_argument( + '--domain', dest='site_domain', default=None, + help='Use this as site domain.' + ) + parser.add_argument( + '--system-fqdn', dest='set_as_system_fqdn', default=False, + action="store_true", + help='Use the systems FQDN (Fully Qualified Domain Name) as name ' + 'and domain. Can be used in combination with --name' + ) + + @signalcommand + def handle(self, *args, **options): + if 'django.contrib.sites' not in settings.INSTALLED_APPS: + raise CommandError('The sites framework is not installed.') + + from django.contrib.sites.models import Site + + try: + site = Site.objects.get(pk=settings.SITE_ID) + except Site.DoesNotExist: + raise CommandError("Default site with pk=%s does not exist" % + settings.SITE_ID) + else: + name = options["site_name"] + domain = options["site_domain"] + set_as_system_fqdn = options["set_as_system_fqdn"] + if all([domain, set_as_system_fqdn]): + raise CommandError( + "The set_as_system_fqdn cannot be used with domain option.") # noqa + if set_as_system_fqdn: + domain = socket.getfqdn() + if not domain: + raise CommandError("Cannot find systems FQDN") + if name is None: + name = domain + + update_kwargs = {} + if name and name != site.name: + update_kwargs["name"] = name + + if domain and domain != site.domain: + update_kwargs["domain"] = domain + + if update_kwargs: + Site.objects.filter( + pk=settings.SITE_ID).update(**update_kwargs) + site = Site.objects.get(pk=settings.SITE_ID) + print("Updated default site. You might need to restart django as sites are cached aggressively.") + else: + print("Nothing to update (need --name, --domain and/or --system-fqdn)") + + print("Default Site:") + print("\tid = %s" % site.id) + print("\tname = %s" % site.name) + print("\tdomain = %s" % site.domain) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/set_fake_emails.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/set_fake_emails.py new file mode 100644 index 0000000..4eb4a9c --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/set_fake_emails.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +""" +set_fake_emails.py + + Give all users a new email account. Useful for testing in a + development environment. As such, this command is only available when + setting.DEBUG is True. + +""" + +from django.conf import settings +from django.contrib.auth import get_user_model +from django.core.management.base import BaseCommand, CommandError + +from django_extensions.management.utils import signalcommand + +DEFAULT_FAKE_EMAIL = '%(username)s@example.com' + + +class Command(BaseCommand): + help = '''DEBUG only: give all users a new email based on their account data ("%s" by default). Possible parameters are: username, first_name, last_name''' % (DEFAULT_FAKE_EMAIL, ) + requires_system_checks = False + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--email', dest='default_email', default=DEFAULT_FAKE_EMAIL, + help='Use this as the new email format.' + ) + parser.add_argument( + '-a', '--no-admin', action="store_true", dest='no_admin', + default=False, help='Do not change administrator accounts' + ) + parser.add_argument( + '-s', '--no-staff', action="store_true", dest='no_staff', + default=False, help='Do not change staff accounts' + ) + parser.add_argument( + '--include', dest='include_regexp', default=None, + help='Include usernames matching this regexp.' + ) + parser.add_argument( + '--exclude', dest='exclude_regexp', default=None, + help='Exclude usernames matching this regexp.' + ) + parser.add_argument( + '--include-groups', dest='include_groups', default=None, + help='Include users matching this group. (use comma seperation for multiple groups)' + ) + parser.add_argument( + '--exclude-groups', dest='exclude_groups', default=None, + help='Exclude users matching this group. (use comma seperation for multiple groups)' + ) + + @signalcommand + def handle(self, *args, **options): + if not settings.DEBUG: + raise CommandError('Only available in debug mode') + + from django.contrib.auth.models import Group + email = options['default_email'] + include_regexp = options['include_regexp'] + exclude_regexp = options['exclude_regexp'] + include_groups = options['include_groups'] + exclude_groups = options['exclude_groups'] + no_admin = options['no_admin'] + no_staff = options['no_staff'] + + User = get_user_model() + users = User.objects.all() + if no_admin: + users = users.exclude(is_superuser=True) + if no_staff: + users = users.exclude(is_staff=True) + if exclude_groups: + groups = Group.objects.filter(name__in=exclude_groups.split(",")) + if groups: + users = users.exclude(groups__in=groups) + else: + raise CommandError("No groups matches filter: %s" % exclude_groups) + if include_groups: + groups = Group.objects.filter(name__in=include_groups.split(",")) + if groups: + users = users.filter(groups__in=groups) + else: + raise CommandError("No groups matches filter: %s" % include_groups) + if exclude_regexp: + users = users.exclude(username__regex=exclude_regexp) + if include_regexp: + users = users.filter(username__regex=include_regexp) + for user in users: + user.email = email % {'username': user.username, + 'first_name': user.first_name, + 'last_name': user.last_name} + user.save() + print('Changed %d emails' % users.count()) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/set_fake_passwords.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/set_fake_passwords.py new file mode 100644 index 0000000..5d619bd --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/set_fake_passwords.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +""" +set_fake_passwords.py + + Reset all user passwords to a common value. Useful for testing in a + development environment. As such, this command is only available when + setting.DEBUG is True. + +""" +from django.conf import settings +from django.contrib.auth import get_user_model +from django.core.management.base import BaseCommand, CommandError + +from django_extensions.management.utils import signalcommand + +DEFAULT_FAKE_PASSWORD = 'password' + + +class Command(BaseCommand): + help = 'DEBUG only: sets all user passwords to a common value ("%s" by default)' % (DEFAULT_FAKE_PASSWORD, ) + requires_system_checks = False + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--prompt', dest='prompt_passwd', default=False, + action='store_true', + help='Prompts for the new password to apply to all users' + ) + parser.add_argument( + '--password', dest='default_passwd', default=DEFAULT_FAKE_PASSWORD, + help='Use this as default password.' + ) + + @signalcommand + def handle(self, *args, **options): + if not settings.DEBUG: + raise CommandError('Only available in debug mode') + + if options['prompt_passwd']: + from getpass import getpass + passwd = getpass('Password: ') + if not passwd: + raise CommandError('You must enter a valid password') + else: + passwd = options['default_passwd'] + + User = get_user_model() + user = User() + user.set_password(passwd) + count = User.objects.all().update(password=user.password) + + print('Reset %d passwords' % count) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/shell_plus.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/shell_plus.py new file mode 100644 index 0000000..8cc263f --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/shell_plus.py @@ -0,0 +1,556 @@ +# -*- coding: utf-8 -*- +import inspect +import os +import sys +import traceback + +from django.db import connections +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from django.utils.datastructures import OrderedSet + +from django_extensions.management.shells import import_objects +from django_extensions.management.utils import signalcommand +from django_extensions.management.debug_cursor import monkey_patch_cursordebugwrapper + + +def use_vi_mode(): + editor = os.environ.get('EDITOR') + if not editor: + return False + editor = os.path.basename(editor) + return editor.startswith('vi') or editor.endswith('vim') + + +def shell_runner(flags, name, help=None): + """ + Decorates methods with information about the application they are starting + + :param flags: The flags used to start this runner via the ArgumentParser. + :param name: The name of this runner for the help text for the ArgumentParser. + :param help: The optional help for the ArgumentParser if the dynamically generated help is not sufficient. + """ + + def decorator(fn): + fn.runner_flags = flags + fn.runner_name = name + fn.runner_help = help + + return fn + + return decorator + + +class Command(BaseCommand): + help = "Like the 'shell' command but autoloads the models of all installed Django apps." + extra_args = None + tests_mode = False + + def __init__(self): + super().__init__() + self.runners = [member for name, member in inspect.getmembers(self) + if hasattr(member, 'runner_flags')] + + def add_arguments(self, parser): + super().add_arguments(parser) + + group = parser.add_mutually_exclusive_group() + for runner in self.runners: + if runner.runner_help: + help = runner.runner_help + else: + help = 'Tells Django to use %s.' % runner.runner_name + + group.add_argument( + *runner.runner_flags, action='store_const', dest='runner', const=runner, help=help) + + parser.add_argument( + '--connection-file', action='store', dest='connection_file', + help='Specifies the connection file to use if using the --kernel option' + ) + parser.add_argument( + '--no-startup', action='store_true', dest='no_startup', + default=False, + help='When using plain Python, ignore the PYTHONSTARTUP environment variable and ~/.pythonrc.py script.' + ) + parser.add_argument( + '--use-pythonrc', action='store_true', dest='use_pythonrc', + default=False, + help='When using plain Python, load the PYTHONSTARTUP environment variable and ~/.pythonrc.py script.' + ) + parser.add_argument( + '--print-sql', action='store_true', + default=False, + help="Print SQL queries as they're executed" + ) + parser.add_argument( + '--print-sql-location', action='store_true', + default=False, + help="Show location in code where SQL query generated from" + ) + parser.add_argument( + '--dont-load', action='append', dest='dont_load', default=[], + help='Ignore autoloading of some apps/models. Can be used several times.' + ) + parser.add_argument( + '--quiet-load', action='store_true', + default=False, + dest='quiet_load', help='Do not display loaded models messages' + ) + parser.add_argument( + '--vi', action='store_true', default=use_vi_mode(), dest='vi_mode', + help='Load Vi key bindings (for --ptpython and --ptipython)' + ) + parser.add_argument( + '--no-browser', action='store_true', + default=False, + dest='no_browser', + help='Don\'t open the notebook in a browser after startup.' + ) + parser.add_argument( + '-c', '--command', + help='Instead of opening an interactive shell, run a command as Django and exit.', + ) + + def run_from_argv(self, argv): + if '--' in argv[2:]: + idx = argv.index('--') + self.extra_args = argv[idx + 1:] + argv = argv[:idx] + return super().run_from_argv(argv) + + def get_ipython_arguments(self, options): + ipython_args = 'IPYTHON_ARGUMENTS' + arguments = getattr(settings, ipython_args, []) + if not arguments: + arguments = os.environ.get(ipython_args, '').split() + return arguments + + def get_notebook_arguments(self, options): + notebook_args = 'NOTEBOOK_ARGUMENTS' + arguments = getattr(settings, notebook_args, []) + if not arguments: + arguments = os.environ.get(notebook_args, '').split() + return arguments + + def get_imported_objects(self, options): + imported_objects = import_objects(options, self.style) + if self.tests_mode: + # save imported objects so we can run tests against it later + self.tests_imported_objects = imported_objects + return imported_objects + + @shell_runner(flags=['--kernel'], name='IPython Kernel') + def get_kernel(self, options): + try: + from IPython import release + if release.version_info[0] < 2: + print(self.style.ERROR("--kernel requires at least IPython version 2.0")) + return + from IPython import start_kernel + except ImportError: + return traceback.format_exc() + + def run_kernel(): + imported_objects = self.get_imported_objects(options) + kwargs = dict( + argv=[], + user_ns=imported_objects, + ) + connection_file = options['connection_file'] + if connection_file: + kwargs['connection_file'] = connection_file + start_kernel(**kwargs) + return run_kernel + + def load_base_kernel_spec(self, app): + """Finds and returns the base Python kernelspec to extend from.""" + ksm = app.kernel_spec_manager + try_spec_names = getattr(settings, 'NOTEBOOK_KERNEL_SPEC_NAMES', [ + 'python3', + 'python', + ]) + + if isinstance(try_spec_names, str): + try_spec_names = [try_spec_names] + + ks = None + for spec_name in try_spec_names: + try: + ks = ksm.get_kernel_spec(spec_name) + break + except Exception: + continue + if not ks: + raise CommandError("No notebook (Python) kernel specs found. Tried %r" % try_spec_names) + + return ks + + def generate_kernel_specs(self, app, ipython_arguments): + """Generate an IPython >= 3.0 kernelspec that loads django extensions""" + ks = self.load_base_kernel_spec(app) + ks.argv.extend(ipython_arguments) + ks.display_name = getattr(settings, 'IPYTHON_KERNEL_DISPLAY_NAME', "Django Shell-Plus") + + manage_py_dir, manage_py = os.path.split(os.path.realpath(sys.argv[0])) + if manage_py == 'manage.py' and os.path.isdir(manage_py_dir): + pythonpath = ks.env.get('PYTHONPATH', os.environ.get('PYTHONPATH', '')) + pythonpath = pythonpath.split(os.pathsep) + if manage_py_dir not in pythonpath: + pythonpath.append(manage_py_dir) + + ks.env['PYTHONPATH'] = os.pathsep.join(filter(None, pythonpath)) + + return {'django_extensions': ks} + + def run_notebookapp(self, app, options, use_kernel_specs=True): + no_browser = options['no_browser'] + + if self.extra_args: + # if another '--' is found split the arguments notebook, ipython + if '--' in self.extra_args: + idx = self.extra_args.index('--') + notebook_arguments = self.extra_args[:idx] + ipython_arguments = self.extra_args[idx + 1:] + # otherwise pass the arguments to the notebook + else: + notebook_arguments = self.extra_args + ipython_arguments = [] + else: + notebook_arguments = self.get_notebook_arguments(options) + ipython_arguments = self.get_ipython_arguments(options) + + # Treat IPYTHON_ARGUMENTS from settings + if 'django_extensions.management.notebook_extension' not in ipython_arguments: + ipython_arguments.extend(['--ext', 'django_extensions.management.notebook_extension']) + + # Treat NOTEBOOK_ARGUMENTS from settings + if no_browser and '--no-browser' not in notebook_arguments: + notebook_arguments.append('--no-browser') + if '--notebook-dir' not in notebook_arguments and not any(e.startswith('--notebook-dir=') for e in notebook_arguments): + notebook_arguments.extend(['--notebook-dir', '.']) + + # IPython < 3 passes through kernel args from notebook CLI + if not use_kernel_specs: + notebook_arguments.extend(ipython_arguments) + + app.initialize(notebook_arguments) + + # IPython >= 3 uses kernelspecs to specify kernel CLI args + if use_kernel_specs: + ksm = app.kernel_spec_manager + for kid, ks in self.generate_kernel_specs(app, ipython_arguments).items(): + roots = [os.path.dirname(ks.resource_dir), ksm.user_kernel_dir] + success = False + for root in roots: + kernel_dir = os.path.join(root, kid) + try: + if not os.path.exists(kernel_dir): + os.makedirs(kernel_dir) + + with open(os.path.join(kernel_dir, 'kernel.json'), 'w') as f: + f.write(ks.to_json()) + + success = True + break + except OSError: + continue + + if not success: + raise CommandError("Could not write kernel %r in directories %r" % (kid, roots)) + + app.start() + + @shell_runner(flags=['--notebook'], name='IPython Notebook') + def get_notebook(self, options): + try: + from IPython import release + except ImportError: + return traceback.format_exc() + try: + from notebook.notebookapp import NotebookApp + except ImportError: + if release.version_info[0] >= 7: + return traceback.format_exc() + try: + from IPython.html.notebookapp import NotebookApp + except ImportError: + if release.version_info[0] >= 3: + return traceback.format_exc() + try: + from IPython.frontend.html.notebook import notebookapp + NotebookApp = notebookapp.NotebookApp + except ImportError: + return traceback.format_exc() + + use_kernel_specs = release.version_info[0] >= 3 + + def run_notebook(): + app = NotebookApp.instance() + self.run_notebookapp(app, options, use_kernel_specs) + + return run_notebook + + @shell_runner(flags=['--lab'], name='JupyterLab Notebook') + def get_jupyterlab(self, options): + try: + from jupyterlab.labapp import LabApp + except ImportError: + return traceback.format_exc() + + def run_jupyterlab(): + app = LabApp.instance() + self.run_notebookapp(app, options) + + return run_jupyterlab + + @shell_runner(flags=['--plain'], name='plain Python') + def get_plain(self, options): + # Using normal Python shell + import code + imported_objects = self.get_imported_objects(options) + try: + # Try activating rlcompleter, because it's handy. + import readline + except ImportError: + pass + else: + # We don't have to wrap the following import in a 'try', because + # we already know 'readline' was imported successfully. + import rlcompleter + readline.set_completer(rlcompleter.Completer(imported_objects).complete) + # Enable tab completion on systems using libedit (e.g. macOS). + # These lines are copied from Lib/site.py on Python 3.4. + readline_doc = getattr(readline, '__doc__', '') + if readline_doc is not None and 'libedit' in readline_doc: + readline.parse_and_bind("bind ^I rl_complete") + else: + readline.parse_and_bind("tab:complete") + + use_pythonrc = options['use_pythonrc'] + no_startup = options['no_startup'] + + # We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system + # conventions and get $PYTHONSTARTUP first then .pythonrc.py. + if use_pythonrc or not no_startup: + for pythonrc in OrderedSet([os.environ.get("PYTHONSTARTUP"), os.path.expanduser('~/.pythonrc.py')]): + if not pythonrc: + continue + if not os.path.isfile(pythonrc): + continue + with open(pythonrc) as handle: + pythonrc_code = handle.read() + # Match the behavior of the cpython shell where an error in + # PYTHONSTARTUP prints an exception and continues. + try: + exec(compile(pythonrc_code, pythonrc, 'exec'), imported_objects) + except Exception: + traceback.print_exc() + if self.tests_mode: + raise + + def run_plain(): + code.interact(local=imported_objects) + return run_plain + + @shell_runner(flags=['--bpython'], name='BPython') + def get_bpython(self, options): + try: + from bpython import embed + except ImportError: + return traceback.format_exc() + + def run_bpython(): + imported_objects = self.get_imported_objects(options) + kwargs = {} + if self.extra_args: + kwargs['args'] = self.extra_args + embed(imported_objects, **kwargs) + return run_bpython + + @shell_runner(flags=['--ipython'], name='IPython') + def get_ipython(self, options): + try: + from IPython import start_ipython + + def run_ipython(): + imported_objects = self.get_imported_objects(options) + ipython_arguments = self.extra_args or self.get_ipython_arguments(options) + start_ipython(argv=ipython_arguments, user_ns=imported_objects) + return run_ipython + except ImportError: + str_exc = traceback.format_exc() + # IPython < 0.11 + # Explicitly pass an empty list as arguments, because otherwise + # IPython would use sys.argv from this script. + # Notebook not supported for IPython < 0.11. + try: + from IPython.Shell import IPShell + except ImportError: + return str_exc + "\n" + traceback.format_exc() + + def run_ipython(): + imported_objects = self.get_imported_objects(options) + shell = IPShell(argv=[], user_ns=imported_objects) + shell.mainloop() + return run_ipython + + @shell_runner(flags=['--ptpython'], name='PTPython') + def get_ptpython(self, options): + try: + from ptpython.repl import embed, run_config + except ImportError: + tb = traceback.format_exc() + try: # prompt_toolkit < v0.27 + from prompt_toolkit.contrib.repl import embed, run_config + except ImportError: + return tb + + def run_ptpython(): + imported_objects = self.get_imported_objects(options) + history_filename = os.path.expanduser('~/.ptpython_history') + embed(globals=imported_objects, history_filename=history_filename, + vi_mode=options['vi_mode'], configure=run_config) + return run_ptpython + + @shell_runner(flags=['--ptipython'], name='PT-IPython') + def get_ptipython(self, options): + try: + from ptpython.repl import run_config + from ptpython.ipython import embed + except ImportError: + tb = traceback.format_exc() + try: # prompt_toolkit < v0.27 + from prompt_toolkit.contrib.repl import run_config + from prompt_toolkit.contrib.ipython import embed + except ImportError: + return tb + + def run_ptipython(): + imported_objects = self.get_imported_objects(options) + history_filename = os.path.expanduser('~/.ptpython_history') + embed(user_ns=imported_objects, history_filename=history_filename, + vi_mode=options['vi_mode'], configure=run_config) + return run_ptipython + + @shell_runner(flags=['--idle'], name='Idle') + def get_idle(self, options): + from idlelib.pyshell import main + + def run_idle(): + sys.argv = [ + sys.argv[0], + '-c', + """ +from django_extensions.management import shells +from django.core.management.color import no_style +for k, m in shells.import_objects({}, no_style()).items(): + globals()[k] = m +""", + ] + main() + + return run_idle + + def set_application_name(self, options): + """ + Set the application_name on PostgreSQL connection + + Use the fallback_application_name to let the user override + it with PGAPPNAME env variable + + http://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-PARAMKEYWORDS # noqa + """ + supported_backends = ( + 'django.db.backends.postgresql', + 'django.db.backends.postgresql_psycopg2', + ) + opt_name = 'fallback_application_name' + default_app_name = 'django_shell' + dbs = getattr(settings, 'DATABASES', []) + + for connection in connections.all(): + alias = connection.alias + mro = inspect.getmro(connection.__class__) + if any(klass.__module__.startswith(supported_backends) for klass in mro): + if 'OPTIONS' not in dbs[alias] or opt_name not in dbs[alias]['OPTIONS']: + dbs[alias].setdefault('OPTIONS', {}).update({opt_name: default_app_name}) + + @signalcommand + def handle(self, *args, **options): + verbosity = options["verbosity"] + get_runner = options['runner'] + print_sql = getattr(settings, 'SHELL_PLUS_PRINT_SQL', False) + runner = None + runner_name = None + + with monkey_patch_cursordebugwrapper(print_sql=options["print_sql"] or print_sql, print_sql_location=options["print_sql_location"], confprefix="SHELL_PLUS"): + SETTINGS_SHELL_PLUS = getattr(settings, 'SHELL_PLUS', None) + + def get_runner_by_flag(flag): + for runner in self.runners: + if flag in runner.runner_flags: + return runner + return None + + self.set_application_name(options) + + if not get_runner and SETTINGS_SHELL_PLUS: + get_runner = get_runner_by_flag('--%s' % SETTINGS_SHELL_PLUS) + if not get_runner: + runner = None + runner_name = SETTINGS_SHELL_PLUS + + if get_runner: + runner = get_runner(options) + runner_name = get_runner.runner_name + else: + def try_runner(get_runner): + runner_name = get_runner.runner_name + if verbosity > 2: + print(self.style.NOTICE("Trying: %s" % runner_name)) + + runner = get_runner(options) + if callable(runner): + if verbosity > 1: + print(self.style.NOTICE("Using: %s" % runner_name)) + return runner + return None + + tried_runners = set() + + # try the runners that are least unexpected (normal shell runners) + preferred_runners = ['ptipython', 'ptpython', 'bpython', 'ipython', 'plain'] + for flag_suffix in preferred_runners: + get_runner = get_runner_by_flag('--%s' % flag_suffix) + tried_runners.add(get_runner) + runner = try_runner(get_runner) + if runner: + runner_name = get_runner.runner_name + break + + # try any remaining runners if needed + if not runner: + for get_runner in self.runners: + if get_runner not in tried_runners: + runner = try_runner(get_runner) + if runner: + runner_name = get_runner.runner_name + break + + if not callable(runner): + if runner: + print(runner) + if not runner_name: + raise CommandError("No shell runner could be found.") + raise CommandError("Could not load shell runner: '%s'." % runner_name) + + if self.tests_mode: + return 130 + + if options['command']: + imported_objects = self.get_imported_objects(options) + exec(options['command'], {}, imported_objects) + return None + + runner() diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/show_template_tags.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/show_template_tags.py new file mode 100644 index 0000000..7956189 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/show_template_tags.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +import inspect +import os +import re + + +from django.apps import apps +from django.core.management import color +from django.core.management import BaseCommand +from django.utils import termcolors +from django.utils.encoding import smart_text + +from django_extensions.compat import load_tag_library +from django_extensions.management.color import _dummy_style_func +from django_extensions.management.utils import signalcommand + + +def no_style(): + style = color.no_style() + for role in ('FILTER', 'MODULE_NAME', 'TAG', 'TAGLIB'): + setattr(style, role, _dummy_style_func) + return style + + +def color_style(): + style = color.color_style() + style.FILTER = termcolors.make_style(fg='yellow', opts=('bold',)) + style.MODULE_NAME = termcolors.make_style(fg='green', opts=('bold',)) + style.TAG = termcolors.make_style(fg='red', opts=('bold',)) + style.TAGLIB = termcolors.make_style(fg='blue', opts=('bold',)) + return style + + +def format_block(block, nlspaces=0): + """ + Format the given block of text, trimming leading/trailing + empty lines and any leading whitespace that is common to all lines. + The purpose is to let us list a code block as a multiline, + triple-quoted Python string, taking care of + indentation concerns. + http://code.activestate.com/recipes/145672/ + """ + # separate block into lines + lines = smart_text(block).split('\n') + + # remove leading/trailing empty lines + while lines and not lines[0]: + del lines[0] + while lines and not lines[-1]: + del lines[-1] + + # look at first line to see how much indentation to trim + ws = re.match(r'\s*', lines[0]).group(0) + if ws: + lines = map(lambda x: x.replace(ws, '', 1), lines) + + # remove leading/trailing blank lines (after leading ws removal) + # we do this again in case there were pure-whitespace lines + while lines and not lines[0]: + del lines[0] + while lines and not lines[-1]: + del lines[-1] + + # account for user-specified leading spaces + flines = ['%s%s' % (' ' * nlspaces, line) for line in lines] + + return '\n'.join(flines) + '\n' + + +class Command(BaseCommand): + help = "Displays template tags and filters available in the current project." + results = "" + + def add_result(self, s, depth=0): + self.results += '%s\n' % s.rjust(depth * 4 + len(s)) + + @signalcommand + def handle(self, *args, **options): + if options['no_color']: + style = no_style() + else: + style = color_style() + + for app_config in apps.get_app_configs(): + app = app_config.name + try: + templatetag_mod = __import__(app + '.templatetags', {}, {}, ['']) + except ImportError: + continue + mod_path = inspect.getabsfile(templatetag_mod) + mod_files = os.listdir(os.path.dirname(mod_path)) + tag_files = [i.rstrip('.py') for i in mod_files if i.endswith('.py') and i[0] != '_'] + app_labeled = False + for taglib in tag_files: + lib = load_tag_library(taglib) + if lib is None: + continue + + if not app_labeled: + self.add_result('App: %s' % style.MODULE_NAME(app)) + app_labeled = True + self.add_result('load: %s' % style.TAGLIB(taglib), 1) + libstuff = [ + (lib.tags, 'Tag:', style.TAG), + (lib.filters, 'Filter:', style.FILTER) + ] + for items, label, style_func in libstuff: + for item in items: + self.add_result('%s %s' % (label, style_func(item)), 2) + doc = inspect.getdoc(items[item]) + if doc: + self.add_result(format_block(doc, 12)) + return self.results diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/show_urls.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/show_urls.py new file mode 100644 index 0000000..cddca12 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/show_urls.py @@ -0,0 +1,237 @@ +# -*- coding: utf-8 -*- + +import functools +import json +import re + +from django.conf import settings +from django.contrib.admindocs.views import simplify_regex +from django.core.exceptions import ViewDoesNotExist +from django.core.management.base import BaseCommand, CommandError +from django.utils import translation + +from django_extensions.management.color import color_style, no_style +from django_extensions.management.utils import signalcommand + +from django.urls import URLPattern, URLResolver # type: ignore + + +class RegexURLPattern: # type: ignore + pass + + +class RegexURLResolver: # type: ignore + pass + + +class LocaleRegexURLResolver: # type: ignore + pass + + +def describe_pattern(p): + return str(p.pattern) + + +FMTR = { + 'dense': "{url}\t{module}\t{url_name}\t{decorator}", + 'table': "{url},{module},{url_name},{decorator}", + 'aligned': "{url},{module},{url_name},{decorator}", + 'verbose': "{url}\n\tController: {module}\n\tURL Name: {url_name}\n\tDecorators: {decorator}\n", + 'json': '', + 'pretty-json': '' +} + + +class Command(BaseCommand): + help = "Displays all of the url matching routes for the project." + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + "--unsorted", "-u", action="store_true", dest="unsorted", + help="Show urls unsorted but same order as found in url patterns" + ) + parser.add_argument( + "--language", "-l", dest="language", + help="Only show this language code (useful for i18n_patterns)" + ) + parser.add_argument( + "--decorator", "-d", action="append", dest="decorator", default=[], + help="Show the presence of given decorator on views" + ) + parser.add_argument( + "--format", "-f", dest="format_style", default="dense", + help="Style of the output. Choices: %s" % FMTR.keys() + ) + parser.add_argument( + "--urlconf", "-c", dest="urlconf", default="ROOT_URLCONF", + help="Set the settings URL conf variable to use" + ) + + @signalcommand + def handle(self, *args, **options): + style = no_style() if options['no_color'] else color_style() + + language = options['language'] + if language is not None: + translation.activate(language) + self.LANGUAGES = [(code, name) for code, name in getattr(settings, 'LANGUAGES', []) if code == language] + else: + self.LANGUAGES = getattr(settings, 'LANGUAGES', ((None, None), )) + + decorator = options['decorator'] + if not decorator: + decorator = ['login_required'] + + format_style = options['format_style'] + if format_style not in FMTR: + raise CommandError( + "Format style '%s' does not exist. Options: %s" % ( + format_style, + ", ".join(sorted(FMTR.keys())), + ) + ) + pretty_json = format_style == 'pretty-json' + if pretty_json: + format_style = 'json' + fmtr = FMTR[format_style] + + urlconf = options['urlconf'] + + views = [] + if not hasattr(settings, urlconf): + raise CommandError("Settings module {} does not have the attribute {}.".format(settings, urlconf)) + + try: + urlconf = __import__(getattr(settings, urlconf), {}, {}, ['']) + except Exception as e: + if options['traceback']: + import traceback + traceback.print_exc() + raise CommandError("Error occurred while trying to load %s: %s" % (getattr(settings, urlconf), str(e))) + + view_functions = self.extract_views_from_urlpatterns(urlconf.urlpatterns) + for (func, regex, url_name) in view_functions: + if hasattr(func, '__globals__'): + func_globals = func.__globals__ + elif hasattr(func, 'func_globals'): + func_globals = func.func_globals + else: + func_globals = {} + + decorators = [d for d in decorator if d in func_globals] + + if isinstance(func, functools.partial): + func = func.func + decorators.insert(0, 'functools.partial') + + if hasattr(func, '__name__'): + func_name = func.__name__ + elif hasattr(func, '__class__'): + func_name = '%s()' % func.__class__.__name__ + else: + func_name = re.sub(r' at 0x[0-9a-f]+', '', repr(func)) + + module = '{0}.{1}'.format(func.__module__, func_name) + url_name = url_name or '' + url = simplify_regex(regex) + decorator = ', '.join(decorators) + + if format_style == 'json': + views.append({"url": url, "module": module, "name": url_name, "decorators": decorator}) + else: + views.append(fmtr.format( + module='{0}.{1}'.format(style.MODULE(func.__module__), style.MODULE_NAME(func_name)), + url_name=style.URL_NAME(url_name), + url=style.URL(url), + decorator=decorator, + ).strip()) + + if not options['unsorted'] and format_style != 'json': + views = sorted(views) + + if format_style == 'aligned': + views = [row.split(',', 3) for row in views] + widths = [len(max(columns, key=len)) for columns in zip(*views)] + views = [ + ' '.join('{0:<{1}}'.format(cdata, width) for width, cdata in zip(widths, row)) + for row in views + ] + elif format_style == 'table': + # Reformat all data and show in a table format + + views = [row.split(',', 3) for row in views] + widths = [len(max(columns, key=len)) for columns in zip(*views)] + table_views = [] + + header = (style.MODULE_NAME('URL'), style.MODULE_NAME('Module'), style.MODULE_NAME('Name'), style.MODULE_NAME('Decorator')) + table_views.append( + ' | '.join('{0:<{1}}'.format(title, width) for width, title in zip(widths, header)) + ) + table_views.append('-+-'.join('-' * width for width in widths)) + + for row in views: + table_views.append( + ' | '.join('{0:<{1}}'.format(cdata, width) for width, cdata in zip(widths, row)) + ) + + # Replace original views so we can return the same object + views = table_views + + elif format_style == 'json': + if pretty_json: + return json.dumps(views, indent=4) + return json.dumps(views) + + return "\n".join([v for v in views]) + "\n" + + def extract_views_from_urlpatterns(self, urlpatterns, base='', namespace=None): + """ + Return a list of views from a list of urlpatterns. + + Each object in the returned list is a three-tuple: (view_func, regex, name) + """ + views = [] + for p in urlpatterns: + if isinstance(p, (URLPattern, RegexURLPattern)): + try: + if not p.name: + name = p.name + elif namespace: + name = '{0}:{1}'.format(namespace, p.name) + else: + name = p.name + pattern = describe_pattern(p) + views.append((p.callback, base + pattern, name)) + except ViewDoesNotExist: + continue + elif isinstance(p, (URLResolver, RegexURLResolver)): + try: + patterns = p.url_patterns + except ImportError: + continue + if namespace and p.namespace: + _namespace = '{0}:{1}'.format(namespace, p.namespace) + else: + _namespace = (p.namespace or namespace) + pattern = describe_pattern(p) + if isinstance(p, LocaleRegexURLResolver): + for language in self.LANGUAGES: + with translation.override(language[0]): + views.extend(self.extract_views_from_urlpatterns(patterns, base + pattern, namespace=_namespace)) + else: + views.extend(self.extract_views_from_urlpatterns(patterns, base + pattern, namespace=_namespace)) + elif hasattr(p, '_get_callback'): + try: + views.append((p._get_callback(), base + describe_pattern(p), p.name)) + except ViewDoesNotExist: + continue + elif hasattr(p, 'url_patterns') or hasattr(p, '_get_url_patterns'): + try: + patterns = p.url_patterns + except ImportError: + continue + views.extend(self.extract_views_from_urlpatterns(patterns, base + describe_pattern(p), namespace=namespace)) + else: + raise TypeError("%s does not appear to be a urlpattern object" % p) + return views diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/sqlcreate.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/sqlcreate.py new file mode 100644 index 0000000..a0af175 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/sqlcreate.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +import socket +import sys +import warnings + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from django.db import DEFAULT_DB_ALIAS + +from django_extensions.management.utils import signalcommand +from django_extensions.utils.deprecation import RemovedInNextVersionWarning +from django_extensions.settings import SQLITE_ENGINES, POSTGRESQL_ENGINES, MYSQL_ENGINES + + +class Command(BaseCommand): + help = """Generates the SQL to create your database for you, as specified in settings.py +The envisioned use case is something like this: + + ./manage.py sqlcreate [--database=] | mysql -u -p + ./manage.py sqlcreate [--database=] | psql -U -W""" + + requires_system_checks = False + can_import_settings = True + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '-R', '--router', action='store', dest='router', default=DEFAULT_DB_ALIAS, + help='Use this router-database other then defined in settings.py' + ) + parser.add_argument( + '--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to run command for. Defaults to the "%s" database.' % DEFAULT_DB_ALIAS, + ) + parser.add_argument( + '-D', '--drop', action='store_true', dest='drop', default=False, + help='If given, includes commands to drop any existing user and database.' + ) + + @signalcommand + def handle(self, *args, **options): + database = options['database'] + if options['router'] != DEFAULT_DB_ALIAS: + warnings.warn("--router is deprecated. You should use --database.", RemovedInNextVersionWarning, stacklevel=2) + database = options['router'] + + dbinfo = settings.DATABASES.get(database) + if dbinfo is None: + raise CommandError("Unknown database %s" % database) + + engine = dbinfo.get('ENGINE') + dbuser = dbinfo.get('USER') + dbpass = dbinfo.get('PASSWORD') + dbname = dbinfo.get('NAME') + dbhost = dbinfo.get('HOST') + dbclient = socket.gethostname() + + # django settings file tells you that localhost should be specified by leaving + # the DATABASE_HOST blank + if not dbhost: + dbhost = 'localhost' + + if engine in SQLITE_ENGINES: + sys.stderr.write("-- manage.py migrate will automatically create a sqlite3 database file.\n") + elif engine in MYSQL_ENGINES: + sys.stderr.write("""-- WARNING!: https://docs.djangoproject.com/en/dev/ref/databases/#collation-settings +-- Please read this carefully! Collation will be set to utf8_bin to have case-sensitive data. +""") + print("CREATE DATABASE %s CHARACTER SET utf8 COLLATE utf8_bin;" % dbname) + print("GRANT ALL PRIVILEGES ON %s.* to '%s'@'%s' identified by '%s';" % ( + dbname, dbuser, dbclient, dbpass + )) + elif engine in POSTGRESQL_ENGINES: + if options['drop']: + print("DROP DATABASE IF EXISTS %s;" % (dbname,)) + if dbuser: + print("DROP USER IF EXISTS %s;" % (dbuser,)) + + if dbuser and dbpass: + print("CREATE USER %s WITH ENCRYPTED PASSWORD '%s' CREATEDB;" % (dbuser, dbpass)) + print("CREATE DATABASE %s WITH ENCODING 'UTF-8' OWNER \"%s\";" % (dbname, dbuser)) + print("GRANT ALL PRIVILEGES ON DATABASE %s TO %s;" % (dbname, dbuser)) + else: + print( + "-- Assuming that unix domain socket connection mode is being used because\n" + "-- USER or PASSWORD are blank in Django DATABASES configuration." + ) + print("CREATE DATABASE %s WITH ENCODING 'UTF-8';" % (dbname, )) + else: + # CREATE DATABASE is not SQL standard, but seems to be supported by most. + sys.stderr.write("-- Don't know how to handle '%s' falling back to SQL.\n" % engine) + print("CREATE DATABASE %s;" % dbname) + print("GRANT ALL PRIVILEGES ON DATABASE %s to %s;" % (dbname, dbuser)) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/sqldiff.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/sqldiff.py new file mode 100644 index 0000000..c1dab5e --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/sqldiff.py @@ -0,0 +1,1381 @@ +# -*- coding: utf-8 -*- +""" +sqldiff.py - Prints the (approximated) difference between models and database + +TODO: + - better support for relations + - better support for constraints (mainly postgresql?) + - support for table spaces with postgresql + - when a table is not managed (meta.managed==False) then only do a one-way + sqldiff ? show differences from db->table but not the other way around since + it's not managed. + +KNOWN ISSUES: + - MySQL has by far the most problems with introspection. Please be + carefull when using MySQL with sqldiff. + - Booleans are reported back as Integers, so there's no way to know if + there was a real change. + - Varchar sizes are reported back without unicode support so their size + may change in comparison to the real length of the varchar. + - Some of the 'fixes' to counter these problems might create false + positives or false negatives. +""" + +import importlib +import sys +import argparse +from typing import Dict, Union, Callable, Optional # NOQA +from django.apps import apps +from django.core.management import BaseCommand, CommandError +from django.core.management.base import OutputWrapper +from django.core.management.color import no_style +from django.db import connection, transaction, models +from django.db.models.fields import AutoField, IntegerField +from django.db.models.options import normalize_together + +from django_extensions.management.utils import signalcommand + +ORDERING_FIELD = IntegerField('_order', null=True) + + +def flatten(lst, ltypes=(list, tuple)): + ltype = type(lst) + lst = list(lst) + i = 0 + while i < len(lst): + while isinstance(lst[i], ltypes): + if not lst[i]: + lst.pop(i) + i -= 1 + break + else: + lst[i:i + 1] = lst[i] + i += 1 + return ltype(lst) + + +def all_local_fields(meta): + all_fields = [] + if meta.proxy: + for parent in meta.parents: + all_fields.extend(all_local_fields(parent._meta)) + else: + for f in meta.local_fields: + col_type = f.db_type(connection=connection) + if col_type is None: + continue + all_fields.append(f) + return all_fields + + +class SQLDiff: + DATA_TYPES_REVERSE_OVERRIDE = {} # type: Dict[int, Union[str, Callable]] + + IGNORE_MISSING_TABLES = [ + "django_migrations", + ] + + DIFF_TYPES = [ + 'error', + 'comment', + 'table-missing-in-db', + 'table-missing-in-model', + 'field-missing-in-db', + 'field-missing-in-model', + 'fkey-missing-in-db', + 'fkey-missing-in-model', + 'index-missing-in-db', + 'index-missing-in-model', + 'unique-missing-in-db', + 'unique-missing-in-model', + 'field-type-differ', + 'field-parameter-differ', + 'notnull-differ', + ] + DIFF_TEXTS = { + 'error': 'error: %(0)s', + 'comment': 'comment: %(0)s', + 'table-missing-in-db': "table '%(0)s' missing in database", + 'table-missing-in-model': "table '%(0)s' missing in models", + 'field-missing-in-db': "field '%(1)s' defined in model but missing in database", + 'field-missing-in-model': "field '%(1)s' defined in database but missing in model", + 'fkey-missing-in-db': "field '%(1)s' FOREIGN KEY defined in model but missing in database", + 'fkey-missing-in-model': "field '%(1)s' FOREIGN KEY defined in database but missing in model", + 'index-missing-in-db': "field '%(1)s' INDEX named '%(2)s' defined in model but missing in database", + 'index-missing-in-model': "field '%(1)s' INDEX defined in database schema but missing in model", + 'unique-missing-in-db': "field '%(1)s' UNIQUE named '%(2)s' defined in model but missing in database", + 'unique-missing-in-model': "field '%(1)s' UNIQUE defined in database schema but missing in model", + 'field-type-differ': "field '%(1)s' not of same type: db='%(3)s', model='%(2)s'", + 'field-parameter-differ': "field '%(1)s' parameters differ: db='%(3)s', model='%(2)s'", + 'notnull-differ': "field '%(1)s' null constraint should be '%(2)s' in the database", + } + + SQL_FIELD_MISSING_IN_DB = lambda self, style, qn, args: "%s %s\n\t%s %s %s;" % ( + style.SQL_KEYWORD('ALTER TABLE'), + style.SQL_TABLE(qn(args[0])), + style.SQL_KEYWORD('ADD COLUMN'), + style.SQL_FIELD(qn(args[1])), + ' '.join(style.SQL_COLTYPE(a) if i == 0 else style.SQL_KEYWORD(a) for i, a in enumerate(args[2:])) + ) + SQL_FIELD_MISSING_IN_MODEL = lambda self, style, qn, args: "%s %s\n\t%s %s;" % ( + style.SQL_KEYWORD('ALTER TABLE'), + style.SQL_TABLE(qn(args[0])), + style.SQL_KEYWORD('DROP COLUMN'), + style.SQL_FIELD(qn(args[1])) + ) + SQL_FKEY_MISSING_IN_DB = lambda self, style, qn, args: "%s %s\n\t%s %s %s %s %s (%s)%s;" % ( + style.SQL_KEYWORD('ALTER TABLE'), + style.SQL_TABLE(qn(args[0])), + style.SQL_KEYWORD('ADD COLUMN'), + style.SQL_FIELD(qn(args[1])), + ' '.join(style.SQL_COLTYPE(a) if i == 0 else style.SQL_KEYWORD(a) for i, a in enumerate(args[4:])), + style.SQL_KEYWORD('REFERENCES'), + style.SQL_TABLE(qn(args[2])), + style.SQL_FIELD(qn(args[3])), + connection.ops.deferrable_sql() + ) + SQL_INDEX_MISSING_IN_DB = lambda self, style, qn, args: "%s %s\n\t%s %s (%s%s);" % ( + style.SQL_KEYWORD('CREATE INDEX'), + style.SQL_TABLE(qn(args[2])), + # style.SQL_TABLE(qn("%s" % '_'.join('_'.join(a) if isinstance(a, (list, tuple)) else a for a in args[0:3] if a))), + style.SQL_KEYWORD('ON'), style.SQL_TABLE(qn(args[0])), + style.SQL_FIELD(', '.join(qn(e) for e in args[1])), + style.SQL_KEYWORD(args[3]) + ) + SQL_INDEX_MISSING_IN_MODEL = lambda self, style, qn, args: "%s %s;" % ( + style.SQL_KEYWORD('DROP INDEX'), + style.SQL_TABLE(qn(args[1])) + ) + SQL_UNIQUE_MISSING_IN_DB = lambda self, style, qn, args: "%s %s\n\t%s %s %s (%s);" % ( + style.SQL_KEYWORD('ALTER TABLE'), + style.SQL_TABLE(qn(args[0])), + style.SQL_KEYWORD('ADD CONSTRAINT'), + style.SQL_TABLE(qn(args[2])), + style.SQL_KEYWORD('UNIQUE'), + style.SQL_FIELD(', '.join(qn(e) for e in args[1])) + ) + SQL_UNIQUE_MISSING_IN_MODEL = lambda self, style, qn, args: "%s %s\n\t%s %s %s;" % ( + style.SQL_KEYWORD('ALTER TABLE'), + style.SQL_TABLE(qn(args[0])), + style.SQL_KEYWORD('DROP'), + style.SQL_KEYWORD('CONSTRAINT'), + style.SQL_TABLE(qn(args[1])) + ) + SQL_FIELD_TYPE_DIFFER = lambda self, style, qn, args: "%s %s\n\t%s %s %s;" % ( + style.SQL_KEYWORD('ALTER TABLE'), + style.SQL_TABLE(qn(args[0])), + style.SQL_KEYWORD("MODIFY"), + style.SQL_FIELD(qn(args[1])), + style.SQL_COLTYPE(args[2]) + ) + SQL_FIELD_PARAMETER_DIFFER = lambda self, style, qn, args: "%s %s\n\t%s %s %s;" % ( + style.SQL_KEYWORD('ALTER TABLE'), + style.SQL_TABLE(qn(args[0])), + style.SQL_KEYWORD("MODIFY"), + style.SQL_FIELD(qn(args[1])), + style.SQL_COLTYPE(args[2]) + ) + SQL_NOTNULL_DIFFER = lambda self, style, qn, args: "%s %s\n\t%s %s %s %s;" % ( + style.SQL_KEYWORD('ALTER TABLE'), + style.SQL_TABLE(qn(args[0])), + style.SQL_KEYWORD('MODIFY'), + style.SQL_FIELD(qn(args[1])), + style.SQL_KEYWORD(args[2]), + style.SQL_KEYWORD('NOT NULL') + ) + SQL_ERROR = lambda self, style, qn, args: style.NOTICE('-- Error: %s' % style.ERROR(args[0])) + SQL_COMMENT = lambda self, style, qn, args: style.NOTICE('-- Comment: %s' % style.SQL_TABLE(args[0])) + SQL_TABLE_MISSING_IN_DB = lambda self, style, qn, args: style.NOTICE('-- Table missing: %s' % args[0]) + SQL_TABLE_MISSING_IN_MODEL = lambda self, style, qn, args: style.NOTICE('-- Model missing for table: %s' % args[0]) + + can_detect_notnull_differ = False + can_detect_unsigned_differ = False + unsigned_suffix = None # type: Optional[str] + + def __init__(self, app_models, options, stdout, stderr): + self.has_differences = None + self.app_models = app_models + self.options = options + self.dense = options['dense_output'] + self.stdout = stdout + self.stderr = stderr + + self.introspection = connection.introspection + + self.differences = [] + self.unknown_db_fields = {} + self.new_db_fields = set() + self.null = {} + self.unsigned = set() + + self.DIFF_SQL = { + 'error': self.SQL_ERROR, + 'comment': self.SQL_COMMENT, + 'table-missing-in-db': self.SQL_TABLE_MISSING_IN_DB, + 'table-missing-in-model': self.SQL_TABLE_MISSING_IN_MODEL, + 'field-missing-in-db': self.SQL_FIELD_MISSING_IN_DB, + 'field-missing-in-model': self.SQL_FIELD_MISSING_IN_MODEL, + 'fkey-missing-in-db': self.SQL_FKEY_MISSING_IN_DB, + 'fkey-missing-in-model': self.SQL_FIELD_MISSING_IN_MODEL, + 'index-missing-in-db': self.SQL_INDEX_MISSING_IN_DB, + 'index-missing-in-model': self.SQL_INDEX_MISSING_IN_MODEL, + 'unique-missing-in-db': self.SQL_UNIQUE_MISSING_IN_DB, + 'unique-missing-in-model': self.SQL_UNIQUE_MISSING_IN_MODEL, + 'field-type-differ': self.SQL_FIELD_TYPE_DIFFER, + 'field-parameter-differ': self.SQL_FIELD_PARAMETER_DIFFER, + 'notnull-differ': self.SQL_NOTNULL_DIFFER, + } + + def load(self): + self.cursor = connection.cursor() + self.django_tables = self.introspection.django_table_names(only_existing=self.options['only_existing']) + # TODO: We are losing information about tables which are views here + self.db_tables = [table_info.name for table_info in self.introspection.get_table_list(self.cursor)] + + if self.can_detect_notnull_differ: + self.load_null() + + if self.can_detect_unsigned_differ: + self.load_unsigned() + + def load_null(self): + raise NotImplementedError("load_null functions must be implemented if diff backend has 'can_detect_notnull_differ' set to True") + + def load_unsigned(self): + raise NotImplementedError("load_unsigned function must be implemented if diff backend has 'can_detect_unsigned_differ' set to True") + + def add_app_model_marker(self, app_label, model_name): + self.differences.append((app_label, model_name, [])) + + def add_difference(self, diff_type, *args): + assert diff_type in self.DIFF_TYPES, 'Unknown difference type' + self.differences[-1][-1].append((diff_type, args)) + + def get_data_types_reverse_override(self): + # type: () -> Dict[int, Union[str, Callable]] + return self.DATA_TYPES_REVERSE_OVERRIDE + + def format_field_names(self, field_names): + return field_names + + def sql_to_dict(self, query, param): + """ + Execute query and return a dict + + sql_to_dict(query, param) -> list of dicts + + code from snippet at http://www.djangosnippets.org/snippets/1383/ + """ + cursor = connection.cursor() + cursor.execute(query, param) + fieldnames = [name[0] for name in cursor.description] + fieldnames = self.format_field_names(fieldnames) + result = [] + for row in cursor.fetchall(): + rowset = [] + for field in zip(fieldnames, row): + rowset.append(field) + result.append(dict(rowset)) + return result + + def get_field_model_type(self, field): + return field.db_type(connection=connection) + + def get_field_db_type_kwargs(self, current_kwargs, description, field=None, table_name=None, reverse_type=None): + return {} + + def get_field_db_type(self, description, field=None, table_name=None): + # DB-API cursor.description + # (name, type_code, display_size, internal_size, precision, scale, null_ok) = description + type_code = description[1] + DATA_TYPES_REVERSE_OVERRIDE = self.get_data_types_reverse_override() + if type_code in DATA_TYPES_REVERSE_OVERRIDE: + reverse_type = DATA_TYPES_REVERSE_OVERRIDE[type_code] + else: + try: + reverse_type = self.introspection.get_field_type(type_code, description) + except KeyError: + reverse_type = self.get_field_db_type_lookup(type_code) + if not reverse_type: + # type_code not found in data_types_reverse map + key = (self.differences[-1][:2], description[:2]) + if key not in self.unknown_db_fields: + self.unknown_db_fields[key] = 1 + self.add_difference('comment', "Unknown database type for field '%s' (%s)" % (description[0], type_code)) + return None + + if callable(reverse_type): + reverse_type = reverse_type() + + kwargs = {} + + if isinstance(reverse_type, dict): + kwargs.update(reverse_type['kwargs']) + reverse_type = reverse_type['name'] + + if type_code == 16946 and field and getattr(field, 'geom_type', None) == 'POINT': + reverse_type = 'django.contrib.gis.db.models.fields.PointField' + + if isinstance(reverse_type, tuple): + kwargs.update(reverse_type[1]) + reverse_type = reverse_type[0] + + if reverse_type == "CharField" and description[3]: + kwargs['max_length'] = description[3] + + if reverse_type == "DecimalField": + kwargs['max_digits'] = description[4] + kwargs['decimal_places'] = description[5] and abs(description[5]) or description[5] + + if description[6]: + kwargs['blank'] = True + if reverse_type not in ('TextField', 'CharField'): + kwargs['null'] = True + + if field and getattr(field, 'geography', False): + kwargs['geography'] = True + + if reverse_type == 'GeometryField': + geo_col = description[0] + # Getting a more specific field type and any additional parameters + # from the `get_geometry_type` routine for the spatial backend. + reverse_type, geo_params = self.introspection.get_geometry_type(table_name, geo_col) + if geo_params: + kwargs.update(geo_params) + reverse_type = 'django.contrib.gis.db.models.fields.%s' % reverse_type + + extra_kwargs = self.get_field_db_type_kwargs(kwargs, description, field, table_name, reverse_type) + kwargs.update(extra_kwargs) + + field_class = self.get_field_class(reverse_type) + field_db_type = field_class(**kwargs).db_type(connection=connection) + + tablespace = field.db_tablespace + if not tablespace: + tablespace = "public" + if (tablespace, table_name, field.column) in self.unsigned and self.unsigned_suffix not in field_db_type: + field_db_type = '%s %s' % (field_db_type, self.unsigned_suffix) + + return field_db_type + + def get_field_db_type_lookup(self, type_code): + return None + + def get_field_class(self, class_path): + if '.' in class_path: + module_path, package_name = class_path.rsplit('.', 1) + module = importlib.import_module(module_path) + return getattr(module, package_name) + + return getattr(models, class_path) + + def get_field_db_nullable(self, field, table_name): + tablespace = field.db_tablespace + if tablespace == "": + tablespace = "public" + attname = field.db_column or field.attname + return self.null.get((tablespace, table_name, attname), 'fixme') + + def strip_parameters(self, field_type): + if field_type and field_type != 'double precision': + return field_type.split(" ")[0].split("(")[0].lower() + return field_type + + def expand_together(self, together, meta): + new_together = [] + for fields in normalize_together(together): + new_together.append( + tuple(meta.get_field(field).attname for field in fields) + ) + return new_together + + def find_unique_missing_in_db(self, meta, table_indexes, table_constraints, table_name, skip_list=None): + schema_editor = connection.SchemaEditorClass(connection) + for field in all_local_fields(meta): + if skip_list and field.attname in skip_list: + continue + if field.unique and meta.managed: + attname = field.db_column or field.attname + db_field_unique = table_indexes.get(attname, {}).get('unique') + if not db_field_unique and table_constraints: + db_field_unique = any(constraint['unique'] for contraint_name, constraint in table_constraints.items() if [attname] == constraint['columns']) + if attname in table_indexes and db_field_unique: + continue + + index_name = schema_editor._create_index_name(table_name, [attname]) + + self.add_difference('unique-missing-in-db', table_name, [attname], index_name + "_uniq") + db_type = field.db_type(connection=connection) + if db_type.startswith('varchar'): + self.add_difference('index-missing-in-db', table_name, [attname], index_name + '_like', ' varchar_pattern_ops') + if db_type.startswith('text'): + self.add_difference('index-missing-in-db', table_name, [attname], index_name + '_like', ' text_pattern_ops') + + unique_together = self.expand_together(meta.unique_together, meta) + db_unique_columns = normalize_together([v['columns'] for v in table_constraints.values() if v['unique'] and not v['index']]) + + for unique_columns in unique_together: + if unique_columns in db_unique_columns: + continue + + if skip_list and unique_columns in skip_list: + continue + + index_name = schema_editor._create_index_name(table_name, unique_columns) + + self.add_difference('unique-missing-in-db', table_name, unique_columns, index_name + "_uniq") + + def find_unique_missing_in_model(self, meta, table_indexes, table_constraints, table_name): + fields = dict([(field.column, field) for field in all_local_fields(meta)]) + unique_together = self.expand_together(meta.unique_together, meta) + + for constraint_name, constraint in table_constraints.items(): + if not constraint['unique']: + continue + if constraint['index']: + # unique indexes are handled by find_index_missing_in_model + continue + + columns = constraint['columns'] + if len(columns) == 1: + field = fields.get(columns[0]) + if field is None: + pass + elif field.unique: + continue + else: + if tuple(columns) in unique_together: + continue + + self.add_difference('unique-missing-in-model', table_name, constraint_name) + + def find_index_missing_in_db(self, meta, table_indexes, table_constraints, table_name): + schema_editor = connection.SchemaEditorClass(connection) + for field in all_local_fields(meta): + if field.db_index: + attname = field.db_column or field.attname + if attname not in table_indexes: + index_name = schema_editor._create_index_name(table_name, [attname]) + self.add_difference('index-missing-in-db', table_name, [attname], index_name, '') + db_type = field.db_type(connection=connection) + if db_type.startswith('varchar'): + self.add_difference('index-missing-in-db', table_name, [attname], index_name + '_like', ' varchar_pattern_ops') + if db_type.startswith('text'): + self.add_difference('index-missing-in-db', table_name, [attname], index_name + '_like', ' text_pattern_ops') + + index_together = self.expand_together(meta.index_together, meta) + db_index_together = normalize_together([v['columns'] for v in table_constraints.values() if v['index'] and not v['unique']]) + for columns in index_together: + if columns in db_index_together: + continue + index_name = schema_editor._create_index_name(table_name, columns) + self.add_difference('index-missing-in-db', table_name, columns, index_name + "_idx", '') + + for index in meta.indexes: + if index.name not in table_constraints: + self.add_difference('index-missing-in-db', table_name, index.fields, index.name, '') + + def find_index_missing_in_model(self, meta, table_indexes, table_constraints, table_name): + fields = dict([(field.column, field) for field in all_local_fields(meta)]) + meta_index_names = [idx.name for idx in meta.indexes] + index_together = self.expand_together(meta.index_together, meta) + + for constraint_name, constraint in table_constraints.items(): + if constraint_name in meta_index_names: + continue + if constraint['unique'] and not constraint['index']: + # unique constraints are handled by find_unique_missing_in_model + continue + + columns = constraint['columns'] + field = fields.get(columns[0]) + if (constraint['unique'] and constraint['index']) or field is None: + # unique indexes do not exist in django ? only unique constraints + pass + elif len(columns) == 1: + if constraint['primary_key'] and field.primary_key: + continue + if constraint['foreign_key'] and isinstance(field, models.ForeignKey) and field.db_constraint: + continue + if constraint['unique'] and field.unique: + continue + if constraint['index'] and constraint['type'] == 'idx' and constraint.get('orders') and field.unique: + # django automatically creates a _like varchar_pattern_ops/text_pattern_ops index see https://code.djangoproject.com/ticket/12234 + # note: mysql does not have and/or introspect and fill the 'orders' attribute of constraint information + continue + if constraint['index'] and field.db_index: + continue + if constraint['check'] and field.db_check(connection=connection): + continue + if getattr(field, 'spatial_index', False): + continue + else: + if constraint['index'] and tuple(columns) in index_together: + continue + + self.add_difference('index-missing-in-model', table_name, constraint_name) + + def find_field_missing_in_model(self, fieldmap, table_description, table_name): + for row in table_description: + if row[0] not in fieldmap: + self.add_difference('field-missing-in-model', table_name, row[0]) + + def find_field_missing_in_db(self, fieldmap, table_description, table_name): + db_fields = [row[0] for row in table_description] + for field_name, field in fieldmap.items(): + if field_name not in db_fields: + field_output = [] + + if field.remote_field: + field_output.extend([field.remote_field.model._meta.db_table, field.remote_field.model._meta.get_field(field.remote_field.field_name).column]) + op = 'fkey-missing-in-db' + else: + op = 'field-missing-in-db' + field_output.append(field.db_type(connection=connection)) + if self.options['include_defaults'] and field.has_default(): + field_output.append('DEFAULT %s' % field.get_prep_value(field.get_default())) + if not field.null: + field_output.append('NOT NULL') + self.add_difference(op, table_name, field_name, *field_output) + self.new_db_fields.add((table_name, field_name)) + + def find_field_type_differ(self, meta, table_description, table_name, func=None): + db_fields = dict([(row[0], row) for row in table_description]) + for field in all_local_fields(meta): + if field.name not in db_fields: + continue + description = db_fields[field.name] + + model_type = self.get_field_model_type(field) + db_type = self.get_field_db_type(description, field, table_name) + + # use callback function if defined + if func: + model_type, db_type = func(field, description, model_type, db_type) + + if not self.strip_parameters(db_type) == self.strip_parameters(model_type): + self.add_difference('field-type-differ', table_name, field.name, model_type, db_type) + + def find_field_parameter_differ(self, meta, table_description, table_name, func=None): + db_fields = dict([(row[0], row) for row in table_description]) + for field in all_local_fields(meta): + if field.name not in db_fields: + continue + description = db_fields[field.name] + + model_type = self.get_field_model_type(field) + db_type = self.get_field_db_type(description, field, table_name) + + if not self.strip_parameters(model_type) == self.strip_parameters(db_type): + continue + + # use callback function if defined + if func: + model_type, db_type = func(field, description, model_type, db_type) + + model_check = field.db_parameters(connection=connection)['check'] + if ' CHECK' in db_type: + db_type, db_check = db_type.split(" CHECK", 1) + db_check = db_check.strip().lstrip("(").rstrip(")") + else: + db_check = None + + if not model_type == db_type or not model_check == db_check: + self.add_difference('field-parameter-differ', table_name, field.name, model_type, db_type) + + def find_field_notnull_differ(self, meta, table_description, table_name): + if not self.can_detect_notnull_differ: + return + + for field in all_local_fields(meta): + attname = field.db_column or field.attname + if (table_name, attname) in self.new_db_fields: + continue + null = self.get_field_db_nullable(field, table_name) + if field.null != null: + action = field.null and 'DROP' or 'SET' + self.add_difference('notnull-differ', table_name, attname, action) + + def get_constraints(self, cursor, table_name, introspection): + return {} + + def find_differences(self): + if self.options['all_applications']: + self.add_app_model_marker(None, None) + for table in self.db_tables: + if table not in self.django_tables and table not in self.IGNORE_MISSING_TABLES: + self.add_difference('table-missing-in-model', table) + + cur_app_label = None + for app_model in self.app_models: + meta = app_model._meta + table_name = meta.db_table + app_label = meta.app_label + + if not self.options['include_proxy_models'] and meta.proxy: + continue + + if cur_app_label != app_label: + # Marker indicating start of difference scan for this table_name + self.add_app_model_marker(app_label, app_model.__name__) + + if table_name not in self.db_tables: + # Table is missing from database + self.add_difference('table-missing-in-db', table_name) + continue + + if hasattr(self.introspection, 'get_constraints'): + table_constraints = self.introspection.get_constraints(self.cursor, table_name) + else: + table_constraints = self.get_constraints(self.cursor, table_name, self.introspection) + + fieldmap = dict([(field.db_column or field.get_attname(), field) for field in all_local_fields(meta)]) + + # add ordering field if model uses order_with_respect_to + if meta.order_with_respect_to: + fieldmap['_order'] = ORDERING_FIELD + + try: + table_description = self.introspection.get_table_description(self.cursor, table_name) + except Exception as e: + self.add_difference('error', 'unable to introspect table: %s' % str(e).strip()) + transaction.rollback() # reset transaction + continue + + # map table_contraints into table_indexes + table_indexes = {} + for contraint_name, dct in table_constraints.items(): + + columns = dct['columns'] + if len(columns) == 1: + table_indexes[columns[0]] = { + 'primary_key': dct['primary_key'], + 'unique': dct['unique'], + 'type': dct.get('type'), + 'contraint_name': contraint_name, + } + + # Fields which are defined in database but not in model + # 1) find: 'unique-missing-in-model' + self.find_unique_missing_in_model(meta, table_indexes, table_constraints, table_name) + # 2) find: 'index-missing-in-model' + self.find_index_missing_in_model(meta, table_indexes, table_constraints, table_name) + # 3) find: 'field-missing-in-model' + self.find_field_missing_in_model(fieldmap, table_description, table_name) + + # Fields which are defined in models but not in database + # 4) find: 'field-missing-in-db' + self.find_field_missing_in_db(fieldmap, table_description, table_name) + # 5) find: 'unique-missing-in-db' + self.find_unique_missing_in_db(meta, table_indexes, table_constraints, table_name) + # 6) find: 'index-missing-in-db' + self.find_index_missing_in_db(meta, table_indexes, table_constraints, table_name) + + # Fields which have a different type or parameters + # 7) find: 'type-differs' + self.find_field_type_differ(meta, table_description, table_name) + # 8) find: 'type-parameter-differs' + self.find_field_parameter_differ(meta, table_description, table_name) + # 9) find: 'field-notnull' + self.find_field_notnull_differ(meta, table_description, table_name) + self.has_differences = max([len(diffs) for _app_label, _model_name, diffs in self.differences]) + + def print_diff(self, style=no_style()): + """ Print differences to stdout """ + if self.options['sql']: + self.print_diff_sql(style) + else: + self.print_diff_text(style) + + def print_diff_text(self, style): + if not self.can_detect_notnull_differ: + self.stdout.write(style.NOTICE("# Detecting notnull changes not implemented for this database backend")) + self.stdout.write("") + + if not self.can_detect_unsigned_differ: + self.stdout.write(style.NOTICE("# Detecting unsigned changes not implemented for this database backend")) + self.stdout.write("") + + cur_app_label = None + for app_label, model_name, diffs in self.differences: + if not diffs: + continue + if not self.dense and app_label and cur_app_label != app_label: + self.stdout.write("%s %s" % (style.NOTICE("+ Application:"), style.SQL_TABLE(app_label))) + cur_app_label = app_label + if not self.dense and model_name: + self.stdout.write("%s %s" % (style.NOTICE("|-+ Differences for model:"), style.SQL_TABLE(model_name))) + for diff in diffs: + diff_type, diff_args = diff + text = self.DIFF_TEXTS[diff_type] % dict( + (str(i), style.SQL_TABLE(', '.join(e) if isinstance(e, (list, tuple)) else e)) + for i, e in enumerate(diff_args) + ) + text = "'".join(i % 2 == 0 and style.ERROR(e) or e for i, e in enumerate(text.split("'"))) + if not self.dense: + self.stdout.write("%s %s" % (style.NOTICE("|--+"), text)) + else: + if app_label: + self.stdout.write("%s %s %s %s %s" % (style.NOTICE("App"), style.SQL_TABLE(app_label), style.NOTICE('Model'), style.SQL_TABLE(model_name), text)) + else: + self.stdout.write(text) + + def print_diff_sql(self, style): + if not self.can_detect_notnull_differ: + self.stdout.write(style.NOTICE("-- Detecting notnull changes not implemented for this database backend")) + self.stdout.write("") + + cur_app_label = None + qn = connection.ops.quote_name + if not self.has_differences: + if not self.dense: + self.stdout.write(style.SQL_KEYWORD("-- No differences")) + else: + self.stdout.write(style.SQL_KEYWORD("BEGIN;")) + for app_label, model_name, diffs in self.differences: + if not diffs: + continue + if not self.dense and cur_app_label != app_label: + self.stdout.write(style.NOTICE("-- Application: %s" % style.SQL_TABLE(app_label))) + cur_app_label = app_label + if not self.dense and model_name: + self.stdout.write(style.NOTICE("-- Model: %s" % style.SQL_TABLE(model_name))) + for diff in diffs: + diff_type, diff_args = diff + text = self.DIFF_SQL[diff_type](style, qn, diff_args) + if self.dense: + text = text.replace("\n\t", " ") + self.stdout.write(text) + self.stdout.write(style.SQL_KEYWORD("COMMIT;")) + + +class GenericSQLDiff(SQLDiff): + can_detect_notnull_differ = False + can_detect_unsigned_differ = False + + def load_null(self): + pass + + def load_unsigned(self): + pass + + +class MySQLDiff(SQLDiff): + can_detect_notnull_differ = True + can_detect_unsigned_differ = True + unsigned_suffix = 'UNSIGNED' + + def load(self): + super().load() + self.auto_increment = set() + self.load_auto_increment() + + def format_field_names(self, field_names): + return [f.lower() for f in field_names] + + def load_null(self): + tablespace = 'public' + for table_name in self.db_tables: + result = self.sql_to_dict(""" + SELECT column_name, is_nullable + FROM information_schema.columns + WHERE table_schema = DATABASE() + AND table_name = %s""", [table_name]) + for table_info in result: + key = (tablespace, table_name, table_info['column_name']) + self.null[key] = table_info['is_nullable'] == 'YES' + + def load_unsigned(self): + tablespace = 'public' + for table_name in self.db_tables: + result = self.sql_to_dict(""" + SELECT column_name + FROM information_schema.columns + WHERE table_schema = DATABASE() + AND table_name = %s + AND column_type LIKE '%%unsigned'""", [table_name]) + for table_info in result: + key = (tablespace, table_name, table_info['column_name']) + self.unsigned.add(key) + + def load_auto_increment(self): + for table_name in self.db_tables: + result = self.sql_to_dict(""" + SELECT column_name + FROM information_schema.columns + WHERE table_schema = DATABASE() + AND table_name = %s + AND extra = 'auto_increment'""", [table_name]) + for table_info in result: + key = (table_name, table_info['column_name']) + self.auto_increment.add(key) + + # All the MySQL hacks together create something of a problem + # Fixing one bug in MySQL creates another issue. So just keep in mind + # that this is way unreliable for MySQL atm. + def get_field_db_type(self, description, field=None, table_name=None): + db_type = super().get_field_db_type(description, field, table_name) + if not db_type: + return + if field: + # MySQL isn't really sure about char's and varchar's like sqlite + field_type = self.get_field_model_type(field) + + # Fix char/varchar inconsistencies + if self.strip_parameters(field_type) == 'char' and self.strip_parameters(db_type) == 'varchar': + db_type = db_type.lstrip("var") + + # They like to call bools various integer types and introspection makes that a integer + # just convert them all to bools + if self.strip_parameters(field_type) == 'bool': + if db_type == 'integer': + db_type = 'bool' + + if (table_name, field.column) in self.auto_increment and 'AUTO_INCREMENT' not in db_type: + db_type += ' AUTO_INCREMENT' + return db_type + + def find_index_missing_in_model(self, meta, table_indexes, table_constraints, table_name): + fields = dict([(field.column, field) for field in all_local_fields(meta)]) + meta_index_names = [idx.name for idx in meta.indexes] + index_together = self.expand_together(meta.index_together, meta) + unique_together = self.expand_together(meta.unique_together, meta) + + for constraint_name, constraint in table_constraints.items(): + if constraint_name in meta_index_names: + continue + if constraint['unique'] and not constraint['index']: + # unique constraints are handled by find_unique_missing_in_model + continue + + columns = constraint['columns'] + field = fields.get(columns[0]) + + # extra check removed from superclass here, otherwise function is the same + if len(columns) == 1: + if constraint['primary_key'] and field.primary_key: + continue + if constraint['foreign_key'] and isinstance(field, models.ForeignKey) and field.db_constraint: + continue + if constraint['unique'] and field.unique: + continue + if constraint['index'] and constraint['type'] == 'idx' and constraint.get('orders') and field.unique: + # django automatically creates a _like varchar_pattern_ops/text_pattern_ops index see https://code.djangoproject.com/ticket/12234 + # note: mysql does not have and/or introspect and fill the 'orders' attribute of constraint information + continue + if constraint['index'] and field.db_index: + continue + if constraint['check'] and field.db_check(connection=connection): + continue + if getattr(field, 'spatial_index', False): + continue + else: + if constraint['index'] and tuple(columns) in index_together: + continue + if constraint['index'] and constraint['unique'] and tuple(columns) in unique_together: + continue + + self.add_difference('index-missing-in-model', table_name, constraint_name) + + def find_unique_missing_in_db(self, meta, table_indexes, table_constraints, table_name, skip_list=None): + + schema_editor = connection.SchemaEditorClass(connection) + for field in all_local_fields(meta): + if skip_list and field.attname in skip_list: + continue + if field.unique and meta.managed: + attname = field.db_column or field.attname + db_field_unique = table_indexes.get(attname, {}).get('unique') + if not db_field_unique and table_constraints: + db_field_unique = any(constraint['unique'] for contraint_name, constraint in table_constraints.items() if [attname] == constraint['columns']) + if attname in table_indexes and db_field_unique: + continue + + index_name = schema_editor._create_index_name(table_name, [attname]) + + self.add_difference('unique-missing-in-db', table_name, [attname], index_name + "_uniq") + db_type = field.db_type(connection=connection) + if db_type.startswith('varchar'): + self.add_difference('index-missing-in-db', table_name, [attname], index_name + '_like', ' varchar_pattern_ops') + if db_type.startswith('text'): + self.add_difference('index-missing-in-db', table_name, [attname], index_name + '_like', ' text_pattern_ops') + + unique_together = self.expand_together(meta.unique_together, meta) + + # This comparison changed from superclass - otherwise function is the same + db_unique_columns = normalize_together([v['columns'] for v in table_constraints.values() if v['unique']]) + + for unique_columns in unique_together: + if unique_columns in db_unique_columns: + continue + + if skip_list and unique_columns in skip_list: + continue + + index_name = schema_editor._create_index_name(table_name, unique_columns) + self.add_difference('unique-missing-in-db', table_name, unique_columns, index_name + "_uniq") + + +class SqliteSQLDiff(SQLDiff): + can_detect_notnull_differ = True + can_detect_unsigned_differ = False + + def load_null(self): + for table_name in self.db_tables: + # sqlite does not support tablespaces + tablespace = "public" + # index, column_name, column_type, nullable, default_value + # see: http://www.sqlite.org/pragma.html#pragma_table_info + for table_info in self.sql_to_dict("PRAGMA table_info('%s');" % table_name, []): + key = (tablespace, table_name, table_info['name']) + self.null[key] = not table_info['notnull'] + + def load_unsigned(self): + pass + + # Unique does not seem to be implied on Sqlite for Primary_key's + # if this is more generic among databases this might be usefull + # to add to the superclass's find_unique_missing_in_db method + def find_unique_missing_in_db(self, meta, table_indexes, table_constraints, table_name, skip_list=None): + if skip_list is None: + skip_list = [] + + unique_columns = [field.db_column or field.attname for field in all_local_fields(meta) if field.unique] + + for constraint in table_constraints.values(): + columns = constraint['columns'] + if len(columns) == 1: + column = columns[0] + if column in unique_columns and (constraint['unique'] or constraint['primary_key']): + skip_list.append(column) + + unique_together = self.expand_together(meta.unique_together, meta) + db_unique_columns = normalize_together([v['columns'] for v in table_constraints.values() if v['unique']]) + + for unique_columns in unique_together: + if unique_columns in db_unique_columns: + skip_list.append(unique_columns) + + super().find_unique_missing_in_db(meta, table_indexes, table_constraints, table_name, skip_list=skip_list) + + # Finding Indexes by using the get_indexes dictionary doesn't seem to work + # for sqlite. + def find_index_missing_in_db(self, meta, table_indexes, table_constraints, table_name): + pass + + def find_index_missing_in_model(self, meta, table_indexes, table_constraints, table_name): + pass + + def get_field_db_type(self, description, field=None, table_name=None): + db_type = super().get_field_db_type(description, field, table_name) + if not db_type: + return None + if field: + field_type = self.get_field_model_type(field) + # Fix char/varchar inconsistencies + if self.strip_parameters(field_type) == 'char' and self.strip_parameters(db_type) == 'varchar': + db_type = db_type.lstrip("var") + return db_type + + +class PostgresqlSQLDiff(SQLDiff): + can_detect_notnull_differ = True + can_detect_unsigned_differ = True + + DATA_TYPES_REVERSE_NAME = { + 'hstore': 'django.contrib.postgres.fields.HStoreField', + 'jsonb': 'django.contrib.postgres.fields.JSONField', + } + + # Hopefully in the future we can add constraint checking and other more + # advanced checks based on this database. + SQL_LOAD_CONSTRAINTS = """ + SELECT nspname, relname, conname, attname, pg_get_constraintdef(pg_constraint.oid) + FROM pg_constraint + INNER JOIN pg_attribute ON pg_constraint.conrelid = pg_attribute.attrelid AND pg_attribute.attnum = any(pg_constraint.conkey) + INNER JOIN pg_class ON conrelid=pg_class.oid + INNER JOIN pg_namespace ON pg_namespace.oid=pg_class.relnamespace + ORDER BY CASE WHEN contype='f' THEN 0 ELSE 1 END,contype,nspname,relname,conname; + """ + SQL_LOAD_NULL = """ + SELECT nspname, relname, attname, attnotnull + FROM pg_attribute + INNER JOIN pg_class ON attrelid=pg_class.oid + INNER JOIN pg_namespace ON pg_namespace.oid=pg_class.relnamespace; + """ + + SQL_FIELD_TYPE_DIFFER = lambda self, style, qn, args: "%s %s\n\t%s %s %s %s;" % (style.SQL_KEYWORD('ALTER TABLE'), style.SQL_TABLE(qn(args[0])), style.SQL_KEYWORD('ALTER'), style.SQL_FIELD(qn(args[1])), style.SQL_KEYWORD("TYPE"), style.SQL_COLTYPE(args[2])) + SQL_FIELD_PARAMETER_DIFFER = lambda self, style, qn, args: "%s %s\n\t%s %s %s %s;" % (style.SQL_KEYWORD('ALTER TABLE'), style.SQL_TABLE(qn(args[0])), style.SQL_KEYWORD('ALTER'), style.SQL_FIELD(qn(args[1])), style.SQL_KEYWORD("TYPE"), style.SQL_COLTYPE(args[2])) + SQL_NOTNULL_DIFFER = lambda self, style, qn, args: "%s %s\n\t%s %s %s %s;" % (style.SQL_KEYWORD('ALTER TABLE'), style.SQL_TABLE(qn(args[0])), style.SQL_KEYWORD('ALTER COLUMN'), style.SQL_FIELD(qn(args[1])), style.SQL_KEYWORD(args[2]), style.SQL_KEYWORD('NOT NULL')) + + def load(self): + super().load() + self.check_constraints = {} + self.load_constraints() + + def load_null(self): + for dct in self.sql_to_dict(self.SQL_LOAD_NULL, []): + key = (dct['nspname'], dct['relname'], dct['attname']) + self.null[key] = not dct['attnotnull'] + + def load_unsigned(self): + # PostgreSQL does not support unsigned, so no columns are + # unsigned. Nothing to do. + pass + + def load_constraints(self): + for dct in self.sql_to_dict(self.SQL_LOAD_CONSTRAINTS, []): + key = (dct['nspname'], dct['relname'], dct['attname']) + if 'CHECK' in dct['pg_get_constraintdef']: + self.check_constraints[key] = dct + + def get_data_type_arrayfield(self, base_field): + return { + 'name': 'django.contrib.postgres.fields.ArrayField', + 'kwargs': { + 'base_field': self.get_field_class(base_field)(), + }, + } + + def get_data_types_reverse_override(self): + return { + 1042: 'CharField', + 1000: lambda: self.get_data_type_arrayfield(base_field='BooleanField'), + 1001: lambda: self.get_data_type_arrayfield(base_field='BinaryField'), + 1002: lambda: self.get_data_type_arrayfield(base_field='CharField'), + 1005: lambda: self.get_data_type_arrayfield(base_field='IntegerField'), + 1006: lambda: self.get_data_type_arrayfield(base_field='IntegerField'), + 1007: lambda: self.get_data_type_arrayfield(base_field='IntegerField'), + 1009: lambda: self.get_data_type_arrayfield(base_field='CharField'), + 1014: lambda: self.get_data_type_arrayfield(base_field='CharField'), + 1015: lambda: self.get_data_type_arrayfield(base_field='CharField'), + 1016: lambda: self.get_data_type_arrayfield(base_field='BigIntegerField'), + 1017: lambda: self.get_data_type_arrayfield(base_field='FloatField'), + 1021: lambda: self.get_data_type_arrayfield(base_field='FloatField'), + 1022: lambda: self.get_data_type_arrayfield(base_field='FloatField'), + 1115: lambda: self.get_data_type_arrayfield(base_field='DateTimeField'), + 1185: lambda: self.get_data_type_arrayfield(base_field='DateTimeField'), + 1231: lambda: self.get_data_type_arrayfield(base_field='DecimalField'), + # {'name': 'django.contrib.postgres.fields.ArrayField', 'kwargs': {'base_field': 'IntegerField'}}, + 1186: lambda: self.get_data_type_arrayfield(base_field='DurationField'), + # 1186: 'django.db.models.fields.DurationField', + 3614: 'django.contrib.postgres.search.SearchVectorField', + 3802: 'django.contrib.postgres.fields.JSONField', + } + + def get_constraints(self, cursor, table_name, introspection): + """ + Find constraints for table + + Backport of django's introspection.get_constraints(...) + """ + constraints = {} + # Loop over the key table, collecting things as constraints + # This will get PKs, FKs, and uniques, but not CHECK + cursor.execute(""" + SELECT + kc.constraint_name, + kc.column_name, + c.constraint_type, + array(SELECT table_name::text || '.' || column_name::text FROM information_schema.constraint_column_usage WHERE constraint_name = kc.constraint_name) + FROM information_schema.key_column_usage AS kc + JOIN information_schema.table_constraints AS c ON + kc.table_schema = c.table_schema AND + kc.table_name = c.table_name AND + kc.constraint_name = c.constraint_name + WHERE + kc.table_schema = %s AND + kc.table_name = %s + """, ["public", table_name]) + for constraint, column, kind, used_cols in cursor.fetchall(): + # If we're the first column, make the record + if constraint not in constraints: + constraints[constraint] = { + "columns": [], + "primary_key": kind.lower() == "primary key", + "unique": kind.lower() in ["primary key", "unique"], + "foreign_key": tuple(used_cols[0].split(".", 1)) if kind.lower() == "foreign key" else None, + "check": False, + "index": False, + } + # Record the details + constraints[constraint]['columns'].append(column) + # Now get CHECK constraint columns + cursor.execute(""" + SELECT kc.constraint_name, kc.column_name + FROM information_schema.constraint_column_usage AS kc + JOIN information_schema.table_constraints AS c ON + kc.table_schema = c.table_schema AND + kc.table_name = c.table_name AND + kc.constraint_name = c.constraint_name + WHERE + c.constraint_type = 'CHECK' AND + kc.table_schema = %s AND + kc.table_name = %s + """, ["public", table_name]) + for constraint, column in cursor.fetchall(): + # If we're the first column, make the record + if constraint not in constraints: + constraints[constraint] = { + "columns": [], + "primary_key": False, + "unique": False, + "foreign_key": None, + "check": True, + "index": False, + } + # Record the details + constraints[constraint]['columns'].append(column) + # Now get indexes + cursor.execute(""" + SELECT + c2.relname, + ARRAY( + SELECT (SELECT attname FROM pg_catalog.pg_attribute WHERE attnum = i AND attrelid = c.oid) + FROM unnest(idx.indkey) i + ), + idx.indisunique, + idx.indisprimary + FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, + pg_catalog.pg_index idx + WHERE c.oid = idx.indrelid + AND idx.indexrelid = c2.oid + AND c.relname = %s + """, [table_name]) + for index, columns, unique, primary in cursor.fetchall(): + if index not in constraints: + constraints[index] = { + "columns": list(columns), + "primary_key": primary, + "unique": unique, + "foreign_key": None, + "check": False, + "index": True, + } + return constraints + + # def get_field_db_type_kwargs(self, current_kwargs, description, field=None, table_name=None, reverse_type=None): + # kwargs = {} + # if field and 'base_field' in current_kwargs: + # # find + # attname = field.db_column or field.attname + # introspect_db_type = self.sql_to_dict( + # """SELECT attname, format_type(atttypid, atttypmod) AS type + # FROM pg_attribute + # WHERE attrelid = %s::regclass + # AND attname = %s + # AND attnum > 0 + # AND NOT attisdropped + # ORDER BY attnum; + # """, + # (table_name, attname) + # )[0]['type'] + # # TODO: this gives the concrete type that the database uses, why not use this + # # much earlier in the process to compare to whatever django spits out as + # # the database type ? + # max_length = re.search("character varying\((\d+)\)\[\]", introspect_db_type) + # if max_length: + # kwargs['max_length'] = max_length[1] + # return kwargs + + def get_field_db_type(self, description, field=None, table_name=None): + db_type = super().get_field_db_type(description, field, table_name) + if not db_type: + return + if field: + if db_type.endswith("[]"): + # TODO: This is a hack for array types. Ideally we either pass the correct + # constraints for the type in `get_data_type_arrayfield` which instantiates + # the array base_field or maybe even better restructure sqldiff entirely + # to be based around the concrete type yielded by the code below. That gives + # the complete type the database uses, why not use thie much earlier in the + # process to compare to whatever django spits out as the desired database type ? + attname = field.db_column or field.attname + introspect_db_type = self.sql_to_dict( + """SELECT attname, format_type(atttypid, atttypmod) AS type + FROM pg_attribute + WHERE attrelid = %s::regclass + AND attname = %s + AND attnum > 0 + AND NOT attisdropped + ORDER BY attnum; + """, + (table_name, attname) + )[0]['type'] + if introspect_db_type.startswith("character varying"): + introspect_db_type = introspect_db_type.replace("character varying", "varchar") + + return introspect_db_type + + if field.primary_key and isinstance(field, AutoField): + if db_type == 'integer': + db_type = 'serial' + elif db_type == 'bigint': + db_type = 'bigserial' + if table_name: + tablespace = field.db_tablespace + if tablespace == "": + tablespace = "public" + attname = field.db_column or field.attname + check_constraint = self.check_constraints.get((tablespace, table_name, attname), {}).get('pg_get_constraintdef', None) + if check_constraint: + check_constraint = check_constraint.replace("((", "(") + check_constraint = check_constraint.replace("))", ")") + check_constraint = '("'.join([')' in e and '" '.join(p.strip('"') for p in e.split(" ", 1)) or e for e in check_constraint.split("(")]) + # TODO: might be more then one constraint in definition ? + db_type += ' ' + check_constraint + return db_type + + def get_field_db_type_lookup(self, type_code): + try: + name = self.sql_to_dict("SELECT typname FROM pg_type WHERE typelem=%s;", [type_code])[0]['typname'] + return self.DATA_TYPES_REVERSE_NAME.get(name.strip('_')) + except (IndexError, KeyError): + pass + + """ + def find_field_type_differ(self, meta, table_description, table_name): + def callback(field, description, model_type, db_type): + if field.primary_key and db_type=='integer': + db_type = 'serial' + return model_type, db_type + super().find_field_type_differ(meta, table_description, table_name, callback) + """ + + +DATABASE_SQLDIFF_CLASSES = { + 'postgis': PostgresqlSQLDiff, + 'postgresql_psycopg2': PostgresqlSQLDiff, + 'postgresql': PostgresqlSQLDiff, + 'mysql': MySQLDiff, + 'sqlite3': SqliteSQLDiff, + 'oracle': GenericSQLDiff +} + + +class Command(BaseCommand): + help = """Prints the (approximated) difference between models and fields in the database for the given app name(s). + +It indicates how columns in the database are different from the sql that would +be generated by Django. This command is not a database migration tool. (Though +it can certainly help) It's purpose is to show the current differences as a way +to check/debug ur models compared to the real database tables and columns.""" + + output_transaction = False + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument('app_label', nargs='*') + parser.add_argument( + '--all-applications', '-a', action='store_true', + default=False, + dest='all_applications', + help="Automaticly include all application from INSTALLED_APPS." + ) + parser.add_argument( + '--not-only-existing', '-e', action='store_false', + default=True, + dest='only_existing', + help="Check all tables that exist in the database, not only tables that should exist based on models." + ) + parser.add_argument( + '--dense-output', '-d', action='store_true', dest='dense_output', + default=False, + help="Shows the output in dense format, normally output is spreaded over multiple lines." + ) + parser.add_argument( + '--output_text', '-t', action='store_false', dest='sql', + default=True, + help="Outputs the differences as descriptive text instead of SQL" + ) + parser.add_argument( + '--include-proxy-models', action='store_true', dest='include_proxy_models', + default=False, + help="Include proxy models in the graph" + ) + parser.add_argument( + '--include-defaults', action='store_true', dest='include_defaults', + default=False, + help="Include default values in SQL output (beta feature)" + ) + parser.add_argument( + '--migrate-for-tests', action='store_true', dest='migrate_for_tests', + default=False, + help=argparse.SUPPRESS + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.exit_code = 1 + + @signalcommand + def handle(self, *args, **options): + from django.conf import settings + + app_labels = options['app_label'] + engine = None + if hasattr(settings, 'DATABASES'): + engine = settings.DATABASES['default']['ENGINE'] + else: + engine = settings.DATABASE_ENGINE + + if engine == 'dummy': + # This must be the "dummy" database backend, which means the user + # hasn't set DATABASE_ENGINE. + raise CommandError("""Django doesn't know which syntax to use for your SQL statements, +because you haven't specified the DATABASE_ENGINE setting. +Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.""") + + if options['all_applications']: + app_models = apps.get_models(include_auto_created=True) + else: + if not app_labels: + raise CommandError('Enter at least one appname.') + + if not isinstance(app_labels, (list, tuple, set)): + app_labels = [app_labels] + + app_models = [] + for app_label in app_labels: + app_config = apps.get_app_config(app_label) + app_models.extend(app_config.get_models(include_auto_created=True)) + + if not app_models: + raise CommandError('Unable to execute sqldiff no models founds.') + + migrate_for_tests = options['migrate_for_tests'] + if migrate_for_tests: + from django.core.management import call_command + call_command("migrate", *app_labels, no_input=True, run_syncdb=True) + + if not engine: + engine = connection.__module__.split('.')[-2] + + if '.' in engine: + engine = engine.split('.')[-1] + + cls = DATABASE_SQLDIFF_CLASSES.get(engine, GenericSQLDiff) + sqldiff_instance = cls(app_models, options, stdout=self.stdout, stderr=self.stderr) + sqldiff_instance.load() + sqldiff_instance.find_differences() + if not sqldiff_instance.has_differences: + self.exit_code = 0 + sqldiff_instance.print_diff(self.style) + + def execute(self, *args, **options): + try: + super().execute(*args, **options) + except CommandError as e: + if options['traceback']: + raise + + # self.stderr is not guaranteed to be set here + stderr = getattr(self, 'stderr', None) + if not stderr: + stderr = OutputWrapper(sys.stderr, self.style.ERROR) + stderr.write('%s: %s' % (e.__class__.__name__, e)) + sys.exit(2) + + def run_from_argv(self, argv): + super().run_from_argv(argv) + sys.exit(self.exit_code) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/sqldsn.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/sqldsn.py new file mode 100644 index 0000000..dab3772 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/sqldsn.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- +""" +sqldns.py + +Prints Data Source Name on stdout +""" + +import sys +import warnings + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from django.core.management.color import color_style +from django.db import DEFAULT_DB_ALIAS +from django_extensions.settings import SQLITE_ENGINES, POSTGRESQL_ENGINES, MYSQL_ENGINES +from django_extensions.utils.deprecation import RemovedInNextVersionWarning + + +class Command(BaseCommand): + help = "Prints DSN on stdout, as specified in settings.py" + requires_system_checks = False + can_import_settings = True + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '-R', '--router', action='store', + dest='router', default=DEFAULT_DB_ALIAS, + help='Use this router-database other then default (deprecated: use --database instead)' + ) + parser.add_argument( + '--database', default=DEFAULT_DB_ALIAS, + help='Nominates a database to run command for. Defaults to the "%s" database.' % DEFAULT_DB_ALIAS, + ) + parser.add_argument( + '-s', '--style', action='store', + dest='style', default=None, + help='DSN format style: keyvalue, uri, pgpass, all' + ) + parser.add_argument( + '-a', '--all', action='store_true', + dest='all', default=False, + help='Show DSN for all database routes' + ) + parser.add_argument( + '-q', '--quiet', action='store_true', + dest='quiet', default=False, + help='Quiet mode only show DSN' + ) + + def handle(self, *args, **options): + self.style = color_style() + all_databases = options['all'] + + if all_databases: + databases = settings.DATABASES.keys() + else: + databases = [options['database']] + if options['router'] != DEFAULT_DB_ALIAS: + warnings.warn("--router is deprecated. You should use --database.", RemovedInNextVersionWarning, stacklevel=2) + databases = [options['router']] + + for i, database in enumerate(databases): + if i != 0: + sys.stdout.write("\n") + self.show_dsn(database, options) + + def show_dsn(self, database, options): + dbinfo = settings.DATABASES.get(database) + quiet = options['quiet'] + dsn_style = options['style'] + + if dbinfo is None: + raise CommandError("Unknown database %s" % database) + + engine = dbinfo.get('ENGINE') + dbuser = dbinfo.get('USER') + dbpass = dbinfo.get('PASSWORD') + dbname = dbinfo.get('NAME') + dbhost = dbinfo.get('HOST') + dbport = dbinfo.get('PORT') + + dsn = [] + + if engine in SQLITE_ENGINES: + dsn.append('{}'.format(dbname)) + elif engine in MYSQL_ENGINES: + dsn.append(self._mysql(dbhost, dbport, dbname, dbuser, dbpass)) + elif engine in POSTGRESQL_ENGINES: + dsn.extend(self._postgresql( + dbhost, dbport, dbname, dbuser, dbpass, dsn_style=dsn_style)) + else: + dsn.append(self.style.ERROR('Unknown database, can''t generate DSN')) + + if not quiet: + sys.stdout.write(self.style.SQL_TABLE("DSN for database '%s' with engine '%s':\n" % (database, engine))) + + for output in dsn: + sys.stdout.write("{}\n".format(output)) + + def _mysql(self, dbhost, dbport, dbname, dbuser, dbpass): + dsnstr = 'host="{0}", db="{2}", user="{3}", passwd="{4}"' + + if dbport is not None: + dsnstr += ', port="{1}"' + + return dsnstr.format(dbhost, dbport, dbname, dbuser, dbpass) + + def _postgresql(self, dbhost, dbport, dbname, dbuser, dbpass, dsn_style=None): # noqa + """PostgreSQL psycopg2 driver accepts two syntaxes + + Plus a string for .pgpass file + """ + dsn = [] + + if dsn_style is None or dsn_style == 'all' or dsn_style == 'keyvalue': + dsnstr = "host='{0}' dbname='{2}' user='{3}' password='{4}'" + + if dbport is not None: + dsnstr += " port='{1}'" + + dsn.append(dsnstr.format( + dbhost, + dbport, + dbname, + dbuser, + dbpass, + )) + + if dsn_style in ('all', 'kwargs'): + dsnstr = "host='{0}', database='{2}', user='{3}', password='{4}'" + if dbport is not None: + dsnstr += ", port='{1}'" + + dsn.append(dsnstr.format( + dbhost, + dbport, + dbname, + dbuser, + dbpass, + )) + + if dsn_style in ('all', 'uri'): + dsnstr = "postgresql://{user}:{password}@{host}/{name}" + + dsn.append(dsnstr.format( + host="{host}:{port}".format(host=dbhost, port=dbport) if dbport else dbhost, # noqa + name=dbname, + user=dbuser, + password=dbpass, + )) + + if dsn_style in ('all', 'pgpass'): + dsn.append(':'.join(map(str, filter(None, [dbhost, dbport, dbname, dbuser, dbpass])))) + + return dsn diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/sync_s3.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/sync_s3.py new file mode 100644 index 0000000..251749e --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/sync_s3.py @@ -0,0 +1,400 @@ +# -*- coding: utf-8 -*- +""" +Sync Media to S3 +================ + +Django command that scans all files in your settings.MEDIA_ROOT and +settings.STATIC_ROOT folders and uploads them to S3 with the same directory +structure. + +This command can optionally do the following but it is off by default: +* gzip compress any CSS and Javascript files it finds and adds the appropriate + 'Content-Encoding' header. +* set a far future 'Expires' header for optimal caching. +* upload only media or static files. +* use any other provider compatible with Amazon S3. +* set other than 'public-read' ACL. + +Note: This script requires the Python boto library and valid Amazon Web +Services API keys. + +Required settings.py variables: +AWS_ACCESS_KEY_ID = '' +AWS_SECRET_ACCESS_KEY = '' +AWS_BUCKET_NAME = '' + +When you call this command with the `--renamegzip` param, it will add +the '.gz' extension to the file name. But Safari just doesn't recognize +'.gz' files and your site won't work on it! To fix this problem, you can +set any other extension (like .jgz) in the `SYNC_S3_RENAME_GZIP_EXT` +variable. + +Command options are: + -p PREFIX, --prefix=PREFIX + The prefix to prepend to the path on S3. + --gzip Enables gzipping CSS and Javascript files. + --expires Enables setting a far future expires header. + --force Skip the file mtime check to force upload of all + files. + --filter-list Override default directory and file exclusion + filters. (enter as comma separated line) + --renamegzip Enables renaming of gzipped files by appending '.gz'. + to the original file name. This way your original + assets will not be replaced by the gzipped ones. + You can change the extension setting the + `SYNC_S3_RENAME_GZIP_EXT` var in your settings.py + file. + --invalidate Invalidates the objects in CloudFront after uploading + stuff to s3. + --media-only Only MEDIA_ROOT files will be uploaded to S3. + --static-only Only STATIC_ROOT files will be uploaded to S3. + --s3host Override default s3 host. + --acl Override default ACL settings ('public-read' if + settings.AWS_DEFAULT_ACL is not defined). + +TODO: + * Use fnmatch (or regex) to allow more complex FILTER_LIST rules. + +""" +import datetime +import email +import gzip +import mimetypes +import os +import time +from typing import List # NOQA + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from io import StringIO + +from django_extensions.management.utils import signalcommand + + +try: + import boto +except ImportError: + HAS_BOTO = False +else: + HAS_BOTO = True + + +class Command(BaseCommand): + # Extra variables to avoid passing these around + AWS_ACCESS_KEY_ID = '' + AWS_SECRET_ACCESS_KEY = '' + AWS_BUCKET_NAME = '' + AWS_CLOUDFRONT_DISTRIBUTION = '' + SYNC_S3_RENAME_GZIP_EXT = '' + + DIRECTORIES = '' + FILTER_LIST = ['.DS_Store', '.svn', '.hg', '.git', 'Thumbs.db'] + GZIP_CONTENT_TYPES = ( + 'text/css', + 'application/javascript', + 'application/x-javascript', + 'text/javascript' + ) + + uploaded_files = [] # type: List[str] + upload_count = 0 + skip_count = 0 + + help = 'Syncs the complete MEDIA_ROOT structure and files to S3 into the given bucket name.' + args = 'bucket_name' + + can_import_settings = True + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '-p', '--prefix', + dest='prefix', + default=getattr(settings, 'SYNC_S3_PREFIX', ''), + help="The prefix to prepend to the path on S3." + ) + parser.add_argument( + '-d', '--dir', + dest='dir', + help="Custom static root directory to use" + ) + parser.add_argument( + '--s3host', + dest='s3host', + default=getattr(settings, 'AWS_S3_HOST', ''), + help="The s3 host (enables connecting to other providers/regions)" + ) + parser.add_argument( + '--acl', + dest='acl', + default=getattr(settings, 'AWS_DEFAULT_ACL', 'public-read'), + help="Enables to override default acl (public-read)." + ) + parser.add_argument( + '--gzip', + action='store_true', dest='gzip', default=False, + help="Enables gzipping CSS and Javascript files." + ) + parser.add_argument( + '--renamegzip', + action='store_true', dest='renamegzip', default=False, + help="Enables renaming of gzipped assets to have '.gz' appended to the filename." + ) + parser.add_argument( + '--expires', + action='store_true', dest='expires', default=False, + help="Enables setting a far future expires header." + ) + parser.add_argument( + '--force', + action='store_true', dest='force', default=False, + help="Skip the file mtime check to force upload of all files." + ) + parser.add_argument( + '--filter-list', dest='filter_list', + action='store', default='', + help="Override default directory and file exclusion filters. (enter as comma seperated line)" + ) + parser.add_argument( + '--invalidate', dest='invalidate', default=False, + action='store_true', + help='Invalidates the associated objects in CloudFront' + ) + parser.add_argument( + '--media-only', dest='media_only', default='', + action='store_true', + help="Only MEDIA_ROOT files will be uploaded to S3" + ) + parser.add_argument( + '--static-only', dest='static_only', default='', + action='store_true', + help="Only STATIC_ROOT files will be uploaded to S3" + ) + + @signalcommand + def handle(self, *args, **options): + if not HAS_BOTO: + raise CommandError("Please install the 'boto' Python library. ($ pip install boto)") + + # Check for AWS keys in settings + if not hasattr(settings, 'AWS_ACCESS_KEY_ID') or not hasattr(settings, 'AWS_SECRET_ACCESS_KEY'): + raise CommandError('Missing AWS keys from settings file. Please supply both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.') + else: + self.AWS_ACCESS_KEY_ID = settings.AWS_ACCESS_KEY_ID + self.AWS_SECRET_ACCESS_KEY = settings.AWS_SECRET_ACCESS_KEY + + if not hasattr(settings, 'AWS_BUCKET_NAME'): + raise CommandError('Missing bucket name from settings file. Please add the AWS_BUCKET_NAME to your settings file.') + else: + if not settings.AWS_BUCKET_NAME: + raise CommandError('AWS_BUCKET_NAME cannot be empty.') + self.AWS_BUCKET_NAME = settings.AWS_BUCKET_NAME + + if not hasattr(settings, 'MEDIA_ROOT'): + raise CommandError('MEDIA_ROOT must be set in your settings.') + else: + if not settings.MEDIA_ROOT: + raise CommandError('MEDIA_ROOT must be set in your settings.') + + self.AWS_CLOUDFRONT_DISTRIBUTION = getattr(settings, 'AWS_CLOUDFRONT_DISTRIBUTION', '') + + self.SYNC_S3_RENAME_GZIP_EXT = \ + getattr(settings, 'SYNC_S3_RENAME_GZIP_EXT', '.gz') + + self.verbosity = options["verbosity"] + self.prefix = options['prefix'] + self.do_gzip = options['gzip'] + self.rename_gzip = options['renamegzip'] + self.do_expires = options['expires'] + self.do_force = options['force'] + self.invalidate = options['invalidate'] + self.DIRECTORIES = options['dir'] + self.s3host = options['s3host'] + self.default_acl = options['acl'] + self.FILTER_LIST = getattr(settings, 'FILTER_LIST', self.FILTER_LIST) + filter_list = options['filter_list'] + if filter_list: + # command line option overrides default filter_list and + # settings.filter_list + self.FILTER_LIST = filter_list.split(',') + + self.media_only = options['media_only'] + self.static_only = options['static_only'] + # Get directories + if self.media_only and self.static_only: + raise CommandError("Can't use --media-only and --static-only together. Better not use anything...") + elif self.media_only: + self.DIRECTORIES = [settings.MEDIA_ROOT] + elif self.static_only: + self.DIRECTORIES = [settings.STATIC_ROOT] + elif self.DIRECTORIES: + self.DIRECTORIES = [self.DIRECTORIES] + else: + self.DIRECTORIES = [settings.MEDIA_ROOT, settings.STATIC_ROOT] + + # Now call the syncing method to walk the MEDIA_ROOT directory and + # upload all files found. + self.sync_s3() + + # Sending the invalidation request to CloudFront if the user + # requested this action + if self.invalidate: + self.invalidate_objects_cf() + + print("") + print("%d files uploaded." % self.upload_count) + print("%d files skipped." % self.skip_count) + + def open_cf(self): + """Return an open connection to CloudFront""" + return boto.connect_cloudfront( + self.AWS_ACCESS_KEY_ID, self.AWS_SECRET_ACCESS_KEY) + + def invalidate_objects_cf(self): + """Split the invalidation request in groups of 1000 objects""" + if not self.AWS_CLOUDFRONT_DISTRIBUTION: + raise CommandError( + 'An object invalidation was requested but the variable ' + 'AWS_CLOUDFRONT_DISTRIBUTION is not present in your settings.') + + # We can't send more than 1000 objects in the same invalidation + # request. + chunk = 1000 + + # Connecting to CloudFront + conn = self.open_cf() + + # Splitting the object list + objs = self.uploaded_files + chunks = [objs[i:i + chunk] for i in range(0, len(objs), chunk)] + + # Invalidation requests + for paths in chunks: + conn.create_invalidation_request( + self.AWS_CLOUDFRONT_DISTRIBUTION, paths) + + def sync_s3(self): + """Walk the media/static directories and syncs files to S3""" + bucket, key = self.open_s3() + for directory in self.DIRECTORIES: + for root, dirs, files in os.walk(directory): + self.upload_s3((bucket, key, self.AWS_BUCKET_NAME, directory), root, files, dirs) + + def compress_string(self, s): + """Gzip a given string.""" + zbuf = StringIO() + zfile = gzip.GzipFile(mode='wb', compresslevel=6, fileobj=zbuf) + zfile.write(s) + zfile.close() + return zbuf.getvalue() + + def get_s3connection_kwargs(self): + """Return connection kwargs as a dict""" + kwargs = {} + if self.s3host: + kwargs['host'] = self.s3host + return kwargs + + def open_s3(self): + """Open connection to S3 returning bucket and key""" + conn = boto.connect_s3( + self.AWS_ACCESS_KEY_ID, + self.AWS_SECRET_ACCESS_KEY, + **self.get_s3connection_kwargs()) + try: + bucket = conn.get_bucket(self.AWS_BUCKET_NAME) + except boto.exception.S3ResponseError: + bucket = conn.create_bucket(self.AWS_BUCKET_NAME) + return bucket, boto.s3.key.Key(bucket) + + def upload_s3(self, arg, dirname, names, dirs): + bucket, key, bucket_name, root_dir = arg + + # Skip directories we don't want to sync + if os.path.basename(dirname) in self.FILTER_LIST and os.path.dirname(dirname) in self.DIRECTORIES: + # prevent walk from processing subfiles/subdirs below the ignored one + del dirs[:] + return + + # Later we assume the MEDIA_ROOT ends with a trailing slash + if not root_dir.endswith(os.path.sep): + root_dir = root_dir + os.path.sep + + for file in names: + headers = {} + + if file in self.FILTER_LIST: + continue # Skip files we don't want to sync + + filename = os.path.join(dirname, file) + if os.path.isdir(filename): + continue # Don't try to upload directories + + file_key = filename[len(root_dir):] + if self.prefix: + file_key = '%s/%s' % (self.prefix, file_key) + + # Check if file on S3 is older than local file, if so, upload + if not self.do_force: + s3_key = bucket.get_key(file_key) + if s3_key: + s3_datetime = datetime.datetime(*time.strptime( + s3_key.last_modified, '%a, %d %b %Y %H:%M:%S %Z')[0:6]) + local_datetime = datetime.datetime.utcfromtimestamp( + os.stat(filename).st_mtime) + if local_datetime < s3_datetime: + self.skip_count += 1 + if self.verbosity > 1: + print("File %s hasn't been modified since last being uploaded" % file_key) + continue + + # File is newer, let's process and upload + if self.verbosity > 0: + print("Uploading %s..." % file_key) + + content_type = mimetypes.guess_type(filename)[0] + if content_type: + headers['Content-Type'] = content_type + else: + headers['Content-Type'] = 'application/octet-stream' + + file_obj = open(filename, 'rb') + file_size = os.fstat(file_obj.fileno()).st_size + filedata = file_obj.read() + if self.do_gzip: + # Gzip only if file is large enough (>1K is recommended) + # and only if file is a common text type (not a binary file) + if file_size > 1024 and content_type in self.GZIP_CONTENT_TYPES: + filedata = self.compress_string(filedata) + if self.rename_gzip: + # If rename_gzip is True, then rename the file + # by appending an extension (like '.gz)' to + # original filename. + file_key = '%s.%s' % ( + file_key, self.SYNC_S3_RENAME_GZIP_EXT) + headers['Content-Encoding'] = 'gzip' + if self.verbosity > 1: + print("\tgzipped: %dk to %dk" % (file_size / 1024, len(filedata) / 1024)) + if self.do_expires: + # HTTP/1.0 + headers['Expires'] = '%s GMT' % (email.Utils.formatdate(time.mktime((datetime.datetime.now() + datetime.timedelta(days=365 * 2)).timetuple()))) + # HTTP/1.1 + headers['Cache-Control'] = 'max-age %d' % (3600 * 24 * 365 * 2) + if self.verbosity > 1: + print("\texpires: %s" % headers['Expires']) + print("\tcache-control: %s" % headers['Cache-Control']) + + try: + key.name = file_key + key.set_contents_from_string(filedata, headers, replace=True, + policy=self.default_acl) + except boto.exception.S3CreateError as e: + print("Failed: %s" % e) + except Exception as e: + print(e) + raise + else: + self.upload_count += 1 + self.uploaded_files.append(file_key) + + file_obj.close() diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/syncdata.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/syncdata.py new file mode 100644 index 0000000..c05806b --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/syncdata.py @@ -0,0 +1,224 @@ +# -*- coding: utf-8 -*- +""" +SyncData +======== + +Django command similar to 'loaddata' but also deletes. +After 'syncdata' has run, the database will have the same data as the fixture - anything +missing will of been added, anything different will of been updated, +and anything extra will of been deleted. +""" + +import os + +from django.apps import apps +from django.conf import settings +from django.core import serializers +from django.core.management.base import BaseCommand, CommandError +from django.core.management.color import no_style +from django.db import DEFAULT_DB_ALIAS, connections, transaction +from django.template.defaultfilters import pluralize + +from django_extensions.management.utils import signalcommand + + +def humanize(dirname): + return "'%s'" % dirname if dirname else 'absolute path' + + +class SyncDataError(Exception): + pass + + +class Command(BaseCommand): + """ syncdata command """ + + help = 'Makes the current database have the same data as the fixture(s), no more, no less.' + args = "fixture [fixture ...]" + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--skip-remove', action='store_false', dest='remove', default=True, + help='Avoid remove any object from db', + ) + parser.add_argument( + '--remove-before', action='store_true', dest='remove_before', default=False, + help='Remove existing objects before inserting and updating new ones', + ) + parser.add_argument( + '--database', default=DEFAULT_DB_ALIAS, + help='Nominates a specific database to load fixtures into. Defaults to the "default" database.', + ) + parser.add_argument( + 'fixture_labels', nargs='?', type=str, + help='Specify the fixture label (comma separated)', + ) + + def remove_objects_not_in(self, objects_to_keep, verbosity): + """ + Delete all the objects in the database that are not in objects_to_keep. + - objects_to_keep: A map where the keys are classes, and the values are a + set of the objects of that class we should keep. + """ + for class_ in objects_to_keep.keys(): + current = class_.objects.all() + current_ids = set(x.pk for x in current) + keep_ids = set(x.pk for x in objects_to_keep[class_]) + + remove_these_ones = current_ids.difference(keep_ids) + if remove_these_ones: + for obj in current: + if obj.pk in remove_these_ones: + obj.delete() + if verbosity >= 2: + print("Deleted object: %s" % str(obj)) + + if verbosity > 0 and remove_these_ones: + num_deleted = len(remove_these_ones) + if num_deleted > 1: + type_deleted = str(class_._meta.verbose_name_plural) + else: + type_deleted = str(class_._meta.verbose_name) + + print("Deleted %s %s" % (str(num_deleted), type_deleted)) + + @signalcommand + def handle(self, *args, **options): + self.style = no_style() + self.using = options['database'] + fixture_labels = options['fixture_labels'].split(',') if options['fixture_labels'] else () + try: + with transaction.atomic(): + self.syncdata(fixture_labels, options) + except SyncDataError as exc: + raise CommandError(exc) + finally: + # Close the DB connection -- unless we're still in a transaction. This + # is required as a workaround for an edge case in MySQL: if the same + # connection is used to create tables, load data, and query, the query + # can return incorrect results. See Django #7572, MySQL #37735. + if transaction.get_autocommit(self.using): + connections[self.using].close() + + def syncdata(self, fixture_labels, options): + verbosity = options['verbosity'] + show_traceback = options['traceback'] + + # Keep a count of the installed objects and fixtures + fixture_count = 0 + object_count = 0 + objects_per_fixture = [] + models = set() + + # Get a cursor (even though we don't need one yet). This has + # the side effect of initializing the test database (if + # it isn't already initialized). + cursor = connections[self.using].cursor() + + app_modules = [app.module for app in apps.get_app_configs()] + app_fixtures = [os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in app_modules] + for fixture_label in fixture_labels: + parts = fixture_label.split('.') + if len(parts) == 1: + fixture_name = fixture_label + formats = serializers.get_public_serializer_formats() + else: + fixture_name, format_ = '.'.join(parts[:-1]), parts[-1] + if format_ in serializers.get_public_serializer_formats(): + formats = [format_] + else: + formats = [] + + if formats: + if verbosity > 1: + print("Loading '%s' fixtures..." % fixture_name) + else: + raise SyncDataError("Problem installing fixture '%s': %s is not a known serialization format." % (fixture_name, format_)) + + if os.path.isabs(fixture_name): + fixture_dirs = [fixture_name] + else: + fixture_dirs = app_fixtures + list(settings.FIXTURE_DIRS) + [''] + + for fixture_dir in fixture_dirs: + if verbosity > 1: + print("Checking %s for fixtures..." % humanize(fixture_dir)) + + label_found = False + for format_ in formats: + if verbosity > 1: + print("Trying %s for %s fixture '%s'..." % (humanize(fixture_dir), format_, fixture_name)) + try: + full_path = os.path.join(fixture_dir, '.'.join([fixture_name, format_])) + fixture = open(full_path, 'r') + if label_found: + fixture.close() + raise SyncDataError("Multiple fixtures named '%s' in %s. Aborting." % (fixture_name, humanize(fixture_dir))) + else: + fixture_count += 1 + objects_per_fixture.append(0) + if verbosity > 0: + print("Installing %s fixture '%s' from %s." % (format_, fixture_name, humanize(fixture_dir))) + try: + objects_to_keep = {} + objects = list(serializers.deserialize(format_, fixture)) + for obj in objects: + class_ = obj.object.__class__ + if class_ not in objects_to_keep: + objects_to_keep[class_] = set() + objects_to_keep[class_].add(obj.object) + + if options['remove'] and options['remove_before']: + self.remove_objects_not_in(objects_to_keep, verbosity) + + for obj in objects: + object_count += 1 + objects_per_fixture[-1] += 1 + models.add(obj.object.__class__) + obj.save() + + if options['remove'] and not options['remove_before']: + self.remove_objects_not_in(objects_to_keep, verbosity) + + label_found = True + except (SystemExit, KeyboardInterrupt): + raise + except Exception: + import traceback + fixture.close() + if show_traceback: + traceback.print_exc() + raise SyncDataError("Problem installing fixture '%s': %s\n" % (full_path, traceback.format_exc())) + + fixture.close() + except SyncDataError as e: + raise e + except Exception: + if verbosity > 1: + print("No %s fixture '%s' in %s." % (format_, fixture_name, humanize(fixture_dir))) + + # If any of the fixtures we loaded contain 0 objects, assume that an + # error was encountered during fixture loading. + if 0 in objects_per_fixture: + raise SyncDataError("No fixture data found for '%s'. (File format may be invalid.)" % fixture_name) + + # If we found even one object in a fixture, we need to reset the + # database sequences. + if object_count > 0: + sequence_sql = connections[self.using].ops.sequence_reset_sql(self.style, models) + if sequence_sql: + if verbosity > 1: + print("Resetting sequences") + for line in sequence_sql: + cursor.execute(line) + + if object_count == 0: + if verbosity > 1: + print("No fixtures found.") + else: + if verbosity > 0: + print("Installed %d object%s from %d fixture%s" % ( + object_count, pluralize(object_count), + fixture_count, pluralize(fixture_count) + )) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/unreferenced_files.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/unreferenced_files.py new file mode 100644 index 0000000..abedf7d --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/unreferenced_files.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +import os +from collections import defaultdict + +from django.apps import apps +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from django.db import models + +from django_extensions.management.utils import signalcommand + + +class Command(BaseCommand): + help = "Prints a list of all files in MEDIA_ROOT that are not referenced in the database." + + @signalcommand + def handle(self, *args, **options): + if not getattr(settings, 'MEDIA_ROOT'): + raise CommandError("MEDIA_ROOT is not set, nothing to do") + + # Get a list of all files under MEDIA_ROOT + media = set() + for root, dirs, files in os.walk(settings.MEDIA_ROOT): + for f in files: + media.add(os.path.abspath(os.path.join(root, f))) + + # Get list of all fields (value) for each model (key) + # that is a FileField or subclass of a FileField + model_dict = defaultdict(list) + for model in apps.get_models(): + for field in model._meta.fields: + if issubclass(field.__class__, models.FileField): + model_dict[model].append(field) + + # Get a list of all files referenced in the database + referenced = set() + for model in model_dict: + all = model.objects.all().iterator() + for object in all: + for field in model_dict[model]: + target_file = getattr(object, field.name) + if target_file: + referenced.add(os.path.abspath(target_file.path)) + + # Print each file in MEDIA_ROOT that is not referenced in the database + not_referenced = media - referenced + for f in not_referenced: + print(f) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/update_permissions.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/update_permissions.py new file mode 100644 index 0000000..6b0e4cc --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/update_permissions.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +from django import VERSION as DJANGO_VERSION +from django.apps import apps as django_apps +from django.contrib.auth.management import create_permissions, _get_all_permissions +from django.contrib.auth.models import Permission +from django.contrib.contenttypes.models import ContentType +from django.core.management.base import BaseCommand + +from django_extensions.management.utils import signalcommand + + +class Command(BaseCommand): + help = 'reloads permissions for specified apps, or all apps if no args are specified' + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument('--apps', dest='apps', help='Reload permissions only for apps (comma separated)') + parser.add_argument('--create-only', action='store_true', default=False, help='Only create missing permissions') + parser.add_argument('--update-only', action='store_true', default=False, help='Only update permissions') + + @signalcommand + def handle(self, *args, **options): + if options['apps']: + app_names = options['apps'].split(',') + apps = [django_apps.get_app_config(x) for x in app_names] + else: + apps = django_apps.get_app_configs() + + if options['create_only']: + do_create, do_update = True, False + elif options['update_only']: + do_create, do_update = False, True + else: + do_create, do_update = True, True + + for app in apps: + if DJANGO_VERSION < (2, 2): + # see https://github.com/django/django/commit/bec651a427fc032d9115d30c8c5d0e702d754f6c + # Ensure that contenttypes are created for this app. Needed if + # 'django.contrib.auth' is in INSTALLED_APPS before + # 'django.contrib.contenttypes'. + from django.contrib.contenttypes.management import create_contenttypes + create_contenttypes(app, verbosity=options['verbosity']) + + if do_create: + # create permissions if they do not exist + create_permissions(app, options['verbosity']) + + if do_update: + # update permission name's if changed + for model in app.get_models(): + content_type = ContentType.objects.get_for_model(model) + for codename, name in _get_all_permissions(model._meta): + try: + permission = Permission.objects.get(codename=codename, content_type=content_type) + except Permission.DoesNotExist: + continue + if permission.name != name: + old_str = str(permission) + permission.name = name + if options['verbosity'] >= 2: + self.stdout.write(self.style.SUCCESS("Update permission '%s' to '%s'" % (old_str, permission))) + permission.save() diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/commands/validate_templates.py b/venv/lib/python3.7/site-packages/django_extensions/management/commands/validate_templates.py new file mode 100644 index 0000000..1810298 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/commands/validate_templates.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +import os +import fnmatch + +from django.apps import apps +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from django.core.management.color import color_style +from django.template.loader import get_template + +from django_extensions.compat import get_template_setting +from django_extensions.management.utils import signalcommand + + +# +# TODO: Render the template with fake request object ? +# + + +class Command(BaseCommand): + args = '' + help = "Validate templates on syntax and compile errors" + ignores = set([ + ".DS_Store", + "*.swp", + "*~", + ]) + + def add_arguments(self, parser): + super().add_arguments(parser) + parser.add_argument( + '--no-apps', action='store_true', dest='no_apps', + default=False, help="Do not automatically include apps.") + parser.add_argument( + '--break', '-b', action='store_true', dest='break', + default=False, help="Break on first error.") + parser.add_argument( + '--include', '-i', action='append', dest='includes', + default=[], help="Append these paths to TEMPLATE DIRS") + parser.add_argument( + '--ignore-app', action='append', dest='ignore_apps', + default=[], help="Ignore these apps") + + def ignore_filename(self, filename): + filename = os.path.basename(filename) + for ignore_pattern in self.ignores: + if fnmatch.fnmatch(filename, ignore_pattern): + return True + return False + + @signalcommand + def handle(self, *args, **options): + if hasattr(settings, 'VALIDATE_TEMPLATES_IGNORES'): + self.ignores = getattr(settings, 'VALIDATE_TEMPLATES_IGNORES') + + style = color_style() + template_dirs = set(get_template_setting('DIRS', [])) + template_dirs |= set(options['includes']) + template_dirs |= set(getattr(settings, 'VALIDATE_TEMPLATES_EXTRA_TEMPLATE_DIRS', [])) + + if not options['no_apps']: + ignore_apps = options['ignore_apps'] + if not ignore_apps and hasattr(settings, 'VALIDATE_TEMPLATES_IGNORE_APPS'): + ignore_apps = getattr(settings, 'VALIDATE_TEMPLATES_IGNORE_APPS') + for app in apps.get_app_configs(): + if app.name in ignore_apps: + continue + app_template_dir = os.path.join(app.path, 'templates') + if os.path.isdir(app_template_dir): + template_dirs.add(app_template_dir) + + settings.TEMPLATES[0]['DIRS'] = list(template_dirs) + settings.TEMPLATE_DEBUG = True + verbosity = options["verbosity"] + errors = 0 + + for template_dir in template_dirs: + for root, dirs, filenames in os.walk(template_dir): + for filename in filenames: + if self.ignore_filename(filename): + continue + + filepath = os.path.join(root, filename) + if verbosity > 1: + self.stdout.write(filepath) + try: + get_template(filepath) + except Exception as e: + errors += 1 + self.stdout.write("%s: %s" % (filepath, style.ERROR("%s %s" % (e.__class__.__name__, str(e))))) + if errors and options['break']: + raise CommandError("Errors found") + + if errors: + raise CommandError("%s errors found" % errors) + self.stdout.write("%s errors found" % errors) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/debug_cursor.py b/venv/lib/python3.7/site-packages/django_extensions/management/debug_cursor.py new file mode 100644 index 0000000..0ca584b --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/debug_cursor.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +import time +import traceback +from contextlib import contextmanager + +import django +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured +from django.db.backends import utils + + +@contextmanager +def monkey_patch_cursordebugwrapper(print_sql=None, print_sql_location=False, truncate=None, logger=print, confprefix="DJANGO_EXTENSIONS"): + if not print_sql: + yield + else: + truncate = getattr(settings, '%s_PRINT_SQL_TRUNCATE' % confprefix, 1000) + + # Code orginally from http://gist.github.com/118990 + sqlparse = None + if getattr(settings, '%s_SQLPARSE_ENABLED' % confprefix, True): + try: + import sqlparse + + sqlparse_format_kwargs_defaults = dict( + reindent_aligned=True, + truncate_strings=500, + ) + sqlparse_format_kwargs = getattr(settings, '%s_SQLPARSE_FORMAT_KWARGS' % confprefix, sqlparse_format_kwargs_defaults) + except ImportError: + sqlparse = None + + pygments = None + if getattr(settings, '%s_PYGMENTS_ENABLED' % confprefix, True): + try: + import pygments.lexers + import pygments.formatters + + pygments_formatter = getattr(settings, '%s_PYGMENTS_FORMATTER' % confprefix, pygments.formatters.TerminalFormatter) + pygments_formatter_kwargs = getattr(settings, '%s_PYGMENTS_FORMATTER_KWARGS' % confprefix, {}) + except ImportError: + pass + + class PrintQueryWrapperMixin: + def execute(self, sql, params=()): + starttime = time.time() + try: + return utils.CursorWrapper.execute(self, sql, params) + finally: + execution_time = time.time() - starttime + raw_sql = self.db.ops.last_executed_query(self.cursor, sql, params) + if truncate: + raw_sql = raw_sql[:truncate] + + if sqlparse: + raw_sql = sqlparse.format(raw_sql, **sqlparse_format_kwargs) + + if pygments: + raw_sql = pygments.highlight( + raw_sql, + pygments.lexers.get_lexer_by_name("sql"), + pygments_formatter(**pygments_formatter_kwargs), + ) + + logger(raw_sql) + logger("Execution time: %.6fs [Database: %s]" % (execution_time, self.db.alias)) + if print_sql_location: + logger("Location of SQL Call:") + logger(''.join(traceback.format_stack())) + + _CursorDebugWrapper = utils.CursorDebugWrapper + + class PrintCursorQueryWrapper(PrintQueryWrapperMixin, _CursorDebugWrapper): + pass + + try: + from django.db import connections + _force_debug_cursor = {} + for connection_name in connections: + _force_debug_cursor[connection_name] = connections[connection_name].force_debug_cursor + except Exception: + connections = None + + utils.CursorDebugWrapper = PrintCursorQueryWrapper + + postgresql_base = None + if django.VERSION >= (3, 0): + try: + from django.db.backends.postgresql import base as postgresql_base + _PostgreSQLCursorDebugWrapper = postgresql_base.CursorDebugWrapper + + class PostgreSQLPrintCursorDebugWrapper(PrintQueryWrapperMixin, _PostgreSQLCursorDebugWrapper): + pass + except (ImproperlyConfigured, TypeError): + postgresql_base = None + + if postgresql_base: + postgresql_base.CursorDebugWrapper = PostgreSQLPrintCursorDebugWrapper + + if connections: + for connection_name in connections: + connections[connection_name].force_debug_cursor = True + + yield + + utils.CursorDebugWrapper = _CursorDebugWrapper + + if postgresql_base: + postgresql_base.CursorDebugWrapper = _PostgreSQLCursorDebugWrapper + + if connections: + for connection_name in connections: + connections[connection_name].force_debug_cursor = _force_debug_cursor[connection_name] diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/email_notifications.py b/venv/lib/python3.7/site-packages/django_extensions/management/email_notifications.py new file mode 100644 index 0000000..2c360cb --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/email_notifications.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- +import sys +import traceback + +from django.conf import settings +from django.core.mail import send_mail +from django.core.management import BaseCommand + + +class EmailNotificationCommand(BaseCommand): + """ + A BaseCommand subclass which adds sending email fuctionality. + + Subclasses will have an extra command line option ``--email-notification`` + and will be able to send emails by calling ``send_email_notification()`` + if SMTP host and port are specified in settings. The handling of the + command line option is left to the management command implementation. + Configuration is done in settings.EMAIL_NOTIFICATIONS dict. + + Configuration example:: + + EMAIL_NOTIFICATIONS = { + 'scripts.my_script': { + 'subject': 'my_script subject', + 'body': 'my_script body', + 'from_email': 'from_email@example.com', + 'recipients': ('recipient0@example.com',), + 'no_admins': False, + 'no_traceback': False, + 'notification_level': 0, + 'fail_silently': False + }, + 'scripts.another_script': { + ... + }, + ... + } + + Configuration explained: + subject: Email subject. + body: Email body. + from_email: Email from address. + recipients: Sequence of email recipient addresses. + no_admins: When True do not include ADMINS to recipients. + no_traceback: When True do not include traceback to email body. + notification_level: 0: send email on fail, 1: send email always. + fail_silently: Parameter passed to django's send_mail(). + """ + + def add_arguments(self, parser): + parser.add_argument('--email-notifications', + action='store_true', + default=False, + dest='email_notifications', + help='Send email notifications for command.') + parser.add_argument('--email-exception', + action='store_true', + default=False, + dest='email_exception', + help='Send email for command exceptions.') + + def run_from_argv(self, argv): + """Overriden in order to access the command line arguments.""" + self.argv_string = ' '.join(argv) + super().run_from_argv(argv) + + def execute(self, *args, **options): + """ + Overriden in order to send emails on unhandled exception. + + If an unhandled exception in ``def handle(self, *args, **options)`` + occurs and `--email-exception` is set or `self.email_exception` is + set to True send an email to ADMINS with the traceback and then + reraise the exception. + """ + try: + super().execute(*args, **options) + except Exception: + if options['email_exception'] or getattr(self, 'email_exception', False): + self.send_email_notification(include_traceback=True) + raise + + def send_email_notification(self, notification_id=None, include_traceback=False, verbosity=1): + """ + Send email notifications. + + Reads settings from settings.EMAIL_NOTIFICATIONS dict, if available, + using ``notification_id`` as a key or else provides reasonable + defaults. + """ + # Load email notification settings if available + if notification_id is not None: + try: + email_settings = settings.EMAIL_NOTIFICATIONS.get(notification_id, {}) + except AttributeError: + email_settings = {} + else: + email_settings = {} + + # Exit if no traceback found and not in 'notify always' mode + if not include_traceback and not email_settings.get('notification_level', 0): + print(self.style.ERROR("Exiting, not in 'notify always' mode.")) + return + + # Set email fields. + subject = email_settings.get('subject', "Django extensions email notification.") + + command_name = self.__module__.split('.')[-1] + + body = email_settings.get( + 'body', + "Reporting execution of command: '%s'" % command_name + ) + + # Include traceback + if include_traceback and not email_settings.get('no_traceback', False): + try: + exc_type, exc_value, exc_traceback = sys.exc_info() + trb = ''.join(traceback.format_tb(exc_traceback)) + body += "\n\nTraceback:\n\n%s\n" % trb + finally: + del exc_traceback + + # Set from address + from_email = email_settings.get('from_email', settings.DEFAULT_FROM_EMAIL) + + # Calculate recipients + recipients = list(email_settings.get('recipients', [])) + + if not email_settings.get('no_admins', False): + recipients.extend(settings.ADMINS) + + if not recipients: + if verbosity > 0: + print(self.style.ERROR("No email recipients available.")) + return + + # Send email... + send_mail(subject, body, from_email, recipients, + fail_silently=email_settings.get('fail_silently', True)) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/jobs.py b/venv/lib/python3.7/site-packages/django_extensions/management/jobs.py new file mode 100644 index 0000000..1c6cdb4 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/jobs.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +import os +import sys +from imp import find_module +from typing import Optional # NOQA +from django.apps import apps + +_jobs = None + + +def noneimplementation(meth): + return None + + +class JobError(Exception): + pass + + +class BaseJob: + help = "undefined job description." + when = None # type: Optional[str] + + def execute(self): + raise NotImplementedError("Job needs to implement the execute method") + + +class MinutelyJob(BaseJob): + when = "minutely" + + +class QuarterHourlyJob(BaseJob): + when = "quarter_hourly" + + +class HourlyJob(BaseJob): + when = "hourly" + + +class DailyJob(BaseJob): + when = "daily" + + +class WeeklyJob(BaseJob): + when = "weekly" + + +class MonthlyJob(BaseJob): + when = "monthly" + + +class YearlyJob(BaseJob): + when = "yearly" + + +def my_import(name): + try: + imp = __import__(name) + except ImportError as err: + raise JobError("Failed to import %s with error %s" % (name, err)) + + mods = name.split('.') + if len(mods) > 1: + for mod in mods[1:]: + imp = getattr(imp, mod) + return imp + + +def find_jobs(jobs_dir): + try: + return [f[:-3] for f in os.listdir(jobs_dir) if not f.startswith('_') and f.endswith(".py")] + except OSError: + return [] + + +def find_job_module(app_name, when=None): + parts = app_name.split('.') + parts.append('jobs') + if when: + parts.append(when) + parts.reverse() + path = None + while parts: + part = parts.pop() + f, path, descr = find_module(part, path and [path] or None) + return path + + +def import_job(app_name, name, when=None): + jobmodule = "%s.jobs.%s%s" % (app_name, when and "%s." % when or "", name) + job_mod = my_import(jobmodule) + # todo: more friendly message for AttributeError if job_mod does not exist + try: + job = job_mod.Job + except AttributeError: + raise JobError("Job module %s does not contain class instance named 'Job'" % jobmodule) + if when and not (job.when == when or job.when is None): + raise JobError("Job %s is not a %s job." % (jobmodule, when)) + return job + + +def get_jobs(when=None, only_scheduled=False): + """ + Return a dictionary mapping of job names together with their respective + application class. + """ + # FIXME: HACK: make sure the project dir is on the path when executed as ./manage.py + try: + cpath = os.path.dirname(os.path.realpath(sys.argv[0])) + ppath = os.path.dirname(cpath) + if ppath not in sys.path: + sys.path.append(ppath) + except Exception: + pass + _jobs = {} + + for app_name in [app.name for app in apps.get_app_configs()]: + scandirs = (None, 'minutely', 'quarter_hourly', 'hourly', 'daily', 'weekly', 'monthly', 'yearly') + if when: + scandirs = None, when + for subdir in scandirs: + try: + path = find_job_module(app_name, subdir) + for name in find_jobs(path): + if (app_name, name) in _jobs: + raise JobError("Duplicate job %s" % name) + job = import_job(app_name, name, subdir) + if only_scheduled and job.when is None: + # only include jobs which are scheduled + continue + if when and job.when != when: + # generic job not in same schedule + continue + _jobs[(app_name, name)] = job + except ImportError: + # No job module -- continue scanning + pass + + return _jobs + + +def get_job(app_name, job_name): + jobs = get_jobs() + if app_name: + return jobs[(app_name, job_name)] + else: + for a, j in jobs.keys(): + if j == job_name: + return jobs[(a, j)] + raise KeyError("Job not found: %s" % job_name) + + +def print_jobs(when=None, only_scheduled=False, show_when=True, show_appname=False, show_header=True): + jobmap = get_jobs(when, only_scheduled=only_scheduled) + print("Job List: %i jobs" % len(jobmap)) + jlist = sorted(jobmap.keys()) + if not jlist: + return + + appname_spacer = "%%-%is" % max(len(e[0]) for e in jlist) + name_spacer = "%%-%is" % max(len(e[1]) for e in jlist) + when_spacer = "%%-%is" % max(len(e.when) for e in jobmap.values() if e.when) + if show_header: + line = " " + if show_appname: + line += appname_spacer % "appname" + " - " + line += name_spacer % "jobname" + if show_when: + line += " - " + when_spacer % "when" + line += " - help" + print(line) + print("-" * 80) + + for app_name, job_name in jlist: + job = jobmap[(app_name, job_name)] + line = " " + if show_appname: + line += appname_spacer % app_name + " - " + line += name_spacer % job_name + if show_when: + line += " - " + when_spacer % (job.when and job.when or "") + line += " - " + job.help + print(line) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/modelviz.py b/venv/lib/python3.7/site-packages/django_extensions/management/modelviz.py new file mode 100644 index 0000000..62518da --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/modelviz.py @@ -0,0 +1,440 @@ +# -*- coding: utf-8 -*- +""" +modelviz.py - DOT file generator for Django Models + +Based on: + Django model to DOT (Graphviz) converter + by Antonio Cavedoni + Adapted to be used with django-extensions +""" + +import datetime +import os +import re + +from django.apps import apps +from django.db.models.fields.related import ( + ForeignKey, ManyToManyField, OneToOneField, RelatedField, +) +from django.contrib.contenttypes.fields import GenericRelation +from django.template import Context, Template, loader +from django.utils.encoding import force_str +from django.utils.safestring import mark_safe +from django.utils.translation import activate as activate_language + + +__version__ = "1.1" +__license__ = "Python" +__author__ = "Bas van Oostveen ", +__contributors__ = [ + "Antonio Cavedoni " + "Stefano J. Attardi ", + "limodou ", + "Carlo C8E Miron", + "Andre Campos ", + "Justin Findlay ", + "Alexander Houben ", + "Joern Hees ", + "Kevin Cherepski ", + "Jose Tomas Tocino ", + "Adam Dobrawy ", + "Mikkel Munch Mortensen ", + "Andrzej Bistram ", + "Daniel Lipsitt ", +] + + +def parse_file_or_list(arg): + if not arg: + return [] + if isinstance(arg, (list, tuple, set)): + return arg + if ',' not in arg and os.path.isfile(arg): + return [e.strip() for e in open(arg).readlines()] + return [e.strip() for e in arg.split(',')] + + +class ModelGraph: + def __init__(self, app_labels, **kwargs): + self.graphs = [] + self.cli_options = kwargs.get('cli_options', None) + self.disable_fields = kwargs.get('disable_fields', False) + self.disable_abstract_fields = kwargs.get('disable_abstract_fields', False) + self.include_models = parse_file_or_list( + kwargs.get('include_models', "") + ) + self.all_applications = kwargs.get('all_applications', False) + self.use_subgraph = kwargs.get('group_models', False) + self.verbose_names = kwargs.get('verbose_names', False) + self.inheritance = kwargs.get('inheritance', True) + self.relations_as_fields = kwargs.get("relations_as_fields", True) + self.sort_fields = kwargs.get("sort_fields", True) + self.language = kwargs.get('language', None) + if self.language is not None: + activate_language(self.language) + self.exclude_columns = parse_file_or_list( + kwargs.get('exclude_columns', "") + ) + self.exclude_models = parse_file_or_list( + kwargs.get('exclude_models', "") + ) + self.hide_edge_labels = kwargs.get('hide_edge_labels', False) + self.arrow_shape = kwargs.get("arrow_shape") + if self.all_applications: + self.app_labels = [app.label for app in apps.get_app_configs()] + else: + self.app_labels = app_labels + + def generate_graph_data(self): + self.process_apps() + + nodes = [] + for graph in self.graphs: + nodes.extend([e['name'] for e in graph['models']]) + + for graph in self.graphs: + for model in graph['models']: + for relation in model['relations']: + if relation is not None: + if relation['target'] in nodes: + relation['needs_node'] = False + + def get_graph_data(self, as_json=False): + now = datetime.datetime.now() + graph_data = { + 'created_at': now.strftime("%Y-%m-%d %H:%M"), + 'cli_options': self.cli_options, + 'disable_fields': self.disable_fields, + 'disable_abstract_fields': self.disable_abstract_fields, + 'use_subgraph': self.use_subgraph, + } + + if as_json: + # We need to remove the model and field class because it is not JSON serializable + graphs = [context.flatten() for context in self.graphs] + for context in graphs: + for model_data in context['models']: + model_data.pop('model') + for field_data in model_data['fields']: + field_data.pop('field') + graph_data['graphs'] = graphs + else: + graph_data['graphs'] = self.graphs + + return graph_data + + def add_attributes(self, field, abstract_fields): + if self.verbose_names and field.verbose_name: + label = force_str(field.verbose_name) + if label.islower(): + label = label.capitalize() + else: + label = field.name + + t = type(field).__name__ + if isinstance(field, (OneToOneField, ForeignKey)): + t += " ({0})".format(field.remote_field.field_name) + # TODO: ManyToManyField, GenericRelation + + return { + 'field': field, + 'name': field.name, + 'label': label, + 'type': t, + 'blank': field.blank, + 'abstract': field in abstract_fields, + 'relation': isinstance(field, RelatedField), + 'primary_key': field.primary_key, + } + + def add_relation(self, field, model, extras=""): + if self.verbose_names and field.verbose_name: + label = force_str(field.verbose_name) + if label.islower(): + label = label.capitalize() + else: + label = field.name + + # show related field name + if hasattr(field, 'related_query_name'): + related_query_name = field.related_query_name() + if self.verbose_names and related_query_name.islower(): + related_query_name = related_query_name.replace('_', ' ').capitalize() + label = u'{} ({})'.format(label, force_str(related_query_name)) + if self.hide_edge_labels: + label = '' + + # handle self-relationships and lazy-relationships + if isinstance(field.remote_field.model, str): + if field.remote_field.model == 'self': + target_model = field.model + else: + if '.' in field.remote_field.model: + app_label, model_name = field.remote_field.model.split('.', 1) + else: + app_label = field.model._meta.app_label + model_name = field.remote_field.model + target_model = apps.get_model(app_label, model_name) + else: + target_model = field.remote_field.model + + _rel = self.get_relation_context(target_model, field, label, extras) + + if _rel not in model['relations'] and self.use_model(_rel['target']): + return _rel + + def get_abstract_models(self, appmodels): + abstract_models = [] + for appmodel in appmodels: + abstract_models += [ + abstract_model for abstract_model in appmodel.__bases__ + if hasattr(abstract_model, '_meta') and abstract_model._meta.abstract + ] + abstract_models = list(set(abstract_models)) # remove duplicates + return abstract_models + + def get_app_context(self, app): + return Context({ + 'name': '"%s"' % app.name, + 'app_name': "%s" % app.name, + 'cluster_app_name': "cluster_%s" % app.name.replace(".", "_"), + 'models': [] + }) + + def get_appmodel_attributes(self, appmodel): + if self.relations_as_fields: + attributes = [field for field in appmodel._meta.local_fields] + else: + # Find all the 'real' attributes. Relations are depicted as graph edges instead of attributes + attributes = [field for field in appmodel._meta.local_fields if not + isinstance(field, RelatedField)] + return attributes + + def get_appmodel_abstracts(self, appmodel): + return [ + abstract_model.__name__ for abstract_model in appmodel.__bases__ + if hasattr(abstract_model, '_meta') and abstract_model._meta.abstract + ] + + def get_appmodel_context(self, appmodel, appmodel_abstracts): + context = { + 'model': appmodel, + 'app_name': appmodel.__module__.replace(".", "_"), + 'name': appmodel.__name__, + 'abstracts': appmodel_abstracts, + 'fields': [], + 'relations': [] + } + + if self.verbose_names and appmodel._meta.verbose_name: + context['label'] = force_str(appmodel._meta.verbose_name) + else: + context['label'] = context['name'] + + return context + + def get_bases_abstract_fields(self, c): + _abstract_fields = [] + for e in c.__bases__: + if hasattr(e, '_meta') and e._meta.abstract: + _abstract_fields.extend(e._meta.fields) + _abstract_fields.extend(self.get_bases_abstract_fields(e)) + return _abstract_fields + + def get_inheritance_context(self, appmodel, parent): + label = "multi-table" + if parent._meta.abstract: + label = "abstract" + if appmodel._meta.proxy: + label = "proxy" + label += r"\ninheritance" + if self.hide_edge_labels: + label = '' + return { + 'target_app': parent.__module__.replace(".", "_"), + 'target': parent.__name__, + 'type': "inheritance", + 'name': "inheritance", + 'label': label, + 'arrows': '[arrowhead=empty, arrowtail=none, dir=both]', + 'needs_node': True, + } + + def get_models(self, app): + appmodels = list(app.get_models()) + return appmodels + + def get_relation_context(self, target_model, field, label, extras): + return { + 'target_app': target_model.__module__.replace('.', '_'), + 'target': target_model.__name__, + 'type': type(field).__name__, + 'name': field.name, + 'label': label, + 'arrows': extras, + 'needs_node': True + } + + def process_attributes(self, field, model, pk, abstract_fields): + newmodel = model.copy() + if self.skip_field(field) or pk and field == pk: + return newmodel + newmodel['fields'].append(self.add_attributes(field, abstract_fields)) + return newmodel + + def process_apps(self): + for app_label in self.app_labels: + app = apps.get_app_config(app_label) + if not app: + continue + app_graph = self.get_app_context(app) + app_models = self.get_models(app) + abstract_models = self.get_abstract_models(app_models) + app_models = abstract_models + app_models + + for appmodel in app_models: + if not self.use_model(appmodel._meta.object_name): + continue + appmodel_abstracts = self.get_appmodel_abstracts(appmodel) + abstract_fields = self.get_bases_abstract_fields(appmodel) + model = self.get_appmodel_context(appmodel, appmodel_abstracts) + attributes = self.get_appmodel_attributes(appmodel) + + # find primary key and print it first, ignoring implicit id if other pk exists + pk = appmodel._meta.pk + if pk and not appmodel._meta.abstract and pk in attributes: + model['fields'].append(self.add_attributes(pk, abstract_fields)) + + for field in attributes: + model = self.process_attributes(field, model, pk, abstract_fields) + + if self.sort_fields: + model = self.sort_model_fields(model) + + for field in appmodel._meta.local_fields: + model = self.process_local_fields(field, model, abstract_fields) + + for field in appmodel._meta.local_many_to_many: + model = self.process_local_many_to_many(field, model) + + if self.inheritance: + # add inheritance arrows + for parent in appmodel.__bases__: + model = self.process_parent(parent, appmodel, model) + + app_graph['models'].append(model) + if app_graph['models']: + self.graphs.append(app_graph) + + def process_local_fields(self, field, model, abstract_fields): + newmodel = model.copy() + if field.attname.endswith('_ptr_id') or field in abstract_fields or self.skip_field(field): + # excluding field redundant with inheritance relation + # excluding fields inherited from abstract classes. they too show as local_fields + return newmodel + if isinstance(field, OneToOneField): + relation = self.add_relation( + field, newmodel, '[arrowhead=none, arrowtail=none, dir=both]' + ) + elif isinstance(field, ForeignKey): + relation = self.add_relation( + field, + newmodel, + '[arrowhead=none, arrowtail={}, dir=both]'.format( + self.arrow_shape + ), + ) + else: + relation = None + if relation is not None: + newmodel['relations'].append(relation) + return newmodel + + def process_local_many_to_many(self, field, model): + newmodel = model.copy() + if self.skip_field(field): + return newmodel + relation = None + if isinstance(field, ManyToManyField): + if hasattr(field.remote_field.through, '_meta') and field.remote_field.through._meta.auto_created: + relation = self.add_relation( + field, + newmodel, + '[arrowhead={} arrowtail={}, dir=both]'.format( + self.arrow_shape, self.arrow_shape + ), + ) + elif isinstance(field, GenericRelation): + relation = self.add_relation(field, newmodel, mark_safe('[style="dotted", arrowhead=normal, arrowtail=normal, dir=both]')) + if relation is not None: + newmodel['relations'].append(relation) + return newmodel + + def process_parent(self, parent, appmodel, model): + newmodel = model.copy() + if hasattr(parent, "_meta"): # parent is a model + _rel = self.get_inheritance_context(appmodel, parent) + # TODO: seems as if abstract models aren't part of models.getModels, which is why they are printed by this without any attributes. + if _rel not in newmodel['relations'] and self.use_model(_rel['target']): + newmodel['relations'].append(_rel) + return newmodel + + def sort_model_fields(self, model): + newmodel = model.copy() + newmodel['fields'] = sorted(newmodel['fields'], key=lambda field: (not field['primary_key'], not field['relation'], field['label'])) + return newmodel + + def use_model(self, model_name): + """ + Decide whether to use a model, based on the model name and the lists of + models to exclude and include. + """ + # Check against include list. + if self.include_models: + for model_pattern in self.include_models: + model_pattern = '^%s$' % model_pattern.replace('*', '.*') + if re.search(model_pattern, model_name): + return True + # Check against exclude list. + if self.exclude_models: + for model_pattern in self.exclude_models: + model_pattern = '^%s$' % model_pattern.replace('*', '.*') + if re.search(model_pattern, model_name): + return False + # Return `True` if `include_models` is falsey, otherwise return `False`. + return not self.include_models + + def skip_field(self, field): + if self.exclude_columns: + if self.verbose_names and field.verbose_name: + if field.verbose_name in self.exclude_columns: + return True + if field.name in self.exclude_columns: + return True + return False + + +def generate_dot(graph_data, template='django_extensions/graph_models/digraph.dot'): + if isinstance(template, str): + template = loader.get_template(template) + + if not isinstance(template, Template) and not (hasattr(template, 'template') and isinstance(template.template, Template)): + raise Exception("Default Django template loader isn't used. " + "This can lead to the incorrect template rendering. " + "Please, check the settings.") + + c = Context(graph_data).flatten() + dot = template.render(c) + + return dot + + +def generate_graph_data(*args, **kwargs): + generator = ModelGraph(*args, **kwargs) + generator.generate_graph_data() + return generator.get_graph_data() + + +def use_model(model, include_models, exclude_models): + generator = ModelGraph([], include_models=include_models, exclude_models=exclude_models) + return generator.use_model(model) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/mysql.py b/venv/lib/python3.7/site-packages/django_extensions/management/mysql.py new file mode 100644 index 0000000..4b3f7fd --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/mysql.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +import configparser + + +def parse_mysql_cnf(dbinfo): + """ + Attempt to parse mysql database config file for connection settings. + Ideally we would hook into django's code to do this, but read_default_file is handled by the mysql C libs + so we have to emulate the behaviour + + Settings that are missing will return '' + returns (user, password, database_name, database_host, database_port) + """ + read_default_file = dbinfo.get('OPTIONS', {}).get('read_default_file') + if read_default_file: + config = configparser.RawConfigParser({ + 'user': '', + 'password': '', + 'database': '', + 'host': '', + 'port': '', + 'socket': '', + }) + import os + config.read(os.path.expanduser(read_default_file)) + try: + user = config.get('client', 'user') + password = config.get('client', 'password') + database_name = config.get('client', 'database') + database_host = config.get('client', 'host') + database_port = config.get('client', 'port') + socket = config.get('client', 'socket') + + if database_host == 'localhost' and socket: + # mysql actually uses a socket if host is localhost + database_host = socket + + return user, password, database_name, database_host, database_port + + except configparser.NoSectionError: + pass + + return '', '', '', '', '' diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/notebook_extension.py b/venv/lib/python3.7/site-packages/django_extensions/management/notebook_extension.py new file mode 100644 index 0000000..bd07273 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/notebook_extension.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +def load_ipython_extension(ipython): + from django.core.management.color import no_style + from django_extensions.management.shells import import_objects + + imported_objects = import_objects( + options={'dont_load': []}, + style=no_style(), + ) + ipython.push(imported_objects) diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/shells.py b/venv/lib/python3.7/site-packages/django_extensions/management/shells.py new file mode 100644 index 0000000..3fc9c6a --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/shells.py @@ -0,0 +1,345 @@ +# -*- coding: utf-8 -*- +import ast +import traceback +import warnings +import importlib + +from typing import ( # NOQA + Dict, + List, + Tuple, + Union, +) + +from django.apps.config import MODELS_MODULE_NAME +from django.utils.module_loading import import_string +from django_extensions.collision_resolvers import CollisionResolvingRunner +from django_extensions.import_subclasses import SubclassesFinder +from django_extensions.utils.deprecation import RemovedInNextVersionWarning + + +SHELL_PLUS_DJANGO_IMPORTS = [ + 'from django.core.cache import cache', + 'from django.conf import settings', + 'from django.contrib.auth import get_user_model', + 'from django.db import transaction', + 'from django.db.models import Avg, Case, Count, F, Max, Min, Prefetch, Q, Sum, When', + 'from django.utils import timezone', + 'from django.urls import reverse', + 'from django.db.models import Exists, OuterRef, Subquery', +] + + +class ObjectImportError(Exception): + pass + + +def get_app_name(mod_name): + """ + Retrieve application name from models.py module path + + >>> get_app_name('testapp.models.foo') + 'testapp' + + 'testapp' instead of 'some.testapp' for compatibility: + >>> get_app_name('some.testapp.models.foo') + 'testapp' + >>> get_app_name('some.models.testapp.models.foo') + 'testapp' + >>> get_app_name('testapp.foo') + 'testapp' + >>> get_app_name('some.testapp.foo') + 'testapp' + """ + rparts = list(reversed(mod_name.split('.'))) + try: + try: + return rparts[rparts.index(MODELS_MODULE_NAME) + 1] + except ValueError: + # MODELS_MODULE_NAME ('models' string) is not found + return rparts[1] + except IndexError: + # Some weird model naming scheme like in Sentry. + return mod_name + + +def import_items(import_directives, style, quiet_load=False): + """ + Import the items in import_directives and return a list of the imported items + + Each item in import_directives should be one of the following forms + * a tuple like ('module.submodule', ('classname1', 'classname2')), which indicates a 'from module.submodule import classname1, classname2' + * a tuple like ('module.submodule', 'classname1'), which indicates a 'from module.submodule import classname1' + * a tuple like ('module.submodule', '*'), which indicates a 'from module.submodule import *' + * a simple 'module.submodule' which indicates 'import module.submodule'. + + Returns a dict mapping the names to the imported items + """ + imported_objects = {} + + for directive in import_directives: + if isinstance(directive, str): + directive = directive.strip() + try: + if isinstance(directive, str) and directive.startswith(("from ", "import ")): + try: + node = ast.parse(directive) + except Exception as exc: + if not quiet_load: + print(style.ERROR("Error parsing: %r %s" % (directive, exc))) + continue + if not all(isinstance(body, (ast.Import, ast.ImportFrom)) for body in node.body): + if not quiet_load: + print(style.ERROR("Only specify import statements: %r" % directive)) + continue + + if not quiet_load: + print(style.SQL_COLTYPE("%s" % directive)) + + for body in node.body: + if isinstance(body, ast.Import): + for name in body.names: + asname = name.asname or name.name + imported_objects[asname] = importlib.import_module(name.name) + if isinstance(body, ast.ImportFrom): + imported_object = importlib.__import__(body.module, {}, {}, [name.name for name in body.names]) + for name in body.names: + asname = name.asname or name.name + try: + if name.name == "*": + for k in dir(imported_object): + imported_objects[k] = getattr(imported_object, k) + else: + imported_objects[asname] = getattr(imported_object, name.name) + except AttributeError as exc: + print(dir(imported_object)) + # raise + raise ImportError(exc) + else: + warnings.warn("Old style import definitions are deprecated. You should use the new style which is similar to normal Python imports. ", RemovedInNextVersionWarning, stacklevel=2) + + if isinstance(directive, str): + imported_object = __import__(directive) + imported_objects[directive.split('.')[0]] = imported_object + if not quiet_load: + print(style.SQL_COLTYPE("import %s" % directive)) + continue + elif isinstance(directive, (list, tuple)) and len(directive) == 2: + if not isinstance(directive[0], str): + if not quiet_load: + print(style.ERROR("Unable to import %r: module name must be of type string" % directive[0])) + continue + + if isinstance(directive[1], (list, tuple)) and all(isinstance(e, str) for e in directive[1]): + # Try the ('module.submodule', ('classname1', 'classname2')) form + imported_object = __import__(directive[0], {}, {}, directive[1]) + imported_names = [] + for name in directive[1]: + try: + imported_objects[name] = getattr(imported_object, name) + except AttributeError: + if not quiet_load: + print(style.ERROR("Unable to import %r from %r: %r does not exist" % (name, directive[0], name))) + else: + imported_names.append(name) + if not quiet_load: + print(style.SQL_COLTYPE("from %s import %s" % (directive[0], ', '.join(imported_names)))) + elif isinstance(directive[1], str): + # If it is a tuple, but the second item isn't a list, so we have something like ('module.submodule', 'classname1') + # Check for the special '*' to import all + if directive[1] == '*': + imported_object = __import__(directive[0], {}, {}, directive[1]) + for k in dir(imported_object): + imported_objects[k] = getattr(imported_object, k) + if not quiet_load: + print(style.SQL_COLTYPE("from %s import *" % directive[0])) + else: + imported_object = getattr(__import__(directive[0], {}, {}, [directive[1]]), directive[1]) + imported_objects[directive[1]] = imported_object + if not quiet_load: + print(style.SQL_COLTYPE("from %s import %s" % (directive[0], directive[1]))) + else: + if not quiet_load: + print(style.ERROR("Unable to import %r from %r: names must be of type string" % (directive[1], directive[0]))) + else: + if not quiet_load: + print(style.ERROR("Unable to import %r: names must be of type string" % directive)) + except ImportError: + if not quiet_load: + print(style.ERROR("Unable to import %r" % directive)) + + return imported_objects + + +def import_objects(options, style): + from django.apps import apps + from django import setup + + if not apps.ready: + setup() + + from django.conf import settings + + dont_load_cli = options.get('dont_load', []) + dont_load_conf = getattr(settings, 'SHELL_PLUS_DONT_LOAD', []) + dont_load = dont_load_cli + dont_load_conf + dont_load_any_models = '*' in dont_load + quiet_load = options.get('quiet_load') + model_aliases = getattr(settings, 'SHELL_PLUS_MODEL_ALIASES', {}) + app_prefixes = getattr(settings, 'SHELL_PLUS_APP_PREFIXES', {}) + SHELL_PLUS_PRE_IMPORTS = getattr(settings, 'SHELL_PLUS_PRE_IMPORTS', {}) + + imported_objects = {} + load_models = {} + + def get_dict_from_names_to_possible_models(): # type: () -> Dict[str, List[str]] + """ + Collect dictionary from names to possible models. Model is represented as his full path. + Name of model can be alias if SHELL_PLUS_MODEL_ALIASES or SHELL_PLUS_APP_PREFIXES is specified for this model. + This dictionary is used by collision resolver. + At this phase we can't import any models, because collision resolver can change results. + :return: Dict[str, List[str]]. Key is name, value is list of full model's path's. + """ + models_to_import = {} # type: Dict[str, List[str]] + for app_mod, models in sorted(load_models.items()): + app_name = get_app_name(app_mod) + app_aliases = model_aliases.get(app_name, {}) + prefix = app_prefixes.get(app_name) + + for model_name in sorted(models): + if "%s.%s" % (app_name, model_name) in dont_load: + continue + + alias = app_aliases.get(model_name) + + if not alias: + if prefix: + alias = "%s_%s" % (prefix, model_name) + else: + alias = model_name + + models_to_import.setdefault(alias, []) + models_to_import[alias].append("%s.%s" % (app_mod, model_name)) + return models_to_import + + def import_subclasses(): + base_classes_to_import = getattr(settings, 'SHELL_PLUS_SUBCLASSES_IMPORT', []) # type: List[Union[str, type]] + if base_classes_to_import: + if not quiet_load: + print(style.SQL_TABLE("# Shell Plus Subclasses Imports")) + perform_automatic_imports(SubclassesFinder(base_classes_to_import).collect_subclasses()) + + def import_models(): + """ + Perform collision resolving and imports all models. + When collisions are resolved we can perform imports and print information's, because it is last phase. + This function updates imported_objects dictionary. + """ + modules_to_models = CollisionResolvingRunner().run_collision_resolver(get_dict_from_names_to_possible_models()) + perform_automatic_imports(modules_to_models) + + def perform_automatic_imports(modules_to_classes): # type: (Dict[str, List[Tuple[str, str]]]) -> () + """ + Import elements from given dictionary. + :param modules_to_classes: dictionary from module name to tuple. + First element of tuple is model name, second is model alias. + If both elements are equal than element is imported without alias. + """ + for full_module_path, models in modules_to_classes.items(): + model_labels = [] + for (model_name, alias) in sorted(models): + try: + imported_objects[alias] = import_string("%s.%s" % (full_module_path, model_name)) + if model_name == alias: + model_labels.append(model_name) + else: + model_labels.append("%s (as %s)" % (model_name, alias)) + except ImportError as e: + if options.get("traceback"): + traceback.print_exc() + if not options.get('quiet_load'): + print(style.ERROR( + "Failed to import '%s' from '%s' reason: %s" % (model_name, full_module_path, str(e)))) + if not options.get('quiet_load'): + print(style.SQL_COLTYPE("from %s import %s" % (full_module_path, ", ".join(model_labels)))) + + def get_apps_and_models(): + for app in apps.get_app_configs(): + if app.models_module: + yield app.models_module, app.get_models() + + mongoengine = False + try: + from mongoengine.base import _document_registry + mongoengine = True + except ImportError: + pass + + # Perform pre-imports before any other imports + if SHELL_PLUS_PRE_IMPORTS: + if not quiet_load: + print(style.SQL_TABLE("# Shell Plus User Pre Imports")) + imports = import_items(SHELL_PLUS_PRE_IMPORTS, style, quiet_load=quiet_load) + for k, v in imports.items(): + imported_objects[k] = v + + if mongoengine and not dont_load_any_models: + for name, mod in _document_registry.items(): + name = name.split('.')[-1] + app_name = get_app_name(mod.__module__) + if app_name in dont_load or ("%s.%s" % (app_name, name)) in dont_load: + continue + + load_models.setdefault(mod.__module__, []) + load_models[mod.__module__].append(name) + + if not dont_load_any_models: + for app_mod, app_models in get_apps_and_models(): + if not app_models: + continue + + app_name = get_app_name(app_mod.__name__) + if app_name in dont_load: + continue + + for mod in app_models: + if "%s.%s" % (app_name, mod.__name__) in dont_load: + continue + + if mod.__module__: + # Only add the module to the dict if `__module__` is not empty. + load_models.setdefault(mod.__module__, []) + load_models[mod.__module__].append(mod.__name__) + + import_subclasses() + if not quiet_load: + print(style.SQL_TABLE("# Shell Plus Model Imports%s") % (' SKIPPED' if dont_load_any_models else '')) + + import_models() + + # Imports often used from Django + if getattr(settings, 'SHELL_PLUS_DJANGO_IMPORTS', True): + if not quiet_load: + print(style.SQL_TABLE("# Shell Plus Django Imports")) + imports = import_items(SHELL_PLUS_DJANGO_IMPORTS, style, quiet_load=quiet_load) + for k, v in imports.items(): + imported_objects[k] = v + + SHELL_PLUS_IMPORTS = getattr(settings, 'SHELL_PLUS_IMPORTS', {}) + if SHELL_PLUS_IMPORTS: + if not quiet_load: + print(style.SQL_TABLE("# Shell Plus User Imports")) + imports = import_items(SHELL_PLUS_IMPORTS, style, quiet_load=quiet_load) + for k, v in imports.items(): + imported_objects[k] = v + + # Perform post-imports after any other imports + SHELL_PLUS_POST_IMPORTS = getattr(settings, 'SHELL_PLUS_POST_IMPORTS', {}) + if SHELL_PLUS_POST_IMPORTS: + if not quiet_load: + print(style.SQL_TABLE("# Shell Plus User Post Imports")) + imports = import_items(SHELL_PLUS_POST_IMPORTS, style, quiet_load=quiet_load) + for k, v in imports.items(): + imported_objects[k] = v + + return imported_objects diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/signals.py b/venv/lib/python3.7/site-packages/django_extensions/management/signals.py new file mode 100644 index 0000000..3a490cf --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/signals.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from django.dispatch import Signal + +run_minutely_jobs = Signal() +run_quarter_hourly_jobs = Signal() +run_hourly_jobs = Signal() +run_daily_jobs = Signal() +run_weekly_jobs = Signal() +run_monthly_jobs = Signal() +run_yearly_jobs = Signal() + +pre_command = Signal() +post_command = Signal() diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/technical_response.py b/venv/lib/python3.7/site-packages/django_extensions/management/technical_response.py new file mode 100644 index 0000000..509c5ec --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/technical_response.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +import threading + +from django.core.handlers.wsgi import WSGIHandler + +tld = threading.local() +tld.wsgi_tb = None + + +def null_technical_500_response(request, exc_type, exc_value, tb, status_code=500): + """ + Alternative function for django.views.debug.technical_500_response. + + Django's convert_exception_to_response() wrapper is called on each 'Middleware' object to avoid + leaking exceptions. If an uncaught exception is raised, the wrapper calls technical_500_response() + to create a response for django's debug view. + + Runserver_plus overrides the django debug view's technical_500_response() function to allow for + an enhanced WSGI debugger view to be displayed. However, because Django calls + convert_exception_to_response() on each object in the stack of Middleware objects, re-raising an + error quickly pollutes the traceback displayed. + + Runserver_plus only needs needs traceback frames relevant to WSGIHandler Middleware objects, so + only store the traceback if it is for a WSGIHandler. If an exception is not raised here, Django + eventually throws an error for not getting a valid response object for its debug view. + """ + try: + # Store the most recent tb for WSGI requests. The class can be found in the second frame of the tb + if isinstance(tb.tb_next.tb_frame.f_locals.get('self'), WSGIHandler): + tld.wsgi_tb = tb + elif tld.wsgi_tb: + tb = tld.wsgi_tb + except AttributeError: + pass + + try: + if exc_value is None: + exc_value = exc_type() + if exc_value.__traceback__ is not tb: + raise exc_value.with_traceback(tb) + raise exc_value + finally: + exc_value = None + tb = None diff --git a/venv/lib/python3.7/site-packages/django_extensions/management/utils.py b/venv/lib/python3.7/site-packages/django_extensions/management/utils.py new file mode 100644 index 0000000..3a5ed51 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/management/utils.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +import logging +import os +import sys + +from django_extensions.management.signals import post_command, pre_command + + +def _make_writeable(filename): + """ + Make sure that the file is writable. Useful if our source is + read-only. + """ + import stat + if sys.platform.startswith('java'): + # On Jython there is no os.access() + return + if not os.access(filename, os.W_OK): + st = os.stat(filename) + new_permissions = stat.S_IMODE(st.st_mode) | stat.S_IWUSR + os.chmod(filename, new_permissions) + + +def setup_logger(logger, stream, filename=None, fmt=None): + """ + Set up a logger (if no handlers exist) for console output, + and file 'tee' output if desired. + """ + if len(logger.handlers) < 1: + console = logging.StreamHandler(stream) + console.setLevel(logging.DEBUG) + console.setFormatter(logging.Formatter(fmt)) + logger.addHandler(console) + logger.setLevel(logging.DEBUG) + logger.propagate = False + + if filename: + outfile = logging.FileHandler(filename) + outfile.setLevel(logging.INFO) + outfile.setFormatter(logging.Formatter("%(asctime)s " + (fmt if fmt else '%(message)s'))) + logger.addHandler(outfile) + + +class RedirectHandler(logging.Handler): + """Redirect logging sent to one logger (name) to another.""" + + def __init__(self, name, level=logging.DEBUG): + # Contemplate feasibility of copying a destination (allow original handler) and redirecting. + logging.Handler.__init__(self, level) + self.name = name + self.logger = logging.getLogger(name) + + def emit(self, record): + self.logger.handle(record) + + +def signalcommand(func): + """Python decorator for management command handle defs that sends out a pre/post signal.""" + + def inner(self, *args, **kwargs): + pre_command.send(self.__class__, args=args, kwargs=kwargs) + ret = func(self, *args, **kwargs) + post_command.send(self.__class__, args=args, kwargs=kwargs, outcome=ret) + return ret + return inner + + +def has_ipdb(): + try: + import ipdb # noqa + import IPython # noqa + return True + except ImportError: + return False diff --git a/venv/lib/python3.7/site-packages/django_extensions/models.py b/venv/lib/python3.7/site-packages/django_extensions/models.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/mongodb/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/mongodb/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.7/site-packages/django_extensions/mongodb/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/mongodb/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ecc2466ffbbc2a6c7339f1cbe27bc3a374290af GIT binary patch literal 196 zcmYL@u?oU47=%-B5TOs^VE@6vMMT8eMVv$0{MMK@3H{Sz`$j&6@8Ia_6NsCW$siuw zcgIb)Nz(}ny5C+r<}>1_B$Rb9jRGXwvuU!svL?=dd}=rlHUzpEdK$bv^4uCMw1O>? z_SQis%9fx*(?O+jaJ@fSGtU-4%Hzz5LW>d!jFtRM8VK`_XM!O%25Fj$*;-x$o}tus5=#<;_}7BD`V9oH81s5k%t{y~rw9f@C-C3w&nl7r}l-KVG9;u|rH+Q`8pkT=? ziGMp4lYY%-qjMKUzKMz(fys=(VrF1-=gbIN+(q4nofflUr+sDx9&=!2tK25-rz*F8YzKi0nmhR+!v?rB_V&(5elKXKQN$F>_&{qeM^5>#BP8gTIq3d?)LKfMJ2}%xQcckj-1j9!#v7( z7?#~I#8Hcs`n@pxauKEVjMtd*Z$r=ty87j4@|om9PL9O#L@re^3-^kg$4ANJK9@(T zm`{$Q{e_$y^Za;{CVP|li8?6qzm5Msk%{7W=23ivE0z;>80Gs#2;}fw;$r0_DQ)5lhNdzq)$ZL+Oaix!Ae%0-ay$zSNG!jtF+#w>IPK=lE5MN zlv`{5d@{VA#e%<}NWvq*t7~@6o+U`WVY>|hee!Ko>j3-Kn3^Us3ZXGn6KTy>m(Eo%s(!Yt59VGt$DI$t8E{X9>Ayz1Jy#}m1)VvoD2Pif%@T%`9SV z-U4sC;OaK_kR1_wduJx=JhFq%O46+*UF1bZ&^ynQ!0LS+mXs%X!9a)Q5SSj8gH5k2 z547tyg-^}rQH8RG(pSUvOhMmlfQ(Dea&Z&B2wZ(I2miL?gCaqUmu<#p(IQp5%h!)M zpZh$Us}p}#2)q}5l4YDF;C#P615XrS@&fh}#As#bfT#12(!b@a7nUbEc207<`D=?e z?uoE>7e&%FZ{CyUgR5HG6{Y<-exK3-YuUpp3WN;3=w)7_oj&!*wM4?q6s-an^;B0$Hq zpqxd}a}o?0-%wk}P0+4syn4Mz6G1QH`E%K*tHbX$rtYC=4oCReU2|ad%q#eFt${6Q zesoRTK@&V*C3xe7N|4MUC(b3Z2LMRWZ3v>x;F?bPkSruQA0va)|2GJ_mEg+yR0ZtH z7;PJQYIAkN-l9!Y{%^9&ah+X`>%Hg|*Xg3p5_PhtA7t$oZOFL~)~WA3q?5>&-zOs~ VH^2cs^BNxXYxeeVdwcu&{{zVScH{s6 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/__init__.py b/venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/__init__.py new file mode 100644 index 0000000..857a5db --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/__init__.py @@ -0,0 +1,268 @@ +# -*- coding: utf-8 -*- +""" +MongoDB model fields emulating Django Extensions' additional model fields + +These fields are essentially identical to existing Extensions fields, but South hooks have been removed (since mongo requires no schema migration) + +""" + +import re +import datetime +from django import forms +from django.db.models.constants import LOOKUP_SEP +from django.template.defaultfilters import slugify +from django.utils.translation import gettext_lazy as _ +from mongoengine.fields import StringField, DateTimeField + +import uuid + + +class SlugField(StringField): + description = _("String (up to %(max_length)s)") + + def __init__(self, *args, **kwargs): + kwargs['max_length'] = kwargs.get('max_length', 50) + # Set db_index=True unless it's been set manually. + if 'db_index' not in kwargs: + kwargs['db_index'] = True + super().__init__(*args, **kwargs) + + def get_internal_type(self): + return "SlugField" + + def formfield(self, **kwargs): + defaults = {'form_class': forms.SlugField} + defaults.update(kwargs) + return super().formfield(**defaults) + + +class AutoSlugField(SlugField): + """ + AutoSlugField, adapted for MongoDB + + By default, sets editable=False, blank=True. + + Required arguments: + + populate_from + Specifies which field or list of fields the slug is populated from. + + Optional arguments: + + separator + Defines the used separator (default: '-') + + overwrite + If set to True, overwrites the slug on every save (default: False) + + Inspired by SmileyChris' Unique Slugify snippet: + http://www.djangosnippets.org/snippets/690/ + """ + + def __init__(self, *args, **kwargs): + kwargs.setdefault('blank', True) + kwargs.setdefault('editable', False) + + populate_from = kwargs.pop('populate_from', None) + if populate_from is None: + raise ValueError("missing 'populate_from' argument") + else: + self._populate_from = populate_from + + self.slugify_function = kwargs.pop('slugify_function', slugify) + self.separator = kwargs.pop('separator', str('-')) + self.overwrite = kwargs.pop('overwrite', False) + super().__init__(*args, **kwargs) + + def _slug_strip(self, value): + """ + Clean up a slug by removing slug separator characters that occur at + the beginning or end of a slug. + + If an alternate separator is used, it will also replace any instances + of the default '-' separator with the new separator. + """ + re_sep = '(?:-|%s)' % re.escape(self.separator) + value = re.sub('%s+' % re_sep, self.separator, value) + return re.sub(r'^%s+|%s+$' % (re_sep, re_sep), '', value) + + def slugify_func(self, content): + return self.slugify_function(content) + + def create_slug(self, model_instance, add): + # get fields to populate from and slug field to set + if not isinstance(self._populate_from, (list, tuple)): + self._populate_from = (self._populate_from, ) + slug_field = model_instance._meta.get_field(self.attname) + + if add or self.overwrite: + # slugify the original field content and set next step to 2 + slug_for_field = lambda lookup_value: self.slugify_func(self.get_slug_fields(model_instance, lookup_value)) + slug = self.separator.join(map(slug_for_field, self._populate_from)) + next = 2 + else: + # get slug from the current model instance and calculate next + # step from its number, clean-up + slug = self._slug_strip(getattr(model_instance, self.attname)) + next = slug.split(self.separator)[-1] + if next.isdigit(): + slug = self.separator.join(slug.split(self.separator)[:-1]) + next = int(next) + else: + next = 2 + + # strip slug depending on max_length attribute of the slug field + # and clean-up + slug_len = slug_field.max_length + if slug_len: + slug = slug[:slug_len] + slug = self._slug_strip(slug) + original_slug = slug + + # exclude the current model instance from the queryset used in finding + # the next valid slug + queryset = model_instance.__class__._default_manager.all() + if model_instance.pk: + queryset = queryset.exclude(pk=model_instance.pk) + + # form a kwarg dict used to impliment any unique_together contraints + kwargs = {} + for params in model_instance._meta.unique_together: + if self.attname in params: + for param in params: + kwargs[param] = getattr(model_instance, param, None) + kwargs[self.attname] = slug + + # increases the number while searching for the next valid slug + # depending on the given slug, clean-up + while not slug or queryset.filter(**kwargs): + slug = original_slug + end = '%s%s' % (self.separator, next) + end_len = len(end) + if slug_len and len(slug) + end_len > slug_len: + slug = slug[:slug_len - end_len] + slug = self._slug_strip(slug) + slug = '%s%s' % (slug, end) + kwargs[self.attname] = slug + next += 1 + return slug + + def get_slug_fields(self, model_instance, lookup_value): + lookup_value_path = lookup_value.split(LOOKUP_SEP) + attr = model_instance + for elem in lookup_value_path: + try: + attr = getattr(attr, elem) + except AttributeError: + raise AttributeError( + "value {} in AutoSlugField's 'populate_from' argument {} returned an error - {} has no attribute {}".format( + elem, lookup_value, attr, elem)) + + if callable(attr): + return "%s" % attr() + + return attr + + def pre_save(self, model_instance, add): + value = str(self.create_slug(model_instance, add)) + setattr(model_instance, self.attname, value) + return value + + def get_internal_type(self): + return "SlugField" + + +class CreationDateTimeField(DateTimeField): + """ + CreationDateTimeField + + By default, sets editable=False, blank=True, default=datetime.now + """ + + def __init__(self, *args, **kwargs): + kwargs.setdefault('default', datetime.datetime.now) + DateTimeField.__init__(self, *args, **kwargs) + + def get_internal_type(self): + return "DateTimeField" + + +class ModificationDateTimeField(CreationDateTimeField): + """ + ModificationDateTimeField + + By default, sets editable=False, blank=True, default=datetime.now + + Sets value to datetime.now() on each save of the model. + """ + + def pre_save(self, model, add): + value = datetime.datetime.now() + setattr(model, self.attname, value) + return value + + def get_internal_type(self): + return "DateTimeField" + + +class UUIDVersionError(Exception): + pass + + +class UUIDField(StringField): + """ + UUIDField + + By default uses UUID version 1 (generate from host ID, sequence number and current time) + + The field support all uuid versions which are natively supported by the uuid python module. + For more information see: http://docs.python.org/lib/module-uuid.html + """ + + def __init__(self, verbose_name=None, name=None, auto=True, version=1, node=None, clock_seq=None, namespace=None, **kwargs): + kwargs['max_length'] = 36 + self.auto = auto + self.version = version + if version == 1: + self.node, self.clock_seq = node, clock_seq + elif version == 3 or version == 5: + self.namespace, self.name = namespace, name + StringField.__init__(self, verbose_name, name, **kwargs) + + def get_internal_type(self): + return StringField.__name__ + + def contribute_to_class(self, cls, name): + if self.primary_key: + assert not cls._meta.has_auto_field, "A model can't have more than one AutoField: %s %s %s; have %s" % (self, cls, name, cls._meta.auto_field) + super().contribute_to_class(cls, name) + cls._meta.has_auto_field = True + cls._meta.auto_field = self + else: + super().contribute_to_class(cls, name) + + def create_uuid(self): + if not self.version or self.version == 4: + return uuid.uuid4() + elif self.version == 1: + return uuid.uuid1(self.node, self.clock_seq) + elif self.version == 2: + raise UUIDVersionError("UUID version 2 is not supported.") + elif self.version == 3: + return uuid.uuid3(self.namespace, self.name) + elif self.version == 5: + return uuid.uuid5(self.namespace, self.name) + else: + raise UUIDVersionError("UUID version %s is not valid." % self.version) + + def pre_save(self, model_instance, add): + if self.auto and add: + value = str(self.create_uuid()) + setattr(model_instance, self.attname, value) + return value + else: + value = super().pre_save(model_instance, add) + if self.auto and not value: + value = str(self.create_uuid()) + setattr(model_instance, self.attname, value) + return value diff --git a/venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/__pycache__/__init__.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..03ea63ae5dcf3afce5eb7f1d234f54a1f9d181a0 GIT binary patch literal 8749 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 G)B11Fv~vvr literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/__pycache__/json.cpython-37.pyc b/venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/__pycache__/json.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74e40c5d52afd85d5843e7c436ff05baf5607996 GIT binary patch literal 2898 zcmZuzOK%)S5T4iW&aNME9A1h7G!X``AiKPgLV$oB2#`2Pb|l!#sCT;89(x{3cds39 z9E6fcIgy`$k|V!@|G;ssoH%mj#8*AL8{49#epPo@S66*i)n6_wv>cQ_|M(}$L&y1x zCespNa1~Ymj7B&;N4UaE-JXlyPrc0V`EErEdI4xbTFdIax~0|9Mi%x$*ZJBJb zo3}Q;N@OY+ADJTKCW(2P9x^Re!qa3dHOmTZ*!PEKr^uO+D$~pqjLtE^4ezwpl;j5c zINQ4R!xkG@ZU>3k0Y%6GAEk!v^K>LxF<=+(-n-agY*R|`(k9x~Mcx@6vO%F*S)n9L zatuih&|57wP({YXF3-1%j_9)_8y3nyBq39MVl|R?jLbETX>9CRDfDzd-2!HD%C%-U zZrxa|7<6tDpZ4VzqXGtsvrm~7X{MLecI$6g%h_nVWn*2&NybwQLoJO-@@Qe#2`p= zqm;(;QS{S@r`3w(YF~7$ISc+)1uxKbq|eZ`^B7)d3-zQ^Yvc16z{U>QST7pyzH9sk z&XeHCAv?C+jdo2nu%`?}5*tM!rc!WSTIc|UHS1%iL?~-wlnph*eocUK@LKf}`k5Ff zpvJIboLv`!0H?ot_aFv<7eJ^Brbf_$Fdn(W+>k3Rqd{75)2=JhXIaBUXbT=Ita=_) zD=Wu5+mNJzAprqe=FUPaX;`!i317kR>mHw7YqWVJFRGp<8L z<6o>(Uk5~(E|`)-wc2JB+oWLqLq=+$@Wl?2G-bue3`eF4YUBix3j{06VG{VNpk#2^ z20g~Mb`s4FI3iba$BY!>pXGE=sJ++h!I_51&?LV#G*W^!G`TRDwXz1fMJ$|B4S|mY zkD_<6XhGz-v#_0PQVQ3yUxaJVlff zO7}saqTfOD|4J7%D8Kf|8Mrnng}wSC1g>5Kj|2 zxPgtyh{#?Qku7>Uv%NEQOrsX5MZb;)>R2)kLMHxFHuc$Yr4pLkKaW5D;Kaj8-&3^U z-F&KvzJ$9=dc5ZQl9fpQep%C_p;YD4wltCGM?-jKM9Vgu0tD89DZn8*HlxV?HQ<2O z_pHagiM8)YUK{A}*m-Y!{+Y>7^KFNxoLaqt!-`QuFIL2_T$tPx%QT(dMpq)DtkNcX z^Q#zrh^on4f#t4D5ThXj+uX^kTSedCDhO8D*H!*WY7vF<#~U(1u5%Gt^WYX{jU4~ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/json.py b/venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/json.py new file mode 100644 index 0000000..042603b --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/mongodb/fields/json.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +""" +JSONField automatically serializes most Python terms to JSON data. +Creates a TEXT field with a default value of "{}". See test_json.py for +more information. + + from django.db import models + from django_extensions.db.fields import json + + class LOL(models.Model): + extra = json.JSONField() +""" + +import datetime +from decimal import Decimal + +import json +from django.conf import settings +from mongoengine.fields import StringField + + +class JSONEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, Decimal): + return str(obj) + elif isinstance(obj, datetime.datetime): + assert settings.TIME_ZONE == 'UTC' + return obj.strftime('%Y-%m-%dT%H:%M:%SZ') + return json.JSONEncoder.default(self, obj) + + +def dumps(value): + assert isinstance(value, dict) + return JSONEncoder().encode(value) + + +def loads(txt): + value = json.loads(txt, parse_float=Decimal) + assert isinstance(value, dict) + return value + + +class JSONDict(dict): + """ + Hack so repr() called by dumpdata will output JSON instead of + Python formatted data. This way fixtures will work! + """ + + def __repr__(self): + return dumps(self) + + +class JSONField(StringField): + """ + JSONField is a generic textfield that neatly serializes/unserializes + JSON objects seamlessly. Main object must be a dict object. + """ + + def __init__(self, *args, **kwargs): + if 'default' not in kwargs: + kwargs['default'] = '{}' + StringField.__init__(self, *args, **kwargs) + + def to_python(self, value): + """ Convert our string value to JSON after we load it from the DB """ + if not value: + return {} + elif isinstance(value, str): + res = loads(value) + assert isinstance(res, dict) + return JSONDict(**res) + else: + return value + + def get_db_prep_save(self, value): + """ Convert our JSON object to a string before we save """ + if not value: + return super().get_db_prep_save("") + else: + return super().get_db_prep_save(dumps(value)) diff --git a/venv/lib/python3.7/site-packages/django_extensions/mongodb/models.py b/venv/lib/python3.7/site-packages/django_extensions/mongodb/models.py new file mode 100644 index 0000000..2c2d51d --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/mongodb/models.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +import datetime + +from django.utils.translation import gettext_lazy as _ +from mongoengine.document import Document +from mongoengine.fields import DateTimeField, IntField, StringField +from mongoengine.queryset import QuerySetManager + +from django_extensions.mongodb.fields import AutoSlugField, CreationDateTimeField, ModificationDateTimeField + + +class TimeStampedModel(Document): + """ + TimeStampedModel + + An abstract base class model that provides self-managed "created" and + "modified" fields. + """ + + created = CreationDateTimeField() + modified = ModificationDateTimeField() + + class Meta: + abstract = True + + +class TitleSlugDescriptionModel(Document): + """ + TitleSlugDescriptionModel + + An abstract base class model that provides title and description fields + and a self-managed "slug" field that populates from the title. + """ + + title = StringField(max_length=255) + slug = AutoSlugField(populate_from='title') + description = StringField(blank=True, null=True) + + class Meta: + abstract = True + + +class ActivatorModelManager(QuerySetManager): + """ + ActivatorModelManager + + Manager to return instances of ActivatorModel: SomeModel.objects.active() / .inactive() + """ + + def active(self): + """ + Return active instances of ActivatorModel: + + SomeModel.objects.active() + """ + return super().get_queryset().filter(status=1) + + def inactive(self): + """ + Return inactive instances of ActivatorModel: + + SomeModel.objects.inactive() + """ + return super().get_queryset().filter(status=0) + + +class ActivatorModel(Document): + """ + ActivatorModel + + An abstract base class model that provides activate and deactivate fields. + """ + + STATUS_CHOICES = ( + (0, _('Inactive')), + (1, _('Active')), + ) + status = IntField(choices=STATUS_CHOICES, default=1) + activate_date = DateTimeField(blank=True, null=True, help_text=_('keep empty for an immediate activation')) + deactivate_date = DateTimeField(blank=True, null=True, help_text=_('keep empty for indefinite activation')) + objects = ActivatorModelManager() + + class Meta: + abstract = True + + def save(self, *args, **kwargs): + if not self.activate_date: + self.activate_date = datetime.datetime.now() + super().save(*args, **kwargs) diff --git a/venv/lib/python3.7/site-packages/django_extensions/settings.py b/venv/lib/python3.7/site-packages/django_extensions/settings.py new file mode 100644 index 0000000..ec1b0cc --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/settings.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +import os + +from django.conf import settings + +BASE_DIR = os.path.dirname(os.path.realpath(__file__)) +REPLACEMENTS = getattr(settings, 'EXTENSIONS_REPLACEMENTS', {}) + +DEFAULT_SQLITE_ENGINES = ( + 'django.db.backends.sqlite3', + 'django.db.backends.spatialite', +) +DEFAULT_MYSQL_ENGINES = ( + 'django.db.backends.mysql', + 'django.contrib.gis.db.backends.mysql', + 'mysql.connector.django', +) +DEFAULT_POSTGRESQL_ENGINES = ( + 'django.db.backends.postgresql', + 'django.db.backends.postgresql_psycopg2', + 'django.db.backends.postgis', + 'django.contrib.gis.db.backends.postgis', + 'psqlextra.backend', + 'django_zero_downtime_migrations.backends.postgres', + 'django_zero_downtime_migrations.backends.postgis', +) + +SQLITE_ENGINES = getattr(settings, 'DJANGO_EXTENSIONS_RESET_DB_SQLITE_ENGINES', DEFAULT_SQLITE_ENGINES) +MYSQL_ENGINES = getattr(settings, 'DJANGO_EXTENSIONS_RESET_DB_MYSQL_ENGINES', DEFAULT_MYSQL_ENGINES) +POSTGRESQL_ENGINES = getattr(settings, 'DJANGO_EXTENSIONS_RESET_DB_POSTGRESQL_ENGINES', DEFAULT_POSTGRESQL_ENGINES) diff --git a/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/css/jquery.autocomplete.css b/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/css/jquery.autocomplete.css new file mode 100644 index 0000000..0363616 --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/css/jquery.autocomplete.css @@ -0,0 +1,38 @@ +/** + * @fileOverview CSS for jquery-autocomplete, the jQuery Autocompleter + * @author Dylan Verheul + * @license MIT | GPL | Apache 2.0, see LICENSE.txt + * @see https://github.com/dyve/jquery-autocomplete + */ +.acResults { + padding: 0px; + border: 1px solid WindowFrame; + background-color: Window; + overflow: hidden; +} + +.acResults ul { + margin: 0px; + padding: 0px; + list-style-position: outside; + list-style: none; +} + +.acResults ul li { + margin: 0px; + padding: 2px 5px; + cursor: pointer; + display: block; + font: menu; + font-size: 12px; + overflow: hidden; +} + +.acLoading { + background : url('../img/indicator.gif') right center no-repeat; +} + +.acSelect { + background-color: Highlight; + color: HighlightText; +} diff --git a/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/img/indicator.gif b/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/img/indicator.gif new file mode 100644 index 0000000000000000000000000000000000000000..085ccaecaf5fa5c34bc14cd2c2ed5cbbd8e25dcb GIT binary patch literal 1553 zcma)+TTl~c6vwlh>nb99Af5rT)t{mCEg5urg=A(g z{C|6SPb~9Xage|wB`SrZk2FOMYM!buln2sX?5Y+T78iB(Zu9cS7|LZyZ++}u$^oi1 z_j@S}bW9OzU2R+RMy&~OT>X-oZ98$jq#ogNfJ!BM-42wHGZk*6s2KD}U*IA%epmxb zm}|6BK9YoIF;*xSL!+z@<64lB7->LTW2Vi4ostCA(z&2XniwNIv}fFo-`MbG;)u4G z^p@F!)|9HhZprHd_vXjDoxs6WkK-6P0@lfxnGT>*p(QHoUV=u1FAqb@b%*W=a3{`LsH5k^AvQNL>6fPpy#oU(&MuH(*aEX4b35*} zn4n7)`I2U%=+Z=?BVZQ?vjQFW4gD@~XSOO6b{qu81`4&LFuU2(ilxW+1|ZkNMnWe79C$gs zWT?Ele|HR{JGPe)5BTW>0Ey?-Ls6S#GoV0tbt6ku7B&*0 z;i9QM$W1Rj*rRIdceL)rAOSl+sDe3LkB87<%){;ZdHp6|SNlopDXRx< zxBDF9-lTo&v`8$humFygUij@qgT=Qzhj8{ym2-{Xciwqq_Xwk%=O3B-MNAL_6e`3U zyxwmXex4`g0^1RYw~Dth3av3Dl^AAlpO3mG!nLr#&ZZ7c_wUboI+deC+&%TFjK2Lm z!Y&f1h|T_On%RCV&=4bx`!>(YezqGVhl&QpED?N6GV)HmzJ9&rh$x*i?*@o9#6QI< z5ZI_MRX;0+pY8$`j)eF#TlUyG(eE%E7S!rj;mj^M5vhUicPm zVWQ2z+imFyg}SRABmOBY_@osR!>7Ov!ioK`NB6_Rv}7Ud?35ed5Sb@?yND?kv~RCa wqs^a3Sh>&&L4)!LKI?D2&k@))k(LESaga|C278ChSzn3NWVkcuNoY&{0f?~U_5c6? literal 0 HcmV?d00001 diff --git a/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.ajaxQueue.js b/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.ajaxQueue.js new file mode 100644 index 0000000..cd4492c --- /dev/null +++ b/venv/lib/python3.7/site-packages/django_extensions/static/django_extensions/js/jquery.ajaxQueue.js @@ -0,0 +1,119 @@ +/** + * Ajax Queue Plugin + * + * Homepage: http://jquery.com/plugins/project/ajaxqueue + * Documentation: http://docs.jquery.com/AjaxQueue + */ + +/** + + +