From bf302d4a2b9a74676eced86c6befabc330f6e0b2 Mon Sep 17 00:00:00 2001 From: smcoll Date: Tue, 1 Aug 2017 10:27:27 -0500 Subject: [PATCH 1/6] increase Request.prof_file max_length to 300 (#203) --- README.md | 9 ++++++++- silk/migrations/0004_request_prof_file_storage.py | 2 +- .../0005_increase_request_prof_file_length.py | 2 +- silk/models.py | 11 +++++++---- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index efefdab7..fce42886 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,14 @@ When enabled a graph visualisation generated using [gprof2dot](https://github.co -You can specify where to store the generated binary `.prof` files to a path of your choosing. You must ensure the specified directory exists. + +A custom storage class can be used for the saved the generated binary `.prof` files: + +```python +SILKY_STORAGE_CLASS = 'path.to.StorageClass` +``` + +The default storage class is `silk.models.ProfilerResultStorage`, and when using that you can specify a path of your choosing. You must ensure the specified directory exists. ```python # If this is not set, MEDIA_ROOT will be used. diff --git a/silk/migrations/0004_request_prof_file_storage.py b/silk/migrations/0004_request_prof_file_storage.py index 918e26aa..e780e849 100644 --- a/silk/migrations/0004_request_prof_file_storage.py +++ b/silk/migrations/0004_request_prof_file_storage.py @@ -16,6 +16,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='request', name='prof_file', - field=models.FileField(null=True, storage=silk.models.ProfilerResultStorage(), upload_to=''), + field=models.FileField(null=True, storage=silk.models.silk_storage, upload_to=''), ), ] diff --git a/silk/migrations/0005_increase_request_prof_file_length.py b/silk/migrations/0005_increase_request_prof_file_length.py index a480fd44..7465b0dd 100644 --- a/silk/migrations/0005_increase_request_prof_file_length.py +++ b/silk/migrations/0005_increase_request_prof_file_length.py @@ -16,6 +16,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='request', name='prof_file', - field=models.FileField(max_length=300, null=True, storage=silk.models.ProfilerResultStorage(), upload_to=''), + field=models.FileField(max_length=300, null=True, storage=silk.models.silk_storage, upload_to=''), ), ] diff --git a/silk/models.py b/silk/models.py index e1ef3daf..c3c74bd8 100644 --- a/silk/models.py +++ b/silk/models.py @@ -4,7 +4,8 @@ import random import re -from django.core.files.storage import FileSystemStorage +from django.conf import settings +from django.core.files.storage import FileSystemStorage, get_storage_class from django.db import models from django.db.models import ( DateTimeField, TextField, CharField, ForeignKey, IntegerField, @@ -24,6 +25,10 @@ atomic = getattr(transaction, 'atomic', None) or getattr(transaction, 'commit_on_success') +storage_class = getattr(settings, 'SILKY_STORAGE_CLASS', 'silk.models.ProfilerResultStorage') +silk_storage = get_storage_class(storage_class)() + + # Seperated out so can use in tests w/o models def _time_taken(start_time, end_time): d = end_time - start_time @@ -82,9 +87,7 @@ class Request(models.Model): meta_num_queries = IntegerField(null=True, blank=True) meta_time_spent_queries = FloatField(null=True, blank=True) pyprofile = TextField(blank=True, default='') - prof_file = FileField( - max_length=300, null=True, storage=ProfilerResultStorage() - ) + prof_file = FileField(max_length=300, null=True, storage=silk_storage) @property def total_meta_time(self): From bfbbc6c96d12f1db988c3236433c45f44d603a1e Mon Sep 17 00:00:00 2001 From: shannon Date: Tue, 1 Aug 2017 09:24:17 -0500 Subject: [PATCH 2/6] move ProfilerResultStorage to own module to resolve import --- README.md | 4 ++-- silk/models.py | 27 ++++++++------------------- silk/storage.py | 13 +++++++++++++ 3 files changed, 23 insertions(+), 21 deletions(-) create mode 100644 silk/storage.py diff --git a/README.md b/README.md index fce42886..1494f298 100644 --- a/README.md +++ b/README.md @@ -169,10 +169,10 @@ When enabled a graph visualisation generated using [gprof2dot](https://github.co A custom storage class can be used for the saved the generated binary `.prof` files: ```python -SILKY_STORAGE_CLASS = 'path.to.StorageClass` +SILKY_STORAGE_CLASS = 'path.to.StorageClass' ``` -The default storage class is `silk.models.ProfilerResultStorage`, and when using that you can specify a path of your choosing. You must ensure the specified directory exists. +The default storage class is `silk.storage.ProfilerResultStorage`, and when using that you can specify a path of your choosing. You must ensure the specified directory exists. ```python # If this is not set, MEDIA_ROOT will be used. diff --git a/silk/models.py b/silk/models.py index c3c74bd8..d5f25fea 100644 --- a/silk/models.py +++ b/silk/models.py @@ -1,31 +1,30 @@ -from collections import Counter -import json import base64 +import json import random import re +from collections import Counter +from uuid import uuid4 +import sqlparse from django.conf import settings -from django.core.files.storage import FileSystemStorage, get_storage_class +from django.core.files.storage import get_storage_class from django.db import models +from django.db import transaction from django.db.models import ( DateTimeField, TextField, CharField, ForeignKey, IntegerField, BooleanField, F, ManyToManyField, OneToOneField, FloatField, FileField ) from django.utils import timezone -from django.db import transaction -from uuid import uuid4 -import sqlparse from django.utils.safestring import mark_safe -from silk.utils.profile_parser import parse_profile from silk.config import SilkyConfig +from silk.utils.profile_parser import parse_profile # Django 1.8 removes commit_on_success, django 1.5 does not have atomic atomic = getattr(transaction, 'atomic', None) or getattr(transaction, 'commit_on_success') - -storage_class = getattr(settings, 'SILKY_STORAGE_CLASS', 'silk.models.ProfilerResultStorage') +storage_class = getattr(settings, 'SILKY_STORAGE_CLASS', 'silk.storage.ProfilerResultStorage') silk_storage = get_storage_class(storage_class)() @@ -58,16 +57,6 @@ def __init__(self, d): self[k] = v -class ProfilerResultStorage(FileSystemStorage): - # the default storage will only store under MEDIA_ROOT, so we must define our own. - def __init__(self): - super(ProfilerResultStorage, self).__init__( - location=SilkyConfig().SILKY_PYTHON_PROFILER_RESULT_PATH, - base_url='' - ) - self.base_url = None - - class Request(models.Model): id = CharField(max_length=36, default=uuid4, primary_key=True) path = CharField(max_length=190, db_index=True) diff --git a/silk/storage.py b/silk/storage.py new file mode 100644 index 00000000..34291724 --- /dev/null +++ b/silk/storage.py @@ -0,0 +1,13 @@ +from django.core.files.storage import FileSystemStorage + +from silk.config import SilkyConfig + + +class ProfilerResultStorage(FileSystemStorage): + # the default storage will only store under MEDIA_ROOT, so we must define our own. + def __init__(self): + super(ProfilerResultStorage, self).__init__( + location=SilkyConfig().SILKY_PYTHON_PROFILER_RESULT_PATH, + base_url='' + ) + self.base_url = None From d79664531ef10b7a1c1f10c35c63a8649dec4574 Mon Sep 17 00:00:00 2001 From: shannon Date: Tue, 1 Aug 2017 09:28:51 -0500 Subject: [PATCH 3/6] use SilkyConfig for SILKY_STORAGE_CLASS --- silk/config.py | 1 + silk/models.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/silk/config.py b/silk/config.py index be6f382a..68abf484 100644 --- a/silk/config.py +++ b/silk/config.py @@ -28,6 +28,7 @@ class SilkyConfig(six.with_metaclass(Singleton, object)): 'SILKY_INTERCEPT_PERCENT': 100, 'SILKY_INTERCEPT_FUNC': None, 'SILKY_PYTHON_PROFILER': False, + 'SILKY_STORAGE_CLASS': 'silk.storage.ProfilerResultStorage' } def _setup(self): diff --git a/silk/models.py b/silk/models.py index d5f25fea..6502cd78 100644 --- a/silk/models.py +++ b/silk/models.py @@ -6,7 +6,6 @@ from uuid import uuid4 import sqlparse -from django.conf import settings from django.core.files.storage import get_storage_class from django.db import models from django.db import transaction @@ -24,7 +23,7 @@ # Django 1.8 removes commit_on_success, django 1.5 does not have atomic atomic = getattr(transaction, 'atomic', None) or getattr(transaction, 'commit_on_success') -storage_class = getattr(settings, 'SILKY_STORAGE_CLASS', 'silk.storage.ProfilerResultStorage') +storage_class = SilkyConfig().SILKY_STORAGE_CLASS silk_storage = get_storage_class(storage_class)() From 17ab7bdd969a88a79ad9a2697696530a74140e09 Mon Sep 17 00:00:00 2001 From: shannon Date: Tue, 1 Aug 2017 09:36:55 -0500 Subject: [PATCH 4/6] terse storage definition --- silk/models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/silk/models.py b/silk/models.py index 6502cd78..22b7d26b 100644 --- a/silk/models.py +++ b/silk/models.py @@ -23,8 +23,7 @@ # Django 1.8 removes commit_on_success, django 1.5 does not have atomic atomic = getattr(transaction, 'atomic', None) or getattr(transaction, 'commit_on_success') -storage_class = SilkyConfig().SILKY_STORAGE_CLASS -silk_storage = get_storage_class(storage_class)() +silk_storage = get_storage_class(SilkyConfig().SILKY_STORAGE_CLASS)() # Seperated out so can use in tests w/o models From b42d67000b7722105e6eb5754a96a6b1fde2536b Mon Sep 17 00:00:00 2001 From: shannon Date: Tue, 1 Aug 2017 09:41:05 -0500 Subject: [PATCH 5/6] didn't mean to reorder imports --- silk/models.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/silk/models.py b/silk/models.py index 22b7d26b..b31d8cbd 100644 --- a/silk/models.py +++ b/silk/models.py @@ -1,24 +1,24 @@ -import base64 +from collections import Counter import json +import base64 import random import re -from collections import Counter -from uuid import uuid4 -import sqlparse from django.core.files.storage import get_storage_class from django.db import models -from django.db import transaction from django.db.models import ( DateTimeField, TextField, CharField, ForeignKey, IntegerField, BooleanField, F, ManyToManyField, OneToOneField, FloatField, FileField ) from django.utils import timezone +from django.db import transaction +from uuid import uuid4 +import sqlparse from django.utils.safestring import mark_safe -from silk.config import SilkyConfig from silk.utils.profile_parser import parse_profile +from silk.config import SilkyConfig # Django 1.8 removes commit_on_success, django 1.5 does not have atomic atomic = getattr(transaction, 'atomic', None) or getattr(transaction, 'commit_on_success') From aae93178ace2d53370b75e7f66f70418011e6773 Mon Sep 17 00:00:00 2001 From: shannon Date: Tue, 8 Aug 2017 12:50:37 -0500 Subject: [PATCH 6/6] test default storage class --- project/tests/test_models.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/project/tests/test_models.py b/project/tests/test_models.py index 406af69a..e9fa6502 100644 --- a/project/tests/test_models.py +++ b/project/tests/test_models.py @@ -10,6 +10,7 @@ from freezegun import freeze_time from silk import models +from silk.storage import ProfilerResultStorage from silk.config import SilkyConfig from .factories import RequestMinFactory, SQLQueryFactory, ResponseFactory @@ -199,6 +200,10 @@ def test_save_if_have_end_time(self): self.assertEqual(obj.end_time, date) self.assertEqual(obj.time_taken, 3000.0) + def test_prof_file_default_storage(self): + obj = models.Request(path='/some/path/', method='get') + self.assertEqual(obj.prof_file.storage.__class__, ProfilerResultStorage) + class ResponseTest(TestCase):