• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SectorLabs / django-postgres-extra / aa311641-5906-49cd-842a-2a4de96f7145

18 Jun 2024 11:26AM UTC coverage: 91.023% (-0.1%) from 91.138%
aa311641-5906-49cd-842a-2a4de96f7145

push

circleci

Photonios
Fix automatic hstore extension creation not working on Django 4.2 or newer

The following change broke the auto setup:
https://github.com/django/django/commit/d3e746ace

This breaks because the call to `pscygop2.extras.register_hstore` is now
conditional. Before, it would be called multiple times with
empty OIDS, when eventually our auto registration would kick
in and psycopg2 would fetch the OIDs itself.

5 of 8 new or added lines in 1 file covered. (62.5%)

1815 of 1994 relevant lines covered (91.02%)

0.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.09
/psqlextra/backend/base.py
1
import logging
1✔
2

3
from typing import TYPE_CHECKING
1✔
4

5
from django.conf import settings
1✔
6
from django.contrib.postgres.signals import (
1✔
7
    get_hstore_oids,
8
    register_type_handlers,
9
)
10
from django.db import ProgrammingError
1✔
11

12
from . import base_impl
1✔
13
from .introspection import PostgresIntrospection
1✔
14
from .operations import PostgresOperations
1✔
15
from .schema import PostgresSchemaEditor
1✔
16

17
from django.db.backends.postgresql.base import (  # isort:skip
1✔
18
    DatabaseWrapper as PostgresDatabaseWrapper,
19
)
20

21

22
logger = logging.getLogger(__name__)
1✔
23

24

25
if TYPE_CHECKING:
1✔
26

27
    class Wrapper(PostgresDatabaseWrapper):
×
28
        pass
×
29

30
else:
31
    Wrapper = base_impl.backend()
1✔
32

33

34
class DatabaseWrapper(Wrapper):
1✔
35
    """Wraps the standard PostgreSQL database back-end.
36

37
    Overrides the schema editor with our custom schema editor and makes
38
    sure the `hstore` extension is enabled.
39
    """
40

41
    SchemaEditorClass = PostgresSchemaEditor  # type: ignore[assignment]
1✔
42
    introspection_class = PostgresIntrospection
1✔
43
    ops_class = PostgresOperations
1✔
44

45
    def __init__(self, *args, **kwargs):
1✔
46
        super().__init__(*args, **kwargs)
1✔
47

48
        # Some base back-ends such as the PostGIS back-end don't properly
49
        # set `ops_class` and `introspection_class` and initialize these
50
        # classes themselves.
51
        #
52
        # This can lead to broken functionality. We fix this automatically.
53

54
        if not isinstance(self.introspection, self.introspection_class):
1✔
55
            self.introspection = self.introspection_class(self)
×
56

57
        if not isinstance(self.ops, self.ops_class):
1✔
58
            self.ops = self.ops_class(self)
×
59

60
        for expected_compiler_class in self.ops.compiler_classes:
1✔
61
            compiler_class = self.ops.compiler(expected_compiler_class.__name__)
1✔
62

63
            if not issubclass(compiler_class, expected_compiler_class):
1✔
64
                logger.warning(
×
65
                    "Compiler '%s.%s' is not properly deriving from '%s.%s'."
66
                    % (
67
                        compiler_class.__module__,
68
                        compiler_class.__name__,
69
                        expected_compiler_class.__module__,
70
                        expected_compiler_class.__name__,
71
                    )
72
                )
73

74
    def prepare_database(self):
1✔
75
        """Ran to prepare the configured database.
76

77
        This is where we enable the `hstore` extension if it wasn't
78
        enabled yet.
79
        """
80

81
        super().prepare_database()
1✔
82

83
        setup_ext = getattr(
1✔
84
            settings, "POSTGRES_EXTRA_AUTO_EXTENSION_SET_UP", True
85
        )
86
        if not setup_ext:
1✔
87
            return False
×
88

89
        with self.cursor() as cursor:
1✔
90
            try:
1✔
91
                cursor.execute("CREATE EXTENSION IF NOT EXISTS hstore")
1✔
92
            except ProgrammingError:  # permission denied
×
93
                logger.warning(
×
94
                    'Failed to create "hstore" extension. '
95
                    "Tables with hstore columns may fail to migrate. "
96
                    "If hstore is needed, make sure you are connected "
97
                    "to the database as a superuser "
98
                    "or add the extension manually.",
99
                    exc_info=True,
100
                )
NEW
101
                return
×
102

103
        # Clear old (non-existent), stale oids.
104
        get_hstore_oids.cache_clear()
1✔
105

106
        # Verify that we (and Django) can find the OIDs
107
        # for hstore.
108
        oids, _ = get_hstore_oids(self.alias)
1✔
109
        if not oids:
1✔
NEW
110
            logger.warning(
×
111
                '"hstore" extension was created, but we cannot find the oids'
112
                "in the database. Something went wrong.",
113
            )
NEW
114
            return
×
115

116
        # We must trigger Django into registering the type handlers now
117
        # so that any subsequent code can properly use the newly
118
        # registered types.
119
        register_type_handlers(self)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc