Skip to content

Commit

Permalink
Work on automatic label generation (#6)
Browse files Browse the repository at this point in the history
* add

* Update paths.py

* lets see

* Revert "lets see"

This reverts commit 7633fac.

* Revert "Revert "lets see""

This reverts commit 5238e6a.

* Update paths.py

* Update paths.py

* add

* Update guess_label_size.py

add

Update guess_label_size.py

Update guess_label_size.py

Update guess_label_size.py

add

* Update guess_label_size.py

add

Update guess_label_size.py

Update guess_label_size.py

Update guess_label_size.py

add

* Update paths.py

* Update paths.py

* Update paths.py

* Update paths.py

* Update paths.py

* Update paths.py

* Update paths.py

Update paths.py

* Update paths.py

* Update paths.py

* Update paths.py

* add

add

Update test_label_generation.py
  • Loading branch information
baseplate-admin committed Feb 23, 2024
1 parent 518ef2d commit 871f742
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 122 deletions.
1 change: 0 additions & 1 deletion django_ltree/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ def create_child(self, parent=None, **kwargs):
path_generator = PathGenerator(
prefix,
skip=paths_in_use.values_list("path", flat=True),
label_size=getattr(self.model, "label_size"),
)
kwargs["path"] = path_generator.next()
return self.create(**kwargs)
41 changes: 36 additions & 5 deletions django_ltree/paths.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import string
import math
from itertools import product

from django_ltree.fields import PathValue
from .fields import PathValue


class PathGenerator(object):
_default_label_size = 6 # Postgres limits this to 256
def __init__(self, prefix=None, skip=None):
combinations = string.digits + string.ascii_letters

def __init__(self, prefix=None, skip=None, label_size=None):
self.skip_paths = [] if skip is None else skip[:]
self.path_prefix = prefix if prefix else []
self.product_iterator = product(
string.digits + string.ascii_letters,
repeat=label_size or self._default_label_size,
combinations,
repeat=self.guess_the_label_size(
path_size=len(self.skip_paths), combination_size=len(combinations)
),
)

def __iter__(self):
Expand All @@ -26,3 +29,31 @@ def __next__(self):
return path

next = __next__

@staticmethod
def guess_the_label_size(path_size: int, combination_size: int) -> int:
# The theoritical limit for this at the time of writing is 2_538_557_185_841_324_496 (python 3.12.2)
calculated_path_size = -1 # -1 is here for 0th index items
# The theoritical limit for this at the time of writing is 32 (python 3.12.2)
label_size = 0

# THIS IS AN VERY IMPORTANT CHECK
last = 0

while True:
possible_cominations = math.comb(combination_size, label_size)
if last > possible_cominations:
raise ValueError("We approached the limit of `math.comb`")

last = possible_cominations
calculated_path_size += possible_cominations

if calculated_path_size > path_size and label_size != 0:
break

label_size += 1

return label_size


print(PathGenerator.guess_the_label_size(62, 62))
2 changes: 1 addition & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions tests/taxonomy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@


class Taxonomy(TreeModel):
label_size = 2

name = models.TextField()

def __str__(self):
return '{}: {}'.format(self.path, self.name)
return f"{self.path}: {self.name}"
13 changes: 13 additions & 0 deletions tests/test_label_generation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django_ltree.paths import PathGenerator


def test_label_generation():
assert PathGenerator.guess_the_label_size(62, 62) == 2
assert PathGenerator.guess_the_label_size(0, 62) == 1


def test_automatic_name_creation():
from taxonomy.models import Taxonomy

for i in range(0, 1000):
Taxonomy.objects.create_child(name=i)
Empty file added tests/test_limits.py
Empty file.
Loading

0 comments on commit 871f742

Please sign in to comment.