# Path: speedinfo/conf.py
# DEFAULTS = {
#     "SPEEDINFO_TESTS": False,
#     "SPEEDINFO_CACHED_RESPONSE_ATTR_NAME": "_is_cached",
#     "SPEEDINFO_STORAGE": None,
#     "SPEEDINFO_CACHE_STORAGE_CACHE_ALIAS": "default",
#     "SPEEDINFO_PROFILING_CONDITIONS": [],
#     "SPEEDINFO_EXCLUDE_URLS": [],
#     "SPEEDINFO_ADMIN_COLUMNS": (
#         ("View name", "{}", "view_name"),
#         ("HTTP method", "{}", "method"),
#         ("Anonymous calls", "{:.1f}%", "anon_calls_ratio"),
#         ("Cache hits", "{:.1f}%", "cache_hits_ratio"),
#         ("SQL queries per call", "{}", "sql_count_per_call"),
#         ("SQL time", "{:.1f}%", "sql_time_ratio"),
#         ("Total calls", "{}", "total_calls"),
#         ("Time per call", "{:.8f}", "time_per_call"),
#         ("Total time", "{:.4f}", "total_time"),
#     ),
# }
# class SpeedinfoSettings:
#     def __init__(self, defaults=None):
#     def __getattr__(self, name):
# 
# Path: speedinfo/models.py
# class ViewProfiler(models.Model):
#     """
#     Model doesn't have associated table in the database.
#     So don't try to use it as an ordinary ORM model. You should
#     think of it as a dataclass. Model is used for wrapping
#     storage data and Django admin integration.
#     """
#     view_name = models.CharField("View name", max_length=255)
#     method = models.CharField("HTTP method", max_length=8)
#     anon_calls = models.PositiveIntegerField("Anonymous calls", default=0)
#     cache_hits = models.PositiveIntegerField("Cache hits", default=0)
#     sql_total_time = models.FloatField("SQL total time", default=0)
#     sql_total_count = models.PositiveIntegerField("SQL total queries count", default=0)
#     total_calls = models.PositiveIntegerField("Total calls", default=0)
#     total_time = models.FloatField("Total time", default=0)
# 
#     objects = ViewProfilerQuerySet.as_manager()
# 
#     class Meta:
#         verbose_name_plural = "Views"
#         managed = False
# 
#     def __init__(self, *args, **kwargs):
#         # Extract extra fields from parameters
#         extra_fields = {}
#         model_field_names = [field.attname for field in self._meta.get_fields()]
# 
#         for field_name in list(kwargs):
#             if field_name not in model_field_names:
#                 extra_fields[field_name] = kwargs.pop(field_name)
# 
#         super(ViewProfiler, self).__init__(*args, **kwargs)
# 
#         # Assign extra fields to the object if the field names
#         # do not override existing fields
#         for field_name, value in extra_fields.items():
#             if not getattr(self, field_name, None):
#                 setattr(self, field_name, value)
# 
#     @property
#     def anon_calls_ratio(self):
#         """Anonymous calls ratio.
# 
#         :return: anonymous calls ratio percent
#         :rtype: float
#         """
#         if self.total_calls > 0:
#             return 100 * self.anon_calls / float(self.total_calls)
#         else:
#             return 0
# 
#     @property
#     def cache_hits_ratio(self):
#         """Cache hits ratio.
# 
#         :return: cache hits ratio percent
#         :rtype: float
#         """
#         if self.total_calls > 0:
#             return 100 * self.cache_hits / float(self.total_calls)
#         else:
#             return 0
# 
#     @property
#     def sql_time_ratio(self):
#         """SQL time per call ratio.
# 
#         :return: SQL time per call ratio percent
#         :rtype: float
#         """
#         if self.total_time > 0:
#             return 100 * self.sql_total_time / float(self.total_time)
#         else:
#             return 0
# 
#     @property
#     def sql_count_per_call(self):
#         """SQL queries count per call.
# 
#         :return: SQL queries count per call
#         :rtype: int
#         """
#         if self.total_calls > 0:
#             return int(round(self.sql_total_count / float(self.total_calls)))
#         else:
#             return 0
# 
#     @property
#     def time_per_call(self):
#         """Time per call.
# 
#         :return: time per call
#         :rtype: float
#         """
#         if self.total_calls > 0:
#             return self.total_time / float(self.total_calls)
#         else:
#             return 0
# 
# Path: speedinfo/utils.py
# def import_class(module_path):
#     """Import class by string path.
# 
#     :param str module_path: Path to class to import (e.g. 'speedinfo.profiler.Profiler')
#     :raises ImportError: if path to class is invalid
#     :return: imported class
#     """
#     path, class_name = module_path.rsplit(".", 1)
# 
#     try:
#         module = import_module(path)
#         return getattr(module, class_name)
#     except (AttributeError, ImportError) as e:
#         msg = "Could not import '{}'. {}: {}.".format(module_path, e.__class__.__name__, e)
#         raise ImportError(msg)


