[Python-modules-commits] [django-hstore] 01/07: import django-hstore_1.5~alpha~git20161126+dfsg.orig.tar.gz

Scott Kitterman kitterman at moszumanska.debian.org
Sat Nov 26 23:16:51 UTC 2016


This is an automated email from the git hooks/post-receive script.

kitterman pushed a commit to branch master
in repository django-hstore.

commit b16ee57cdd3438b3d6f9e8b8302e3f5c1609d543
Author: Scott Kitterman <scott at kitterman.com>
Date:   Sat Nov 26 16:39:05 2016 -0500

    import django-hstore_1.5~alpha~git20161126+dfsg.orig.tar.gz
---
 AUTHORS                                            |  22 +
 LICENSE                                            |  42 ++
 MANIFEST.in                                        |   3 +
 PKG-INFO                                           |  68 ++
 README.rst                                         |  42 ++
 django_hstore.egg-info/PKG-INFO                    |  68 ++
 django_hstore.egg-info/SOURCES.txt                 |  48 ++
 django_hstore.egg-info/dependency_links.txt        |   1 +
 django_hstore.egg-info/not-zip-safe                |   1 +
 django_hstore.egg-info/top_level.txt               |   1 +
 django_hstore/__init__.py                          |  17 +
 django_hstore/apps.py                              |  91 +++
 django_hstore/compat.py                            |  14 +
 django_hstore/descriptors.py                       |  55 ++
 django_hstore/dict.py                              | 165 +++++
 django_hstore/exceptions.py                        |   9 +
 django_hstore/fields.py                            | 348 ++++++++++
 django_hstore/forms.py                             | 119 ++++
 django_hstore/hstore.py                            |   7 +
 django_hstore/lookups.py                           | 140 ++++
 django_hstore/managers.py                          |  41 ++
 django_hstore/models.py                            |   2 +
 django_hstore/query.py                             | 251 ++++++++
 .../static/admin/js/django_hstore/hstore-widget.js | 200 ++++++
 django_hstore/templates/hstore_default_widget.html |  65 ++
 .../templates/hstore_grappelli_widget.html         |  63 ++
 django_hstore/utils.py                             |  83 +++
 django_hstore/virtual.py                           | 171 +++++
 django_hstore/widgets.py                           |  81 +++
 setup.cfg                                          |  19 +
 setup.py                                           |  74 +++
 tests/__init__.py                                  |   0
 tests/django_hstore_tests/__init__.py              |   0
 tests/django_hstore_tests/admin.py                 |  34 +
 tests/django_hstore_tests/models.py                | 238 +++++++
 tests/django_hstore_tests/tests/__init__.py        |   0
 .../tests/test_dictionary_field.py                 | 701 +++++++++++++++++++++
 .../tests/test_gis_integration.py                  |  73 +++
 .../tests/test_not_transactional.py                |  28 +
 .../tests/test_reference_field.py                  | 192 ++++++
 .../django_hstore_tests/tests/test_schema_mode.py  | 459 ++++++++++++++
 .../tests/test_serialized_dictionary_field.py      | 460 ++++++++++++++
 tests/local_settings.py.example                    |  15 +
 tests/local_settings_psycopg.py.example            |  15 +
 tests/manage.py                                    |   9 +
 tests/settings.py                                  |  96 +++
 tests/settings_psycopg.py                          | 101 +++
 tests/urls.py                                      |  16 +
 48 files changed, 4748 insertions(+)

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..7c924fd
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,22 @@
+Current Mantainers
+------------------
+Federico Capoano    https://github.com/nemesisdesign/
+Andrei Antoukh      https://github.com/niwibe
+
+
+Original Author
+---------------
+Jordan McCoy        https://github.com/jordanm
+
+
+Contributors
+------------
+Jannis Leidel       https://github.com/jezdez
+Oliver Yu           https://github.com/oliy
+Pavel Chernykh      https://github.com/pavel-v-chernykh
+Tippr               https://github.com/Tippr
+Donald Stufft       https://github.com/dstufft
+Mikko Hellsing      https://github.com/aino
+Adieu               https://github.com/adieu
+Alexander Dinu      https://github.com/aluuu
+Anthony Lukach      http://github.com/alukach
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c58c25d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,42 @@
+Copyright (C) 2013-2014 Federico Capoano
+
+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.
+
+
+Original Author
+===============
+Copyright (C) 2011 Jordan McCoy
+
+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/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..216b19b
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,3 @@
+include AUTHORS LICENSE README.rst
+recursive-include tests *
+recursive-exclude * *.pyc *.swp
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..d93276c
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,68 @@
+Metadata-Version: 1.1
+Name: django-hstore
+Version: 1.5.alpha
+Summary: PostgreSQL HStore support for Django
+Home-page: https://github.com/djangonauts/django-hstore
+Author: Djangonauts Organization
+Author-email: django-hstore at googlegroups.com
+License: BSD
+Download-URL: https://github.com/djangonauts/django-hstore/releases
+Description: =============
+        django-hstore
+        =============
+        
+        .. image:: https://travis-ci.org/djangonauts/django-hstore.svg
+           :target: https://travis-ci.org/djangonauts/django-hstore
+        
+        .. image:: https://coveralls.io/repos/djangonauts/django-hstore/badge.svg
+          :target: https://coveralls.io/r/djangonauts/django-hstore
+        
+        .. image:: https://requires.io/github/djangonauts/django-hstore/requirements.svg?branch=master
+           :target: https://requires.io/github/djangonauts/django-hstore/requirements/?branch=master
+           :alt: Requirements Status
+        
+        .. image:: https://badge.fury.io/py/django-hstore.svg
+            :target: https://pypi.python.org/pypi/django-hstore
+        
+        .. image:: https://img.shields.io/pypi/dm/django-hstore.svg
+           :target: https://pypi.python.org/pypi/django-hstore
+        
+        ------------
+        
+        You need **dynamic columns** in your tables. What do you do?
+        
+        - Create lots of tables to handle it. Nice, now you’ll need more models and lots of additional sqls. Insertion and selection will be slow as hell.
+        - Use a **noSQL** database just for this issue. **Good luck**.
+        - Create a serialized column. Nice, insertion will be fine, and reading data from a record too. But, what if you have a condition in your select that includes serialized data? Yeah, regular expressions.
+        
+        ------------
+        
+        Documentation_ - `Mailing List`_
+        
+        .. _Documentation: http://djangonauts.github.io/django-hstore/
+        .. _`Mailing List`: https://groups.google.com/forum/#!forum/django-hstore
+        
+        ------------
+        
+        Projects using this package
+        ---------------------------
+        
+        - `django-rest-framework-hstore <https://github.com/djangonauts/django-rest-framework-hstore>`__: **django-rest-framework** tools for **django-hstore**
+        - `Nodeshot <https://github.com/ninuxorg/nodeshot>`__: extensible django web application for management of community-led georeferenced data - some features of **django-hstore**, like the ``schema-mode`` have been developed for this project
+        
+Keywords: django,hstore,schemaless
+Platform: Platform Indipendent
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Framework :: Django
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..b8d5cac
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,42 @@
+=============
+django-hstore
+=============
+
+.. image:: https://travis-ci.org/djangonauts/django-hstore.svg
+   :target: https://travis-ci.org/djangonauts/django-hstore
+
+.. image:: https://coveralls.io/repos/djangonauts/django-hstore/badge.svg
+  :target: https://coveralls.io/r/djangonauts/django-hstore
+
+.. image:: https://requires.io/github/djangonauts/django-hstore/requirements.svg?branch=master
+   :target: https://requires.io/github/djangonauts/django-hstore/requirements/?branch=master
+   :alt: Requirements Status
+
+.. image:: https://badge.fury.io/py/django-hstore.svg
+    :target: https://pypi.python.org/pypi/django-hstore
+
+.. image:: https://img.shields.io/pypi/dm/django-hstore.svg
+   :target: https://pypi.python.org/pypi/django-hstore
+
+------------
+
+You need **dynamic columns** in your tables. What do you do?
+
+- Create lots of tables to handle it. Nice, now you’ll need more models and lots of additional sqls. Insertion and selection will be slow as hell.
+- Use a **noSQL** database just for this issue. **Good luck**.
+- Create a serialized column. Nice, insertion will be fine, and reading data from a record too. But, what if you have a condition in your select that includes serialized data? Yeah, regular expressions.
+
+------------
+
+Documentation_ - `Mailing List`_
+
+.. _Documentation: http://djangonauts.github.io/django-hstore/
+.. _`Mailing List`: https://groups.google.com/forum/#!forum/django-hstore
+
+------------
+
+Projects using this package
+---------------------------
+
+- `django-rest-framework-hstore <https://github.com/djangonauts/django-rest-framework-hstore>`__: **django-rest-framework** tools for **django-hstore**
+- `Nodeshot <https://github.com/ninuxorg/nodeshot>`__: extensible django web application for management of community-led georeferenced data - some features of **django-hstore**, like the ``schema-mode`` have been developed for this project
diff --git a/django_hstore.egg-info/PKG-INFO b/django_hstore.egg-info/PKG-INFO
new file mode 100644
index 0000000..d93276c
--- /dev/null
+++ b/django_hstore.egg-info/PKG-INFO
@@ -0,0 +1,68 @@
+Metadata-Version: 1.1
+Name: django-hstore
+Version: 1.5.alpha
+Summary: PostgreSQL HStore support for Django
+Home-page: https://github.com/djangonauts/django-hstore
+Author: Djangonauts Organization
+Author-email: django-hstore at googlegroups.com
+License: BSD
+Download-URL: https://github.com/djangonauts/django-hstore/releases
+Description: =============
+        django-hstore
+        =============
+        
+        .. image:: https://travis-ci.org/djangonauts/django-hstore.svg
+           :target: https://travis-ci.org/djangonauts/django-hstore
+        
+        .. image:: https://coveralls.io/repos/djangonauts/django-hstore/badge.svg
+          :target: https://coveralls.io/r/djangonauts/django-hstore
+        
+        .. image:: https://requires.io/github/djangonauts/django-hstore/requirements.svg?branch=master
+           :target: https://requires.io/github/djangonauts/django-hstore/requirements/?branch=master
+           :alt: Requirements Status
+        
+        .. image:: https://badge.fury.io/py/django-hstore.svg
+            :target: https://pypi.python.org/pypi/django-hstore
+        
+        .. image:: https://img.shields.io/pypi/dm/django-hstore.svg
+           :target: https://pypi.python.org/pypi/django-hstore
+        
+        ------------
+        
+        You need **dynamic columns** in your tables. What do you do?
+        
+        - Create lots of tables to handle it. Nice, now you’ll need more models and lots of additional sqls. Insertion and selection will be slow as hell.
+        - Use a **noSQL** database just for this issue. **Good luck**.
+        - Create a serialized column. Nice, insertion will be fine, and reading data from a record too. But, what if you have a condition in your select that includes serialized data? Yeah, regular expressions.
+        
+        ------------
+        
+        Documentation_ - `Mailing List`_
+        
+        .. _Documentation: http://djangonauts.github.io/django-hstore/
+        .. _`Mailing List`: https://groups.google.com/forum/#!forum/django-hstore
+        
+        ------------
+        
+        Projects using this package
+        ---------------------------
+        
+        - `django-rest-framework-hstore <https://github.com/djangonauts/django-rest-framework-hstore>`__: **django-rest-framework** tools for **django-hstore**
+        - `Nodeshot <https://github.com/ninuxorg/nodeshot>`__: extensible django web application for management of community-led georeferenced data - some features of **django-hstore**, like the ``schema-mode`` have been developed for this project
+        
+Keywords: django,hstore,schemaless
+Platform: Platform Indipendent
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Framework :: Django
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
diff --git a/django_hstore.egg-info/SOURCES.txt b/django_hstore.egg-info/SOURCES.txt
new file mode 100644
index 0000000..4da780b
--- /dev/null
+++ b/django_hstore.egg-info/SOURCES.txt
@@ -0,0 +1,48 @@
+AUTHORS
+LICENSE
+MANIFEST.in
+README.rst
+setup.cfg
+setup.py
+django_hstore/__init__.py
+django_hstore/apps.py
+django_hstore/compat.py
+django_hstore/descriptors.py
+django_hstore/dict.py
+django_hstore/exceptions.py
+django_hstore/fields.py
+django_hstore/forms.py
+django_hstore/hstore.py
+django_hstore/lookups.py
+django_hstore/managers.py
+django_hstore/models.py
+django_hstore/query.py
+django_hstore/utils.py
+django_hstore/virtual.py
+django_hstore/widgets.py
+django_hstore.egg-info/PKG-INFO
+django_hstore.egg-info/SOURCES.txt
+django_hstore.egg-info/dependency_links.txt
+django_hstore.egg-info/not-zip-safe
+django_hstore.egg-info/top_level.txt
+django_hstore/static/admin/js/django_hstore/hstore-widget.js
+django_hstore/static/admin/js/django_hstore/underscore-min.js
+django_hstore/templates/hstore_default_widget.html
+django_hstore/templates/hstore_grappelli_widget.html
+tests/__init__.py
+tests/local_settings.py.example
+tests/local_settings_psycopg.py.example
+tests/manage.py
+tests/settings.py
+tests/settings_psycopg.py
+tests/urls.py
+tests/django_hstore_tests/__init__.py
+tests/django_hstore_tests/admin.py
+tests/django_hstore_tests/models.py
+tests/django_hstore_tests/tests/__init__.py
+tests/django_hstore_tests/tests/test_dictionary_field.py
+tests/django_hstore_tests/tests/test_gis_integration.py
+tests/django_hstore_tests/tests/test_not_transactional.py
+tests/django_hstore_tests/tests/test_reference_field.py
+tests/django_hstore_tests/tests/test_schema_mode.py
+tests/django_hstore_tests/tests/test_serialized_dictionary_field.py
\ No newline at end of file
diff --git a/django_hstore.egg-info/dependency_links.txt b/django_hstore.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/django_hstore.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/django_hstore.egg-info/not-zip-safe b/django_hstore.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/django_hstore.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/django_hstore.egg-info/top_level.txt b/django_hstore.egg-info/top_level.txt
new file mode 100644
index 0000000..6f8c57e
--- /dev/null
+++ b/django_hstore.egg-info/top_level.txt
@@ -0,0 +1 @@
+django_hstore
diff --git a/django_hstore/__init__.py b/django_hstore/__init__.py
new file mode 100644
index 0000000..b022dee
--- /dev/null
+++ b/django_hstore/__init__.py
@@ -0,0 +1,17 @@
+VERSION = (1, 5, 0, 'alpha')
+__version__ = VERSION
+
+
+def get_version():
+    version = '%s.%s' % (VERSION[0], VERSION[1])
+    if VERSION[2]:
+        version = '%s.%s' % (version, VERSION[2])
+    if VERSION[3:] == ('alpha', 0):
+        version = '%s pre-alpha' % version
+    else:
+        if VERSION[3] != 'final':
+            version = '%s %s' % (version, VERSION[3])
+    return version
+
+
+default_app_config = 'django_hstore.apps.HStoreConfig'
diff --git a/django_hstore/apps.py b/django_hstore/apps.py
new file mode 100644
index 0000000..c7f8da6
--- /dev/null
+++ b/django_hstore/apps.py
@@ -0,0 +1,91 @@
+import sys
+
+import django
+from django.conf import settings
+from django.db.backends.signals import connection_created
+from django.apps import AppConfig
+
+from psycopg2.extras import register_hstore
+
+
+HSTORE_REGISTER_GLOBALLY = getattr(settings, "DJANGO_HSTORE_ADAPTER_REGISTRATION", "global") == "global"
+CONNECTION_CREATED_SIGNAL_WEAKREF = bool(getattr(settings, "DJANGO_HSTORE_ADAPTER_SIGNAL_WEAKREF", False))
+
+# This allows users that introduce hstore into an existing
+# environment to disable global registration of the hstore adapter
+# in order to avoid unpredictable behavior when having hstore installed individually
+# on each database instead of on having it installed on template1.
+
+# Check if GEODJANGO is being used
+GEODJANGO_INSTALLED = False
+
+for database in settings.DATABASES.values():
+    if 'postgis' in database.get('ENGINE'):
+        GEODJANGO_INSTALLED = True
+        break
+
+
+class ConnectionCreateHandler(object):
+    """
+    Generic connection handlers manager.
+    Executes attached functions when connection is created.
+    With possibility of attaching single execution methods.
+    """
+    generic_handlers = []
+    unique_handlers = []
+
+    def __call__(self, sender, connection, **kwargs):
+        handlers = set()
+
+        if len(self.unique_handlers) > 0:
+            handlers.update(self.unique_handlers)
+            self.unique_handlers = []
+
+        handlers.update(self.generic_handlers)
+
+        # List comprehension is used instead of for statement
+        # only for performance.
+        return [x(connection) for x in handlers]
+
+    def attach_handler(self, func, vendor=None, unique=False):
+        if unique:
+            self.unique_handlers.append(func)
+        else:
+            self.generic_handlers.append(func)
+
+connection_handler = ConnectionCreateHandler()
+
+
+def register_hstore_handler(connection, **kwargs):
+    # do not register hstore if DB is not postgres
+    # do not register if HAS_HSTORE flag is set to false
+    if connection.vendor != 'postgresql' or \
+       connection.settings_dict.get('HAS_HSTORE', True) is False:
+        return
+    # if the ``NAME`` of the database in the connection settings is ``None``
+    # defer hstore registration by setting up a new unique handler
+    if connection.settings_dict['NAME'] is None:
+        connection_handler.attach_handler(register_hstore_handler,
+                                          vendor="postgresql",
+                                          unique=HSTORE_REGISTER_GLOBALLY)
+        return
+
+    if sys.version_info[0] < 3:
+        register_hstore(connection.connection, globally=HSTORE_REGISTER_GLOBALLY, unicode=True)
+    else:
+        register_hstore(connection.connection, globally=HSTORE_REGISTER_GLOBALLY)
+
+
+connection_handler.attach_handler(register_hstore_handler,
+                                  vendor="postgresql",
+                                  unique=HSTORE_REGISTER_GLOBALLY)
+
+
+class HStoreConfig(AppConfig):
+    name = 'django_hstore'
+    verbose = 'Django HStore'
+
+    def ready(self):
+        connection_created.connect(connection_handler,
+                                   weak=CONNECTION_CREATED_SIGNAL_WEAKREF,
+                                   dispatch_uid="_connection_create_handler")
diff --git a/django_hstore/compat.py b/django_hstore/compat.py
new file mode 100644
index 0000000..3b595b3
--- /dev/null
+++ b/django_hstore/compat.py
@@ -0,0 +1,14 @@
+import sys
+
+
+class UnicodeMixin(object):
+    """
+    Mixin class to handle defining the proper __str__/__unicode__
+    methods in Python 2 or 3.
+    """
+    if sys.version_info[0] >= 3:  # Python 3
+        def __str__(self):
+            return self.__unicode__()
+    else:  # Python 2
+        def __str__(self):
+            return self.__unicode__().encode('utf8')
diff --git a/django_hstore/descriptors.py b/django_hstore/descriptors.py
new file mode 100644
index 0000000..14f6f69
--- /dev/null
+++ b/django_hstore/descriptors.py
@@ -0,0 +1,55 @@
+from .dict import HStoreDict, HStoreReferenceDict
+
+__all__ = [
+    'HStoreDescriptor',
+    'HStoreReferenceDescriptor',
+    'SerializedDictDescriptor'
+]
+
+
+class Creator(object):
+    """
+    A placeholder class that provides a way to set the attribute on the model.
+    """
+    def __init__(self, field):
+        self.field = field
+
+    def __get__(self, obj, type=None):
+        if obj is None:
+            return self
+        return obj.__dict__[self.field.name]
+
+    def __set__(self, obj, value):
+        obj.__dict__[self.field.name] = self.field.to_python(value)
+
+
+class HStoreDescriptor(Creator):
+    _DictClass = HStoreDict
+
+    def __init__(self, *args, **kwargs):
+        self.schema_mode = kwargs.pop('schema_mode', False)
+        super(HStoreDescriptor, self).__init__(*args, **kwargs)
+
+    def __set__(self, obj, value):
+        value = self.field.to_python(value)
+        if isinstance(value, dict):
+            value = self._DictClass(
+                value=value, field=self.field, instance=obj, schema_mode=self.schema_mode
+            )
+        obj.__dict__[self.field.name] = value
+
+
+class SerializedDictDescriptor(Creator):
+    _DictClass = dict
+
+    def __set__(self, obj, value):
+        # Deserialization is only needed when retrieving data from DB
+        # (not when field is being set via assignment (`x.data = {...}`)
+        # or via the `.create()` method.
+        if value and self.field._from_db(obj):
+            value = self.field.to_python(value)
+        obj.__dict__[self.field.name] = value
+
+
+class HStoreReferenceDescriptor(HStoreDescriptor):
+    _DictClass = HStoreReferenceDict
diff --git a/django_hstore/dict.py b/django_hstore/dict.py
new file mode 100644
index 0000000..16efc34
--- /dev/null
+++ b/django_hstore/dict.py
@@ -0,0 +1,165 @@
+import json
+
+from decimal import Decimal
+
+from django.utils import six
+from django.utils.encoding import force_text, force_str
+
+from .compat import UnicodeMixin
+from . import utils, exceptions
+
+
+__all__ = [
+    'HStoreDict',
+    'HStoreReferenceDict',
+]
+
+
+class DecimalEncoder(json.JSONEncoder):
+    def default(self, obj):
+        if isinstance(obj, Decimal):
+            return float(obj)
+        return json.JSONEncoder.default(self, obj)
+
+
+class HStoreDict(UnicodeMixin, dict):
+    """
+    A dictionary subclass which implements hstore support.
+    """
+    schema_mode = False  # python2.6 compatibility
+
+    def __init__(self, value=None, field=None, instance=None, schema_mode=False, **kwargs):
+        self.schema_mode = schema_mode
+
+        # if passed value is string
+        # ensure is json formatted
+        if isinstance(value, six.string_types):
+            try:
+                value = json.loads(value)
+            except ValueError as e:
+                raise exceptions.HStoreDictException(
+                    'HStoreDict accepts only valid json formatted strings.',
+                    json_error_message=force_text(e)
+                )
+        elif value is None:
+            value = {}
+
+        # allow dictionaries only
+        if not isinstance(value, dict):
+            raise exceptions.HStoreDictException(
+                'HStoreDict accepts only dictionary objects, None and json formatted string representations of json objects'
+            )
+
+        if not self.schema_mode:
+            # ensure values are acceptable
+            for key, val in value.items():
+                value[key] = self.ensure_acceptable_value(val)
+
+        super(HStoreDict, self).__init__(value, **kwargs)
+        self.field = field
+        self.instance = instance
+
+    def __setitem__(self, *args, **kwargs):
+        """
+        perform checks before setting the value of a key
+        """
+        # ensure values are acceptable
+        value = self.ensure_acceptable_value(args[1])
+        # prepare *args
+        args = (args[0], value)
+        super(HStoreDict, self).__setitem__(*args, **kwargs)
+
+    def __getitem__(self, *args, **kwargs):
+        """
+        retrieve value preserving type if in schema mode, string only otherwise
+        """
+        value = super(HStoreDict, self).__getitem__(*args, **kwargs)
+
+        if self.schema_mode:
+            try:
+                return self.instance._hstore_virtual_fields[args[0]].to_python(value)
+            except KeyError:
+                pass
+
+        return value
+
+    def get(self, *args):
+        key = args[0]
+        try:
+            return self.__getitem__(key)
+        except KeyError:
+            if len(args) > 1:
+                return args[1]  # return default value
+            else:
+                return None
+
+    # This method is used both for python3 and python2
+    # thanks to UnicodeMixin
+    def __unicode__(self):
+        return force_text(json.dumps(self))
+
+    def __getstate__(self):
+        return self.__dict__
+
+    def __copy__(self):
+        return self.__class__(self, self.field)
+
+    def update(self, *args, **kwargs):
+        for key, value in dict(*args, **kwargs).items():
+            self[key] = value
+
+    def ensure_acceptable_value(self, value):
+        """
+        if schema_mode disabled (default behaviour):
+            - ensure booleans, integers, floats, Decimals, lists and dicts are
+              converted to string
+            - convert True and False objects to "true" and "false" so they can be
+              decoded back with the json library if needed
+            - convert lists and dictionaries to json formatted strings
+            - leave alone all other objects because they might be representation of django models
+        else:
+            - encode utf8 strings in python2
+            - convert to string
+        """
+        if not self.schema_mode:
+            if isinstance(value, bool):
+                return force_text(value).lower()
+            elif isinstance(value, six.integer_types + (float, Decimal)):
+                return force_text(value)
+            elif isinstance(value, (list, dict)):
+                return force_text(json.dumps(value, cls=DecimalEncoder))
+            else:
+                return value
+        else:
+            # perform string conversion unless is None
+            if value is not None:
+                value = force_str(value)
+            return value
+
+    def remove(self, keys):
+        """
+        Removes the specified keys from this dictionary.
+        """
+        queryset = self.instance._base_manager.get_query_set()
+        queryset.filter(pk=self.instance.pk).hremove(self.field.name, keys)
+
+
+class HStoreReferenceDict(HStoreDict):
+    """
+    A dictionary which adds support to storing references to models
+    """
+    def __getitem__(self, *args, **kwargs):
+        value = super(self.__class__, self).__getitem__(*args, **kwargs)
+        # if value is a string it needs to be converted to model instance
+        if isinstance(value, six.string_types):
+            reference = utils.acquire_reference(value)
+            self.__setitem__(args[0], reference)
+            return reference
+        # otherwise just return the relation
+        return value
+
+    def get(self, key, default=None):
+        try:
+            return self.__getitem__(key)
+        except KeyError:
+            return default
diff --git a/django_hstore/exceptions.py b/django_hstore/exceptions.py
new file mode 100644
index 0000000..2c4eea1
--- /dev/null
+++ b/django_hstore/exceptions.py
@@ -0,0 +1,9 @@
+from __future__ import unicode_literals, absolute_import
+
+
+class HStoreDictException(Exception):
+    json_error_message = None
+
+    def __init__(self, *args, **kwargs):
+        self.json_error_message = kwargs.pop('json_error_message', None)
+        super(HStoreDictException, self).__init__(*args, **kwargs)
diff --git a/django_hstore/fields.py b/django_hstore/fields.py
new file mode 100644
index 0000000..d4fd146
--- /dev/null
+++ b/django_hstore/fields.py
@@ -0,0 +1,348 @@
+from __future__ import absolute_import, unicode_literals
+
+import datetime
+import json
+
+import django
+from django.db import models
+from django.utils import six
+from django.utils.translation import ugettext_lazy as _
+
+from . import forms, utils
+from .descriptors import HStoreDescriptor, HStoreReferenceDescriptor, SerializedDictDescriptor
+from .dict import HStoreDict, HStoreReferenceDict
+from .virtual import create_hstore_virtual_field
+
+
+class HStoreField(models.Field):
+    """ HStore Base Field """
+
+    def __init_dict(self, value):
+        """
+        initializes HStoreDict
+        """
+        return HStoreDict(value, self)
+
+    def validate(self, value, *args):
+        super(HStoreField, self).validate(value, *args)
+        forms.validate_hstore(value, is_serialized=hasattr(self, 'serializer'))
+
+    def contribute_to_class(self, cls, name):
+        super(HStoreField, self).contribute_to_class(cls, name)
+        setattr(cls, self.name, HStoreDescriptor(self))
+
+    def get_default(self):
+        """
+        Returns the default value for this field.
+        """
+        # if default defined
+        if self.has_default():
+            # if default is callable
+            if callable(self.default):
+                return self.__init_dict(self.default())
+            # if it's a dict
+            elif isinstance(self.default, dict):
+                return self.__init_dict(self.default)
+            # else just return it
+            return self.default
+        # default to empty dict
+        return self.__init_dict({})
+
+    def get_prep_value(self, value):
+        if isinstance(value, dict) and not isinstance(value, HStoreDict):
+            return self.__init_dict(value)
+        else:
+            return value
+
+    def get_db_prep_value(self, value, connection, prepared=False):
+        if not prepared:
+            value = self.get_prep_value(value)
+        return value
+
+    def value_to_string(self, obj):
+        return self._get_val_from_obj(obj)
+
+    def db_type(self, connection=None):
+        return 'hstore'
+
+    def south_field_triple(self):  # pragma no cover
+        from south.modelsinspector import introspector
+        name = '%s.%s' % (self.__class__.__module__, self.__class__.__name__)
+        args, kwargs = introspector(self)
+        return name, args, kwargs
+
+
+if django.VERSION >= (1, 7):
+    from .lookups import (HStoreGreaterThan, HStoreGreaterThanOrEqual, HStoreLessThan,
+                          HStoreLessThanOrEqual, HStoreContains, HStoreIContains, HStoreIsNull)
+
+    HStoreField.register_lookup(HStoreGreaterThan)
+    HStoreField.register_lookup(HStoreGreaterThanOrEqual)
+    HStoreField.register_lookup(HStoreLessThan)
+    HStoreField.register_lookup(HStoreLessThanOrEqual)
+    HStoreField.register_lookup(HStoreContains)
+    HStoreField.register_lookup(HStoreIContains)
+    HStoreField.register_lookup(HStoreIsNull)
+
+
+class DictionaryField(HStoreField):
+    description = _("A python dictionary in a postgresql hstore field.")
+
+    def __init__(self, *args, **kwargs):
+        self.schema = kwargs.pop('schema', None)
+        self.schema_mode = False
+        # if schema parameter is supplied the behaviour is slightly different
+        if self.schema is not None:
+            self._validate_schema(self.schema)
+            self.schema_mode = True
+            # DictionaryField with schema is not editable via admin
+            kwargs['editable'] = False
+            # null defaults to True to facilitate migrations
+            kwargs['null'] = kwargs.get('null', True)
+
+        super(DictionaryField, self).__init__(*args, **kwargs)
+
+    def __init_dict(self, value):
+        """
+        init HStoreDict
+        pass schema_mode=True if in "schema" mode
+        """
+        return HStoreDict(value, self, schema_mode=self.schema_mode)
+
+    def contribute_to_class(self, cls, name):
+        super(DictionaryField, self).contribute_to_class(cls, name)
+        setattr(cls, self.name, HStoreDescriptor(self, schema_mode=self.schema_mode))
+
+        if self.schema:
+            self._create_hstore_virtual_fields(cls, name)
+
+    def formfield(self, **kwargs):
+        kwargs['form_class'] = forms.DictionaryField
+        return super(DictionaryField, self).formfield(**kwargs)
+
+    def _value_to_python(self, value):
+        return value
+
+    def south_field_triple(self):  # pragma no cover
+        name, args, kwargs = super(DictionaryField, self).south_field_triple()
+        # if schema mode replace the default value {} with None as {} would break south
+        if self.schema_mode:
+            kwargs['default'] = None
+        return name, args, kwargs
+
+    def _validate_schema(self, schema):
+        if not isinstance(schema, list):
+            raise ValueError('schema parameter must be a list')
+
+        if len(schema) == 0:
+            raise ValueError('schema parameter cannot be an empty list')
+
+        for field in schema:
+            if not isinstance(field, dict):
+                raise ValueError('schema parameter must contain dicts representing fields, read the docs to see the format')
+            if 'name' not in field:
+                raise ValueError('schema element %s is missing the name key' % field)
+            if 'class' not in field:
+                raise ValueError('schema element %s is missing the class key' % field)
+
+    def _create_hstore_virtual_fields(self, cls, hstore_field_name):
+        """
+        this methods creates all the virtual fields automatically by reading the schema attribute
+        """
+        if not self.schema and self.schema_mode is False:
+            return
+        # add hstore_virtual_fields attribute to class
+        if not hasattr(cls, '_hstore_virtual_fields'):
+            cls._hstore_virtual_fields = {}
+        # loop over all fields defined in schema
+        for field in self.schema:
+            # initialize the virtual field by specifying the class, the kwargs and the hstore field name
+            virtual_field = create_hstore_virtual_field(field['class'],
+                                                        field.get('kwargs', {}),
+                                                        hstore_field_name)
+            # this will call the contribute_to_class method in virtual.HStoreVirtualMixin
+            cls.add_to_class(field['name'], virtual_field)
+            # add this field to hstore_virtual_fields dict
+            cls._hstore_virtual_fields[field['name']] = virtual_field
+
+    def reload_schema(self, schema):
+        """
+        Reload schema arbitrarily at run-time
+        """
+        if schema:
+            self._validate_schema(schema)
+            self.schema = schema
+            self.schema_mode = True
+            self.editable = False
+        else:
+            self.schema = None
+            self.schema_mode = False
+            self.editable = True
+        # remove any existing virtual field
+        self._remove_hstore_virtual_fields()
+        # set new descriptor on model class
+        setattr(self.model, self.name, HStoreDescriptor(self, schema_mode=self.schema_mode))
+        # create virtual fields
+        self._create_hstore_virtual_fields(self.model, self.name)
+
+    def _remove_hstore_virtual_fields(self):
+        """ remove hstore virtual fields from class """
+        cls = self.model
+        # remove all hstore virtual fields related attributes
+        if hasattr(cls, '_hstore_virtual_fields'):
+            # remove attributes from class
+            for field_name in cls._hstore_virtual_fields.keys():
... 4084 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-hstore.git



More information about the Python-modules-commits mailing list