django-spire 0.16.12__py3-none-any.whl → 0.16.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. django_spire/ai/admin.py +3 -1
  2. django_spire/ai/apps.py +2 -0
  3. django_spire/ai/chat/admin.py +15 -9
  4. django_spire/ai/chat/apps.py +4 -1
  5. django_spire/ai/chat/auth/controller.py +3 -1
  6. django_spire/ai/chat/choices.py +2 -0
  7. django_spire/ai/chat/intelligence/maps/intent_llm_map.py +8 -5
  8. django_spire/ai/chat/intelligence/prompts.py +4 -2
  9. django_spire/ai/chat/intelligence/workflows/chat_workflow.py +27 -28
  10. django_spire/ai/chat/message_intel.py +7 -4
  11. django_spire/ai/chat/models.py +8 -9
  12. django_spire/ai/chat/querysets.py +3 -1
  13. django_spire/ai/chat/responses.py +19 -10
  14. django_spire/ai/chat/tools.py +20 -15
  15. django_spire/ai/chat/urls/message_urls.py +2 -1
  16. django_spire/ai/chat/urls/page_urls.py +1 -0
  17. django_spire/ai/chat/views/message_request_views.py +2 -0
  18. django_spire/ai/chat/views/message_response_views.py +4 -4
  19. django_spire/ai/chat/views/message_views.py +2 -0
  20. django_spire/ai/chat/views/page_views.py +7 -2
  21. django_spire/ai/chat/views/template_views.py +2 -0
  22. django_spire/ai/decorators.py +13 -7
  23. django_spire/ai/mixins.py +4 -2
  24. django_spire/ai/models.py +7 -2
  25. django_spire/ai/prompt/bots.py +14 -32
  26. django_spire/ai/prompt/intel.py +1 -1
  27. django_spire/ai/prompt/prompts.py +7 -1
  28. django_spire/ai/prompt/system/bots.py +42 -75
  29. django_spire/ai/prompt/system/intel.py +5 -4
  30. django_spire/ai/prompt/system/prompts.py +5 -1
  31. django_spire/ai/prompt/system/system_prompt_cli.py +15 -9
  32. django_spire/ai/prompt/tests/test_bots.py +14 -11
  33. django_spire/ai/prompt/text_to_prompt_cli.py +5 -2
  34. django_spire/ai/prompt/tuning/bot_tuning_cli.py +14 -13
  35. django_spire/ai/prompt/tuning/bots.py +68 -116
  36. django_spire/ai/prompt/tuning/intel.py +1 -1
  37. django_spire/ai/prompt/tuning/mixins.py +2 -0
  38. django_spire/ai/prompt/tuning/prompt_tuning_cli.py +8 -8
  39. django_spire/ai/prompt/tuning/prompts.py +4 -2
  40. django_spire/ai/sms/admin.py +3 -1
  41. django_spire/ai/sms/apps.py +2 -0
  42. django_spire/ai/sms/decorators.py +2 -0
  43. django_spire/ai/sms/intel.py +4 -2
  44. django_spire/ai/sms/intelligence/workflows/sms_conversation_workflow.py +8 -8
  45. django_spire/ai/sms/models.py +16 -14
  46. django_spire/ai/sms/querysets.py +4 -1
  47. django_spire/ai/sms/tools.py +18 -16
  48. django_spire/ai/sms/urls.py +1 -1
  49. django_spire/ai/sms/views.py +2 -0
  50. django_spire/ai/tests/test_ai.py +3 -5
  51. django_spire/ai/urls.py +1 -0
  52. django_spire/consts.py +1 -1
  53. django_spire/contrib/seeding/field/django/seeder.py +6 -4
  54. django_spire/contrib/seeding/field/llm.py +1 -2
  55. django_spire/contrib/seeding/intelligence/bots/field_seeding_bots.py +7 -8
  56. django_spire/contrib/seeding/intelligence/bots/seeder_generator_bot.py +15 -16
  57. django_spire/contrib/seeding/intelligence/intel.py +1 -1
  58. django_spire/contrib/seeding/intelligence/prompts/factory.py +5 -7
  59. django_spire/contrib/seeding/intelligence/prompts/foreign_key_selection_prompt.py +3 -5
  60. django_spire/contrib/seeding/intelligence/prompts/generate_django_model_seeder_prompts.py +1 -2
  61. django_spire/contrib/seeding/intelligence/prompts/generic_relationship_selection_prompt.py +3 -5
  62. django_spire/contrib/seeding/intelligence/prompts/hierarchical_selection_prompt.py +1 -1
  63. django_spire/contrib/seeding/intelligence/prompts/model_field_choices_prompt.py +3 -3
  64. django_spire/contrib/seeding/intelligence/prompts/negation_prompt.py +1 -1
  65. django_spire/contrib/seeding/intelligence/prompts/objective_prompt.py +2 -4
  66. django_spire/contrib/seeding/management/commands/seeding.py +5 -2
  67. django_spire/contrib/seeding/model/base.py +12 -10
  68. django_spire/contrib/seeding/model/django/seeder.py +13 -10
  69. django_spire/contrib/seeding/tests/test_seeding.py +1 -1
  70. django_spire/knowledge/admin.py +2 -0
  71. django_spire/knowledge/apps.py +2 -0
  72. django_spire/knowledge/auth/controller.py +2 -0
  73. django_spire/knowledge/collection/admin.py +3 -0
  74. django_spire/knowledge/collection/forms.py +2 -0
  75. django_spire/knowledge/collection/models.py +4 -0
  76. django_spire/knowledge/collection/querysets.py +3 -3
  77. django_spire/knowledge/collection/seeding/seed.py +2 -0
  78. django_spire/knowledge/collection/tests/factories.py +2 -0
  79. django_spire/knowledge/collection/tests/test_services/test_transformation_service.py +2 -0
  80. django_spire/knowledge/collection/tests/test_urls/test_form_urls.py +2 -0
  81. django_spire/knowledge/collection/tests/test_urls/test_json_urls.py +2 -0
  82. django_spire/knowledge/collection/tests/test_urls/test_page_urls.py +2 -0
  83. django_spire/knowledge/collection/views/json_views.py +2 -0
  84. django_spire/knowledge/collection/views/page_views.py +2 -0
  85. django_spire/knowledge/context_processors.py +2 -0
  86. django_spire/knowledge/entry/services/tool_service.py +1 -0
  87. django_spire/knowledge/entry/services/transformation_services.py +0 -1
  88. django_spire/knowledge/entry/tests/factories.py +3 -0
  89. django_spire/knowledge/entry/tests/test_urls/test_form_urls.py +2 -0
  90. django_spire/knowledge/entry/tests/test_urls/test_json_urls.py +2 -0
  91. django_spire/knowledge/entry/tests/test_urls/test_page_urls.py +2 -0
  92. django_spire/knowledge/entry/urls/form_urls.py +1 -0
  93. django_spire/knowledge/entry/urls/json_urls.py +1 -0
  94. django_spire/knowledge/entry/urls/page_urls.py +1 -0
  95. django_spire/knowledge/entry/urls/template_urls.py +1 -0
  96. django_spire/knowledge/entry/version/admin.py +2 -0
  97. django_spire/knowledge/entry/version/block/admin.py +2 -0
  98. django_spire/knowledge/entry/version/block/blocks/heading_block.py +2 -0
  99. django_spire/knowledge/entry/version/block/blocks/sub_heading_block.py +2 -0
  100. django_spire/knowledge/entry/version/block/blocks/text_block.py +2 -0
  101. django_spire/knowledge/entry/version/block/maps.py +2 -0
  102. django_spire/knowledge/entry/version/block/models.py +2 -0
  103. django_spire/knowledge/entry/version/block/tests/factories.py +2 -0
  104. django_spire/knowledge/entry/version/block/tests/test_urls/test_json_urls.py +2 -0
  105. django_spire/knowledge/entry/version/block/views/json_views.py +2 -0
  106. django_spire/knowledge/entry/version/intelligence/bots/markdown_format_llm_bot.py +12 -9
  107. django_spire/knowledge/entry/version/maps.py +2 -0
  108. django_spire/knowledge/entry/version/models.py +2 -0
  109. django_spire/knowledge/entry/version/querysets.py +2 -0
  110. django_spire/knowledge/entry/version/seeding/seeder.py +1 -0
  111. django_spire/knowledge/entry/version/tests/factories.py +2 -0
  112. django_spire/knowledge/entry/version/tests/test_converters/test_docx_converter.py +3 -0
  113. django_spire/knowledge/entry/version/tests/test_urls/test_form_urls.py +2 -0
  114. django_spire/knowledge/entry/version/tests/test_urls/test_json_urls.py +2 -0
  115. django_spire/knowledge/entry/version/tests/test_urls/test_page_urls.py +2 -0
  116. django_spire/knowledge/entry/version/urls/form_urls.py +1 -0
  117. django_spire/knowledge/entry/version/urls/json_urls.py +1 -0
  118. django_spire/knowledge/entry/version/urls/page_urls.py +1 -0
  119. django_spire/knowledge/entry/version/urls/redirect_urls.py +1 -0
  120. django_spire/knowledge/entry/version/views/form_views.py +2 -0
  121. django_spire/knowledge/entry/version/views/json_views.py +2 -0
  122. django_spire/knowledge/entry/version/views/page_views.py +2 -0
  123. django_spire/knowledge/entry/version/views/redirect_views.py +2 -0
  124. django_spire/knowledge/exceptions.py +2 -0
  125. django_spire/knowledge/intelligence/bots/entry_search_llm_bot.py +5 -16
  126. django_spire/knowledge/intelligence/intel/collection_intel.py +3 -1
  127. django_spire/knowledge/intelligence/intel/entry_intel.py +3 -3
  128. django_spire/knowledge/intelligence/intel/message_intel.py +2 -0
  129. django_spire/knowledge/intelligence/maps/collection_map.py +9 -10
  130. django_spire/knowledge/intelligence/maps/entry_map.py +8 -9
  131. django_spire/knowledge/intelligence/workflows/knowledge_workflow.py +8 -6
  132. django_spire/knowledge/models.py +2 -0
  133. django_spire/knowledge/seeding/seed.py +2 -0
  134. django_spire/knowledge/templatetags/spire_knowledge_tags.py +3 -0
  135. django_spire/knowledge/urls/__init__.py +1 -0
  136. {django_spire-0.16.12.dist-info → django_spire-0.16.13.dist-info}/METADATA +5 -4
  137. {django_spire-0.16.12.dist-info → django_spire-0.16.13.dist-info}/RECORD +140 -140
  138. {django_spire-0.16.12.dist-info → django_spire-0.16.13.dist-info}/WHEEL +0 -0
  139. {django_spire-0.16.12.dist-info → django_spire-0.16.13.dist-info}/licenses/LICENSE.md +0 -0
  140. {django_spire-0.16.12.dist-info → django_spire-0.16.13.dist-info}/top_level.txt +0 -0