from django.forms import model_to_dict
from django.test import TestCase, override_settings
from speedinfo.conf import speedinfo_settings
from speedinfo.models import ViewProfiler
from speedinfo.utils import import_class
# coding: utf-8




class StorageTestCase(object):
    @classmethod
    def setUpClass(cls):
        super(StorageTestCase, cls).setUpClass()
        cls.storage = import_class(speedinfo_settings.SPEEDINFO_STORAGE)()

    def setUp(self):
        self.storage.reset()

    def test_add(self):
        self.storage.add(
            view_name="app.view_name", method="GET", is_anon_call=True, is_cache_hit=True,
            sql_time=2, sql_count=3, view_execution_time=4,
        )
        entries = self.storage.fetch_all()

        self.assertEqual(len(entries), 1)
        self.assertDictEqual(dict(
            view_name="app.view_name", method="GET", anon_calls=1, cache_hits=1,

# Path: speedinfo/conf.py
# DEFAULTS = {
#     "SPEEDINFO_TESTS": False,
#     "SPEEDINFO_CACHED_RESPONSE_ATTR_NAME": "_is_cached",
#     "SPEEDINFO_STORAGE": None,
#     "SPEEDINFO_CACHE_STORAGE_CACHE_ALIAS": "default",
#     "SPEEDINFO_PROFILING_CONDITIONS": [],
#     "SPEEDINFO_EXCLUDE_URLS": [],
#     "SPEEDINFO_ADMIN_COLUMNS": (
#         ("View name", "{}", "view_name"),
#         ("HTTP method", "{}", "method"),
#         ("Anonymous calls", "{:.1f}%", "anon_calls_ratio"),
#         ("Cache hits", "{:.1f}%", "cache_hits_ratio"),
#         ("SQL queries per call", "{}", "sql_count_per_call"),
#         ("SQL time", "{:.1f}%", "sql_time_ratio"),
#         ("Total calls", "{}", "total_calls"),
#         ("Time per call", "{:.8f}", "time_per_call"),
#         ("Total time", "{:.4f}", "total_time"),
#     ),
# }
# class SpeedinfoSettings:
#     def __init__(self, defaults=None):
#     def __getattr__(self, name):
# 
# Path: speedinfo/models.py
# class ViewProfiler(models.Model):
#     """
#     Model doesn't have associated table in the database.
#     So don't try to use it as an ordinary ORM model. You should
#     think of it as a dataclass. Model is used for wrapping
#     storage data and Django admin integration.
#     """
#     view_name = models.CharField("View name", max_length=255)
#     method = models.CharField("HTTP method", max_length=8)
#     anon_calls = models.PositiveIntegerField("Anonymous calls", default=0)
#     cache_hits = models.PositiveIntegerField("Cache hits", default=0)
#     sql_total_time = models.FloatField("SQL total time", default=0)
#     sql_total_count = models.PositiveIntegerField("SQL total queries count", default=0)
#     total_calls = models.PositiveIntegerField("Total calls", default=0)
#     total_time = models.FloatField("Total time", default=0)
# 
#     objects = ViewProfilerQuerySet.as_manager()
# 
#     class Meta:
#         verbose_name_plural = "Views"
#         managed = False
# 
#     def __init__(self, *args, **kwargs):
#         # Extract extra fields from parameters
#         extra_fields = {}
#         model_field_names = [field.attname for field in self._meta.get_fields()]
# 
#         for field_name in list(kwargs):
#             if field_name not in model_field_names:
#                 extra_fields[field_name] = kwargs.pop(field_name)
# 
#         super(ViewProfiler, self).__init__(*args, **kwargs)
# 
#         # Assign extra fields to the object if the field names
#         # do not override existing fields
#         for field_name, value in extra_fields.items():
#             if not getattr(self, field_name, None):
#                 setattr(self, field_name, value)
# 
#     @property
#     def anon_calls_ratio(self):
#         """Anonymous calls ratio.
# 
#         :return: anonymous calls ratio percent
#         :rtype: float
#         """
#         if self.total_calls > 0:
#             return 100 * self.anon_calls / float(self.total_calls)
#         else:
#             return 0
# 
#     @property
#     def cache_hits_ratio(self):
#         """Cache hits ratio.
# 
#         :return: cache hits ratio percent
#         :rtype: float
#         """
#         if self.total_calls > 0:
#             return 100 * self.cache_hits / float(self.total_calls)
#         else:
#             return 0
# 
#     @property
#     def sql_time_ratio(self):
#         """SQL time per call ratio.
# 
#         :return: SQL time per call ratio percent
#         :rtype: float
#         """
#         if self.total_time > 0:
#             return 100 * self.sql_total_time / float(self.total_time)
#         else:
#             return 0
# 
#     @property
#     def sql_count_per_call(self):
#         """SQL queries count per call.
# 
#         :return: SQL queries count per call
#         :rtype: int
#         """
#         if self.total_calls > 0:
#             return int(round(self.sql_total_count / float(self.total_calls)))
#         else:
#             return 0
# 
#     @property
#     def time_per_call(self):
#         """Time per call.
# 
#         :return: time per call
#         :rtype: float
#         """
#         if self.total_calls > 0:
#             return self.total_time / float(self.total_calls)
#         else:
#             return 0
# 
# Path: speedinfo/utils.py
# def import_class(module_path):
#     """Import class by string path.
# 
#     :param str module_path: Path to class to import (e.g. 'speedinfo.profiler.Profiler')
#     :raises ImportError: if path to class is invalid
#     :return: imported class
#     """
#     path, class_name = module_path.rsplit(".", 1)
# 
#     try:
#         module = import_module(path)
#         return getattr(module, class_name)
#     except (AttributeError, ImportError) as e:
#         msg = "Could not import '{}'. {}: {}.".format(module_path, e.__class__.__name__, e)
#         raise ImportError(msg)


# Path: tests/test_storage.py
from django.forms import model_to_dict
from django.test import TestCase, override_settings
from speedinfo.conf import speedinfo_settings
from speedinfo.models import ViewProfiler
from speedinfo.utils import import_class

# coding: utf-8




class StorageTestCase(object):
    @classmethod
    def setUpClass(cls):
        super(StorageTestCase, cls).setUpClass()
        cls.storage = import_class(speedinfo_settings.SPEEDINFO_STORAGE)()

    def setUp(self):
        self.storage.reset()

    def test_add(self):
        self.storage.add(
            view_name="app.view_name", method="GET", is_anon_call=True, is_cache_hit=True,
            sql_time=2, sql_count=3, view_execution_time=4,
        )
        entries = self.storage.fetch_all()

        self.assertEqual(len(entries), 1)
        self.assertDictEqual(dict(
            view_name="app.view_name", method="GET", anon_calls=1, cache_hits=1,

            sql_total_time=2, sql_total_count=3, total_calls=1, total_time=4,