mirror of
https://github.com/ae-utbm/sith.git
synced 2025-07-09 19:40:19 +00:00
use google convention for docstrings
This commit is contained in:
@ -118,11 +118,11 @@ class Command(BaseCommand):
|
||||
self.make_important_citizen(u)
|
||||
|
||||
def make_clubs(self):
|
||||
"""
|
||||
Create all the clubs (:class:`club.models.Club`)
|
||||
and store them in `self.clubs` for fast access later.
|
||||
"""Create all the clubs (:class:`club.models.Club`).
|
||||
|
||||
After creation, the clubs are stored in `self.clubs` for fast access later.
|
||||
Don't create the meta groups (:class:`core.models.MetaGroup`)
|
||||
nor the pages of the clubs (:class:`core.models.Page`)
|
||||
nor the pages of the clubs (:class:`core.models.Page`).
|
||||
"""
|
||||
self.clubs = []
|
||||
for i in range(self.NB_CLUBS):
|
||||
@ -132,8 +132,7 @@ class Command(BaseCommand):
|
||||
self.clubs = list(Club.objects.filter(unix_name__startswith="galaxy-").all())
|
||||
|
||||
def make_users(self):
|
||||
"""
|
||||
Create all the users and store them in `self.users` for fast access later.
|
||||
"""Create all the users and store them in `self.users` for fast access later.
|
||||
|
||||
Also create a subscription for all the generated users.
|
||||
"""
|
||||
@ -167,8 +166,7 @@ class Command(BaseCommand):
|
||||
Subscription.objects.bulk_create(subs)
|
||||
|
||||
def make_families(self):
|
||||
"""
|
||||
Generate the godfather/godchild relations for the users contained in :attr:`self.users`.
|
||||
"""Generate the godfather/godchild relations for the users contained in :attr:`self.users`.
|
||||
|
||||
The :meth:`make_users` method must have been called beforehand.
|
||||
|
||||
@ -194,8 +192,7 @@ class Command(BaseCommand):
|
||||
User.godfathers.through.objects.bulk_create(godfathers)
|
||||
|
||||
def make_club_memberships(self):
|
||||
"""
|
||||
Assign users to clubs and give them a role in a pseudo-random way.
|
||||
"""Assign users to clubs and give them a role in a pseudo-random way.
|
||||
|
||||
The :meth:`make_users` and :meth:`make_clubs` methods
|
||||
must have been called beforehand.
|
||||
@ -265,8 +262,7 @@ class Command(BaseCommand):
|
||||
Membership.objects.bulk_create(memberships)
|
||||
|
||||
def make_pictures(self):
|
||||
"""
|
||||
Create pictures for users to be tagged on later.
|
||||
"""Create pictures for users to be tagged on later.
|
||||
|
||||
The :meth:`make_users` method must have been called beforehand.
|
||||
"""
|
||||
@ -301,11 +297,10 @@ class Command(BaseCommand):
|
||||
self.picts = list(Picture.objects.filter(name__startswith="galaxy-").all())
|
||||
|
||||
def make_pictures_memberships(self):
|
||||
"""
|
||||
Assign users to pictures and make enough of them for our
|
||||
"""Assign users to pictures and make enough of them for our
|
||||
created users to be eligible for promotion as citizen.
|
||||
|
||||
See :meth:`galaxy.models.Galaxy.rule` for details on promotion to citizen.
|
||||
See `galaxy.models.Galaxy.rule` for details on promotion to citizen.
|
||||
"""
|
||||
self.pictures_tags = []
|
||||
|
||||
@ -363,9 +358,9 @@ class Command(BaseCommand):
|
||||
PeoplePictureRelation.objects.bulk_create(self.pictures_tags)
|
||||
|
||||
def make_important_citizen(self, uid: int):
|
||||
"""
|
||||
Make the user whose uid is given in parameter a more important citizen,
|
||||
thus triggering many more connections to others (lanes)
|
||||
"""Make the user whose uid is given in parameter a more important citizen.
|
||||
|
||||
This will trigger many more connections to others (lanes)
|
||||
and dragging him towards the center of the Galaxy.
|
||||
|
||||
This promotion is obtained by adding more family links
|
||||
@ -375,7 +370,8 @@ class Command(BaseCommand):
|
||||
also be tagged in more pictures, thus making them also
|
||||
more important.
|
||||
|
||||
:param uid: the id of the user to make more important
|
||||
Args:
|
||||
uid: the id of the user to make more important
|
||||
"""
|
||||
u1 = self.users[uid]
|
||||
u2 = self.users[uid - 100]
|
||||
|
@ -26,7 +26,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
import math
|
||||
import time
|
||||
from typing import List, NamedTuple, Optional, TypedDict, Union
|
||||
from typing import NamedTuple, TypedDict
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import Case, Count, F, Q, Value, When
|
||||
@ -40,9 +40,9 @@ from sas.models import Picture
|
||||
|
||||
|
||||
class GalaxyStar(models.Model):
|
||||
"""
|
||||
Define a star (vertex -> user) in the galaxy graph,
|
||||
storing a reference to its owner citizen.
|
||||
"""Define a star (vertex -> user) in the galaxy graph.
|
||||
|
||||
Store a reference to its owner citizen.
|
||||
|
||||
Stars are linked to each others through the :class:`GalaxyLane` model.
|
||||
|
||||
@ -74,13 +74,14 @@ class GalaxyStar(models.Model):
|
||||
|
||||
|
||||
@property
|
||||
def current_star(self) -> Optional[GalaxyStar]:
|
||||
"""
|
||||
The star of this user in the :class:`Galaxy`.
|
||||
def current_star(self) -> GalaxyStar | None:
|
||||
"""The star of this user in the :class:`Galaxy`.
|
||||
|
||||
Only take into account the most recent active galaxy.
|
||||
|
||||
:return: The star of this user if there is an active Galaxy
|
||||
and this user is a citizen of it, else ``None``
|
||||
Returns:
|
||||
The star of this user if there is an active Galaxy
|
||||
and this user is a citizen of it, else `None`
|
||||
"""
|
||||
return self.stars.filter(galaxy=Galaxy.get_current_galaxy()).last()
|
||||
|
||||
@ -90,10 +91,9 @@ User.current_star = current_star
|
||||
|
||||
|
||||
class GalaxyLane(models.Model):
|
||||
"""
|
||||
Define a lane (edge -> link between galaxy citizen)
|
||||
in the galaxy map, storing a reference to both its
|
||||
ends and the distance it covers.
|
||||
"""Define a lane (edge -> link between galaxy citizen) in the galaxy map.
|
||||
|
||||
Store a reference to both its ends and the distance it covers.
|
||||
Score details between citizen owning the stars is also stored here.
|
||||
"""
|
||||
|
||||
@ -138,8 +138,8 @@ class StarDict(TypedDict):
|
||||
|
||||
|
||||
class GalaxyDict(TypedDict):
|
||||
nodes: List[StarDict]
|
||||
links: List
|
||||
nodes: list[StarDict]
|
||||
links: list
|
||||
|
||||
|
||||
class RelationScore(NamedTuple):
|
||||
@ -149,8 +149,8 @@ class RelationScore(NamedTuple):
|
||||
|
||||
|
||||
class Galaxy(models.Model):
|
||||
"""
|
||||
The Galaxy, a graph linking the active users between each others.
|
||||
"""The Galaxy, a graph linking the active users between each others.
|
||||
|
||||
The distance between two users is given by a relation score which takes
|
||||
into account a few parameter like the number of pictures they are both tagged on,
|
||||
the time during which they were in the same clubs and whether they are
|
||||
@ -204,8 +204,8 @@ class Galaxy(models.Model):
|
||||
|
||||
@classmethod
|
||||
def compute_user_score(cls, user: User) -> int:
|
||||
"""
|
||||
Compute an individual score for each citizen.
|
||||
"""Compute an individual score for each citizen.
|
||||
|
||||
It will later be used by the graph algorithm to push
|
||||
higher scores towards the center of the galaxy.
|
||||
|
||||
@ -231,10 +231,7 @@ class Galaxy(models.Model):
|
||||
|
||||
@classmethod
|
||||
def query_user_score(cls, user: User) -> int:
|
||||
"""
|
||||
Perform the db query to get the individual score
|
||||
of the given user in the galaxy.
|
||||
"""
|
||||
"""Get the individual score of the given user in the galaxy."""
|
||||
score_query = (
|
||||
User.objects.filter(id=user.id)
|
||||
.annotate(
|
||||
@ -262,9 +259,9 @@ class Galaxy(models.Model):
|
||||
|
||||
@classmethod
|
||||
def compute_users_score(cls, user1: User, user2: User) -> RelationScore:
|
||||
"""
|
||||
Compute the relationship scores of the two given users
|
||||
in the following fields :
|
||||
"""Compute the relationship scores of the two given users.
|
||||
|
||||
The computation is done with the following fields :
|
||||
|
||||
- family: if they have some godfather/godchild relation
|
||||
- pictures: in how many pictures are both tagged
|
||||
@ -277,11 +274,12 @@ class Galaxy(models.Model):
|
||||
|
||||
@classmethod
|
||||
def compute_users_family_score(cls, user1: User, user2: User) -> int:
|
||||
"""
|
||||
Compute the family score of the relation between the given users.
|
||||
"""Compute the family score of the relation between the given users.
|
||||
|
||||
This takes into account mutual godfathers.
|
||||
|
||||
:return: 366 if user1 is the godfather of user2 (or vice versa) else 0
|
||||
Returns:
|
||||
366 if user1 is the godfather of user2 (or vice versa) else 0
|
||||
"""
|
||||
link_count = User.objects.filter(
|
||||
Q(id=user1.id, godfathers=user2) | Q(id=user2.id, godfathers=user1)
|
||||
@ -294,14 +292,14 @@ class Galaxy(models.Model):
|
||||
|
||||
@classmethod
|
||||
def compute_users_pictures_score(cls, user1: User, user2: User) -> int:
|
||||
"""
|
||||
Compute the pictures score of the relation between the given users.
|
||||
"""Compute the pictures score of the relation between the given users.
|
||||
|
||||
The pictures score is obtained by counting the number
|
||||
of :class:`Picture` in which they have been both identified.
|
||||
This score is then multiplied by 2.
|
||||
|
||||
:return: The number of pictures both users have in common, times 2
|
||||
Returns:
|
||||
The number of pictures both users have in common, times 2
|
||||
"""
|
||||
picture_count = (
|
||||
Picture.objects.filter(people__user__in=(user1,))
|
||||
@ -316,8 +314,7 @@ class Galaxy(models.Model):
|
||||
|
||||
@classmethod
|
||||
def compute_users_clubs_score(cls, user1: User, user2: User) -> int:
|
||||
"""
|
||||
Compute the clubs score of the relation between the given users.
|
||||
"""Compute the clubs score of the relation between the given users.
|
||||
|
||||
The club score is obtained by counting the number of days
|
||||
during which the memberships (see :class:`club.models.Membership`)
|
||||
@ -328,7 +325,8 @@ class Galaxy(models.Model):
|
||||
31/12/2022 (also two years, but with an offset of one year), then their
|
||||
club score is 365.
|
||||
|
||||
:return: the number of days during which both users were in the same club
|
||||
Returns:
|
||||
the number of days during which both users were in the same club
|
||||
"""
|
||||
common_clubs = Club.objects.filter(members__in=user1.memberships.all()).filter(
|
||||
members__in=user2.memberships.all()
|
||||
@ -380,13 +378,13 @@ class Galaxy(models.Model):
|
||||
###################
|
||||
|
||||
@classmethod
|
||||
def scale_distance(cls, value: Union[int, float]) -> int:
|
||||
"""
|
||||
Given a numeric value, return a scaled value which can
|
||||
def scale_distance(cls, value: int | float) -> int:
|
||||
"""Given a numeric value, return a scaled value which can
|
||||
be used in the Galaxy's graphical interface to set the distance
|
||||
between two stars
|
||||
between two stars.
|
||||
|
||||
:return: the scaled value usable in the Galaxy's 3d graph
|
||||
Returns:
|
||||
the scaled value usable in the Galaxy's 3d graph
|
||||
"""
|
||||
# TODO: this will need adjustements with the real, typical data on Taiste
|
||||
if value == 0:
|
||||
@ -409,8 +407,8 @@ class Galaxy(models.Model):
|
||||
return int(value)
|
||||
|
||||
def rule(self, picture_count_threshold=10) -> None:
|
||||
"""
|
||||
Main function of the Galaxy.
|
||||
"""Main function of the Galaxy.
|
||||
|
||||
Iterate over all the rulable users to promote them to citizens.
|
||||
A citizen is a user who has a corresponding star in the Galaxy.
|
||||
Also build up the lanes, which are the links between the different citizen.
|
||||
@ -566,9 +564,7 @@ class Galaxy(models.Model):
|
||||
)
|
||||
|
||||
def make_state(self) -> None:
|
||||
"""
|
||||
Compute JSON structure to send to 3d-force-graph: https://github.com/vasturiano/3d-force-graph/
|
||||
"""
|
||||
"""Compute JSON structure to send to 3d-force-graph: https://github.com/vasturiano/3d-force-graph/."""
|
||||
self.logger.info(
|
||||
"Caching current Galaxy state for a quicker display of the Empire's power."
|
||||
)
|
||||
|
@ -46,9 +46,7 @@ class GalaxyTestModel(TestCase):
|
||||
cls.com = User.objects.get(username="comunity")
|
||||
|
||||
def test_user_self_score(self):
|
||||
"""
|
||||
Test that individual user scores are correct
|
||||
"""
|
||||
"""Test that individual user scores are correct."""
|
||||
with self.assertNumQueries(8):
|
||||
assert Galaxy.compute_user_score(self.root) == 9
|
||||
assert Galaxy.compute_user_score(self.skia) == 10
|
||||
@ -60,9 +58,8 @@ class GalaxyTestModel(TestCase):
|
||||
assert Galaxy.compute_user_score(self.com) == 1
|
||||
|
||||
def test_users_score(self):
|
||||
"""
|
||||
Test on the default dataset generated by the `populate` command
|
||||
that the relation scores are correct
|
||||
"""Test on the default dataset generated by the `populate` command
|
||||
that the relation scores are correct.
|
||||
"""
|
||||
expected_scores = {
|
||||
"krophil": {
|
||||
@ -138,8 +135,7 @@ class GalaxyTestModel(TestCase):
|
||||
self.assertDictEqual(expected_scores, computed_scores)
|
||||
|
||||
def test_rule(self):
|
||||
"""
|
||||
Test on the default dataset generated by the `populate` command
|
||||
"""Test on the default dataset generated by the `populate` command
|
||||
that the number of queries to rule the galaxy is stable.
|
||||
"""
|
||||
galaxy = Galaxy.objects.create()
|
||||
@ -151,18 +147,14 @@ class GalaxyTestModel(TestCase):
|
||||
class GalaxyTestView(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
"""
|
||||
Generate a plausible Galaxy once for every test
|
||||
"""
|
||||
"""Generate a plausible Galaxy once for every test."""
|
||||
call_command("generate_galaxy_test_data", "-v", "0")
|
||||
galaxy = Galaxy.objects.create()
|
||||
galaxy.rule(26) # We want a fast test
|
||||
cls.root = User.objects.get(username="root")
|
||||
|
||||
def test_page_is_citizen(self):
|
||||
"""
|
||||
Test that users can access the galaxy page of users who are citizens
|
||||
"""
|
||||
"""Test that users can access the galaxy page of users who are citizens."""
|
||||
self.client.force_login(self.root)
|
||||
user = User.objects.get(last_name="n°500")
|
||||
response = self.client.get(reverse("galaxy:user", args=[user.id]))
|
||||
@ -173,20 +165,19 @@ class GalaxyTestView(TestCase):
|
||||
)
|
||||
|
||||
def test_page_not_citizen(self):
|
||||
"""
|
||||
Test that trying to access the galaxy page of a user who is not
|
||||
citizens return a 404
|
||||
"""
|
||||
"""Test that trying to access the galaxy page of non-citizen users return a 404."""
|
||||
self.client.force_login(self.root)
|
||||
user = User.objects.get(last_name="n°1")
|
||||
response = self.client.get(reverse("galaxy:user", args=[user.id]))
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_full_galaxy_state(self):
|
||||
"""
|
||||
Test on the more complex dataset generated by the `generate_galaxy_test_data`
|
||||
command that the relation scores are correct, and that the view exposes the
|
||||
right data.
|
||||
"""Test with a more complete galaxy.
|
||||
|
||||
This time, the test is done on
|
||||
the more complex dataset generated by the `generate_galaxy_test_data`
|
||||
command that the relation scores are correct,
|
||||
and that the view exposes the right data.
|
||||
"""
|
||||
self.client.force_login(self.root)
|
||||
response = self.client.get(reverse("galaxy:data"))
|
||||
|
Reference in New Issue
Block a user