@@ -1,29 +1,28 @@
1
- from dandy.llm import BaseLlmBot, LlmConfigOptions
2
-
1
+ from dandy import Bot, LlmConfigOptions
3
2
 
4
3
  from django_spire.contrib.seeding.intelligence.intel import SourceIntel
4
+ from django_spire.contrib.seeding.intelligence.prompts.generate_django_model_seeder_prompts import (
5
+ generate_django_model_seeder_user_prompt,
6
+ generate_django_model_seeder_system_prompt
7
+ )
5
8
 
6
9
 
7
- from django_spire.contrib.seeding.intelligence.prompts.generate_django_model_seeder_prompts import \
8
- generate_django_model_seeder_user_prompt, generate_django_model_seeder_system_prompt
9
-
10
-
11
- class SeederGeneratorBot(BaseLlmBot):
10
+ class SeederGeneratorBot(Bot):
11
+ llm_config = 'PYTHON_MODULE'
12
12
 
13
- config = 'PYTHON_MODULE'
14
-
15
- config_options = LlmConfigOptions(
13
+ llm_config_options = LlmConfigOptions(
16
14
  temperature=0.3,
17
15
  randomize_seed=True
18
16
  )
19
17
 
20
- @classmethod
18
+ llm_role = 'You are an expert Python developer specializing in Django model seeders.'
19
+
21
20
  def process(
22
- cls,
23
- model_import: str,
24
- model_description: str
25
- ):
26
- return cls.process_prompt_to_intel(
21
+ self,
22
+ model_import: str,
23
+ model_description: str
24
+ ) -> SourceIntel:
25
+ return self.llm.prompt_to_intel(
27
26
  prompt=generate_django_model_seeder_user_prompt(
28
27
  model_import,
29
28
  model_description,
@@ -1,4 +1,4 @@
1
- from dandy.intel import BaseIntel
1
+ from dandy import BaseIntel
2
2
 
3
3
 
4
4
  class SeedingIntel(BaseIntel):
@@ -1,19 +1,17 @@
1
- from typing import Type
2
-
3
1
  from django.db.models.base import Model
4
2
 
5
- from dandy.llm import Prompt
3
+ from dandy import Prompt
6
4
 
7
5
 
8
6
  class SeedingModelClassPromptFactory:
9
7
 
10
- def __init__(self, model_class: Type[Model]):
8
+ def __init__(self, model_class: type[Model]):
11
9
  self.model_class = model_class
12
10
 
13
11
  def objective_prompt(
14
- self,
15
- model_description: str,
16
- sector_description: str,
12
+ self,
13
+ model_description: str,
14
+ sector_description: str
17
15
  ) -> Prompt:
18
16
  model_name = self.model_class._meta.verbose_name_plural.title()
19
17
 
@@ -1,13 +1,11 @@
1
- from typing_extensions import Type
2
-
3
1
  from django.db.models import Model
4
2
 
5
- from dandy.llm import Prompt
3
+ from dandy import Prompt
6
4
 
7
5
 
8
6
  def foreign_key_selection_prompt(
9
- model_class: Type[Model],
10
- related_model_class: Type[Model]
7
+ model_class: type[Model],
8
+ related_model_class: type[Model]
11
9
  ) -> Prompt:
12
10
  model_name = model_class._meta.verbose_name.title()
13
11
  related_model_name = related_model_class._meta.verbose_name.title()
@@ -1,7 +1,6 @@
1
- import os
2
1
  from pathlib import Path
3
2
 
4
- from dandy.llm import Prompt
3
+ from dandy import Prompt
5
4
 
6
5
 
7
6
  _RELATIVE_BASE_DIR = Path(Path(__file__).parent.parent.parent.parent.parent.parent.resolve())
@@ -1,14 +1,12 @@
1
- from typing_extensions import List, Type
2
-
3
1
  from django.contrib.contenttypes.models import ContentType
4
2
  from django.db.models import Model
5
3
 
6
- from dandy.llm import Prompt
4
+ from dandy import Prompt
7
5
 
8
6
 
9
7
  def generic_relationship_selection_prompt(
10
- model_class: Type[Model],
11
- related_model_classes: List[Type[Model]]
8
+ model_class: type[Model],
9
+ related_model_classes: list[type[Model]]
12
10
  ) -> Prompt:
13
11
  related_model_classes_map = {
14
12
  related_model_class._meta.verbose_name.title(): {
@@ -2,7 +2,7 @@ from random import shuffle
2
2
 
3
3
  from django.db.models import Model
4
4
 
5
- from dandy.llm import Prompt
5
+ from dandy import Prompt
6
6
 
7
7
 
8
8
  def hierarchical_selection_prompt(
@@ -1,11 +1,11 @@
1
- from dandy.llm import Prompt
1
+ from dandy import Prompt
2
2
  from django.db.models.enums import TextChoices
3
3
  from django.db.models.fields import Field
4
4
 
5
5
 
6
6
  def model_field_choices_prompt(
7
- model_field: Field,
8
- choices: TextChoices,
7
+ model_field: Field,
8
+ choices: TextChoices
9
9
  ) -> Prompt:
10
10
  model_name = model_field.field.model.__name__
11
11
  field_name = model_field.field.name
@@ -1,4 +1,4 @@
1
- from dandy.llm import Prompt
1
+ from dandy import Prompt
2
2
 
3
3
 
4
4
  def negation_prompt(
@@ -1,12 +1,10 @@
1
1
  from django.db.models import Model
2
2
 
3
- from typing_extensions import Type
4
-
5
- from dandy.llm import Prompt
3
+ from dandy import Prompt
6
4
 
7
5
 
8
6
  def objective_prompt(
9
- model_class: Type[Model],
7
+ model_class: type[Model],
10
8
  model_description: str,
11
9
  sector_description: str,
12
10
  ) -> Prompt:
@@ -31,12 +31,15 @@ class Command(BaseCommand):
31
31
  # @recorder_to_html_file('seeding_generator')
32
32
  def handle(self, *args, **kwargs):
33
33
  if not kwargs['model_import'] or not kwargs['model_description']:
34
- raise CommandError('You must provide a model import path and a model description')
34
+ message = 'You must provide a model import path and a model description'
35
+ raise CommandError(message)
35
36
 
36
37
  model_import = kwargs['model_import']
37
38
  model_description = ' '.join(kwargs['model_description'])
38
39
 
39
- source_intel = SeederGeneratorBot.process(model_import, model_description)
40
+ # Instantiate the bot
41
+ bot = SeederGeneratorBot()
42
+ source_intel = bot.process(model_import, model_description)
40
43
 
41
44
  Path(_SEEDING_OUTPUT_PATH).mkdir(parents=True, exist_ok=True)
42
45
 
@@ -1,8 +1,8 @@
1
1
  from abc import ABC, abstractmethod
2
2
 
3
3
  from dandy.recorder import recorder_to_html_file
4
- from dandy.cache import SqliteCache
5
- from dandy.cache.utils import generate_hash_key
4
+ from dandy import SqliteCache
5
+ from dandy.cache.utils import generate_cache_key
6
6
 
7
7
  from django_spire.contrib.seeding.field.override import FieldOverride
8
8
  from django_spire.contrib.seeding.model.config import FieldsConfig
@@ -59,10 +59,7 @@ class BaseModelSeeder(ABC):
59
59
 
60
60
  @classmethod
61
61
  def clear_cache(cls):
62
- SqliteCache(
63
- cache_name=cls.cache_name,
64
- limit=cls.cache_limit
65
- ).clear(cache_name=cls.cache_name)
62
+ SqliteCache.clear(cache_name=cls.cache_name)
66
63
 
67
64
  @classmethod
68
65
  @abstractmethod
@@ -80,9 +77,14 @@ class BaseModelSeeder(ABC):
80
77
  field_config = cls.get_field_config().override(fields) if fields else cls.get_field_config()
81
78
 
82
79
  if cls.cache_seed:
83
- hash_key = generate_hash_key(cls.seed_data, count=count, field_config=field_config.fields)
80
+ cache_key = generate_cache_key(
81
+ cls.seed_data,
82
+ count=count,
83
+ fields=field_config.fields
84
+ )
85
+
84
86
  cache = SqliteCache(cache_name=cls.cache_name, limit=cls.cache_limit)
85
- formatted_seed_data = cache.get(hash_key)
87
+ formatted_seed_data = cache.get(cache_key)
86
88
 
87
89
  if formatted_seed_data:
88
90
  return formatted_seed_data
@@ -95,13 +97,13 @@ class BaseModelSeeder(ABC):
95
97
  if len(seeder.seeder_fields) > 0:
96
98
  seed_data.append(seeder.seed(cls, count))
97
99
 
98
- formatted_seed_data = [dict() for _ in range(max(len(sublist) for sublist in seed_data))]
100
+ formatted_seed_data = [{} for _ in range(max(len(sublist) for sublist in seed_data))]
99
101
  for sublist in seed_data:
100
102
  for i, d in enumerate(sublist):
101
103
  formatted_seed_data[i].update(d)
102
104
 
103
105
  if cls.cache_seed:
104
- cache.set(hash_key, formatted_seed_data)
106
+ cache.set(cache_key, formatted_seed_data)
105
107
 
106
108
  return formatted_seed_data
107
109
 
@@ -1,10 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Type, TypeVar
3
+ from typing import TypeVar, TYPE_CHECKING
4
4
 
5
- from dandy.llm import Prompt
6
5
  from django.db.models import ForeignKey
7
-
8
6
  from django.db.models.base import Model
9
7
 
10
8
  from django_spire.contrib.seeding.field.callable import CallableFieldSeeder
@@ -14,6 +12,9 @@ from django_spire.contrib.seeding.field.static import StaticFieldSeeder
14
12
  from django_spire.contrib.seeding.model.base import BaseModelSeeder
15
13
  from django_spire.contrib.seeding.model.django.config import DjangoModelFieldsConfig
16
14
 
15
+ if TYPE_CHECKING:
16
+ from dandy import Prompt
17
+
17
18
 
18
19
  TypeModel = TypeVar('TypeModel', bound=Model)
19
20
 
@@ -21,7 +22,7 @@ TypeModel = TypeVar('TypeModel', bound=Model)
21
22
  class DjangoModelSeeder(BaseModelSeeder):
22
23
  field_config_class = DjangoModelFieldsConfig
23
24
 
24
- model_class: Type[Model]
25
+ model_class: type[Model]
25
26
  prompt: Prompt = None
26
27
  _field_seeders = [
27
28
  CustomFieldSeeder,
@@ -32,14 +33,16 @@ class DjangoModelSeeder(BaseModelSeeder):
32
33
  ]
33
34
 
34
35
  @classmethod
35
- def __init_subclass__(cls, **kwargs):
36
+ def __init_subclass__(cls, **kwargs) -> None:
36
37
  super().__init_subclass__(**kwargs)
37
38
 
38
39
  if cls.model_class is None:
39
- raise ValueError("Seeds must have a model class")
40
+ message = "Seeds must have a model class"
41
+ raise ValueError(message)
40
42
 
41
43
  if cls.fields is None:
42
- raise ValueError("Seeds must have fields")
44
+ message = "Seeds must have fields"
45
+ raise ValueError(message)
43
46
 
44
47
  @classmethod
45
48
  def field_names(cls) -> list[str]:
@@ -51,9 +54,9 @@ class DjangoModelSeeder(BaseModelSeeder):
51
54
 
52
55
  @classmethod
53
56
  def seed_database(
54
- cls,
55
- count=1,
56
- fields: dict | None = None
57
+ cls,
58
+ count=1,
59
+ fields: dict | None = None
57
60
  ) -> list[TypeModel]:
58
61
  model_objects = cls.seed(count, fields)
59
62
  return cls.model_class.objects.bulk_create(model_objects)
@@ -1,4 +1,4 @@
1
- # from dandy.llm import Prompt
1
+ # from dandy import Prompt
2
2
  # from django.test import TestCase
3
3
  #
4
4
  # from django_spire.seeding.processor import SeedingProcessor
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  # These imports are for the migrations to work as a single app "django_spire_knowledge"
2
4
 
3
5
  from django_spire.knowledge.collection.admin import *
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.apps import AppConfig
2
4
 
3
5
  from django_spire.utils import check_required_apps
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django_spire.auth.controller.controller import BaseAuthController
2
4
 
3
5
 
@@ -1,4 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.contrib import admin
4
+
2
5
  from .models import Collection, CollectionGroup
3
6
 
4
7
 
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django import forms
2
4
 
3
5
  from django_spire.knowledge.collection.models import Collection
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.db import models
2
4
 
3
5
  from django_spire.auth.group.models import AuthGroup
@@ -44,10 +46,12 @@ class CollectionGroup(models.Model):
44
46
  related_name='groups',
45
47
  related_query_name='group',
46
48
  )
49
+
47
50
  auth_group = models.ForeignKey(
48
51
  AuthGroup,
49
52
  on_delete=models.CASCADE,
50
53
  related_name='collection_groups',
51
54
  related_query_name='collection_group',
52
55
  )
56
+
53
57
  services = CollectionGroupService()
@@ -2,15 +2,14 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING
4
4
 
5
- from django.core.handlers.wsgi import WSGIRequest
6
- from django.db.models import Count, Q
5
+ from django.db.models import Count
7
6
 
8
7
  from django_spire.auth.controller.controller import AppAuthController
9
8
  from django_spire.contrib.ordering.querysets import OrderingQuerySetMixin
10
9
  from django_spire.history.querysets import HistoryQuerySet
11
10
 
12
11
  if TYPE_CHECKING:
13
- from django_spire.auth.user.models import AuthUser
12
+ from django.core.handlers.wsgi import WSGIRequest
14
13
  from django.db.models import QuerySet
15
14
  from django_spire.knowledge.collection.models import Collection
16
15
 
@@ -57,6 +56,7 @@ class CollectionQuerySet(HistoryQuerySet, OrderingQuerySetMixin):
57
56
  accessible_ids = set(direct_access.values_list('id', flat=True))
58
57
 
59
58
  current_level_ids = accessible_ids.copy()
59
+
60
60
  while current_level_ids:
61
61
  next_level = self.filter(parent_id__in=current_level_ids)
62
62
  new_ids = set(next_level.values_list('id', flat=True)) - accessible_ids
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django_spire.knowledge.collection.seeding.seeder import CollectionSeeder
2
4
 
3
5
  parent_collections = CollectionSeeder.seed_database(count=5)
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django_spire.knowledge.collection.models import Collection
2
4
 
3
5
 
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
4
 
3
5
  from django.contrib.sites.models import Site
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.urls import reverse
2
4
 
3
5
  from django_spire.core.tests.test_cases import BaseTestCase
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.urls import reverse
2
4
 
3
5
  from django_spire.core.tests.test_cases import BaseTestCase
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.urls import reverse
2
4
 
3
5
  from django_spire.core.tests.test_cases import BaseTestCase
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
4
 
3
5
  from django.core.handlers.wsgi import WSGIRequest
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.core.handlers.wsgi import WSGIRequest
2
4
  from django.shortcuts import get_object_or_404
3
5
  from django.template.response import TemplateResponse
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from typing import Any
2
4
 
3
5
  from django.core.handlers.wsgi import WSGIRequest
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
+
4
5
  from typing import TYPE_CHECKING
5
6
 
6
7
  from django.contrib.contenttypes.models import ContentType
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import json
4
3
  from typing import TYPE_CHECKING
5
4
 
6
5
  from django.conf import settings
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django_spire.knowledge.collection.tests.factories import create_test_collection
2
4
  from django_spire.knowledge.entry.models import Entry
3
5
 
@@ -9,5 +11,6 @@ def create_test_entry(**kwargs) -> Entry:
9
11
  'is_deleted': False,
10
12
  'is_active': True
11
13
  }
14
+
12
15
  data.update(kwargs)
13
16
  return Entry.objects.create(**data)
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.urls import reverse
2
4
 
3
5
  from django_spire.core.tests.test_cases import BaseTestCase
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.urls import reverse
2
4
 
3
5
  from django_spire.core.tests.test_cases import BaseTestCase
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.urls import reverse
2
4
 
3
5
  from django_spire.core.tests.test_cases import BaseTestCase
@@ -2,6 +2,7 @@ from django.urls import path
2
2
 
3
3
  from django_spire.knowledge.entry.views import form_views
4
4
 
5
+
5
6
  app_name = 'form'
6
7
 
7
8
  urlpatterns = [
@@ -2,6 +2,7 @@ from django.urls import path
2
2
 
3
3
  from django_spire.knowledge.entry.views import json_views
4
4
 
5
+
5
6
  app_name = 'json'
6
7
 
7
8
  urlpatterns = [
@@ -2,6 +2,7 @@ from django.urls import path
2
2
 
3
3
  from django_spire.knowledge.entry.views import page_views
4
4
 
5
+
5
6
  app_name = 'page'
6
7
 
7
8
  urlpatterns = [
@@ -2,6 +2,7 @@ from django.urls import path
2
2
 
3
3
  from django_spire.knowledge.entry.views import template_views
4
4
 
5
+
5
6
  app_name = 'template'
6
7
 
7
8
  urlpatterns = [
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.contrib import admin
2
4
 
3
5
  from django_spire.knowledge.entry.version.models import EntryVersion
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.contrib import admin
2
4
 
3
5
  from django_spire.knowledge.entry.version.block.models import EntryVersionBlock
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django_spire.knowledge.entry.version.block.choices import BlockTypeChoices
2
4
  from django_spire.knowledge.entry.version.block.blocks.block import BaseBlock
3
5
 
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django_spire.knowledge.entry.version.block.choices import BlockTypeChoices
2
4
  from django_spire.knowledge.entry.version.block.blocks.block import BaseBlock
3
5
 
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django_spire.knowledge.entry.version.block.choices import BlockTypeChoices
2
4
  from django_spire.knowledge.entry.version.block.blocks.block import BaseBlock
3
5
 
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django_spire.knowledge.entry.version.block.blocks.list_block import ListItemBlock
2
4
  from django_spire.knowledge.entry.version.block.choices import BlockTypeChoices
3
5
  from django_spire.knowledge.entry.version.block.blocks.heading_block import HeadingBlock
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from django.db import models
2
4
  from django.forms import model_to_dict
3
5
  from django.template.loader import render_to_string
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
4
 
3
5
  from django_spire.knowledge.entry.version.block.blocks.text_block import TextBlock
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
4
 
3
5
  from django.urls import reverse
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
4
 
3
5
  from django.core.handlers.wsgi import WSGIRequest