forked from ietf-tools/datatracker
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfactories.py
More file actions
187 lines (151 loc) · 7.01 KB
/
factories.py
File metadata and controls
187 lines (151 loc) · 7.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# Copyright The IETF Trust 2015-2020, All Rights Reserved
# -*- coding: utf-8 -*-
import factory
from factory.fuzzy import FuzzyChoice
import faker
import faker.config
import os
import random
from PIL import Image
from unidecode import unidecode
from unicodedata import normalize
from django.conf import settings
from django.contrib.auth.models import User
from django.utils.text import slugify
from django.utils.encoding import force_str
import debug # pyflakes:ignore
from ietf.person.models import Person, Alias, Email, PersonalApiKey, PersonApiKeyEvent, PERSON_API_KEY_ENDPOINTS
from ietf.person.name import normalize_name, unidecode_name
fake = faker.Factory.create()
# The transliteration of some Arabic and Devanagari names introduces
# non-alphabetic characters that don't work with the draft author
# extraction code, and also don't seem to match the way people with Arabic
# names romanize Arabic names. Exclude those locales from name generation
# in order to avoid test failures.
_acceptable_fakers = [
faker.Faker(locale)
for locale in set(faker.config.AVAILABLE_LOCALES)
if not (locale.startswith('ar_') or locale.startswith('sg_') or locale == 'fr_QC')
]
def random_faker():
"""Helper to get a random faker acceptable for User names"""
return random.sample(_acceptable_fakers, 1)[0]
class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User
django_get_or_create = ('username',)
exclude = ['faker', ]
skip_postgeneration_save = True
faker = factory.LazyFunction(random_faker)
# normalize these i18n Unicode strings in the same way the database does
first_name = factory.LazyAttribute(lambda o: normalize("NFKC", o.faker.first_name()))
last_name = factory.LazyAttribute(lambda o: normalize("NFKC", o.faker.last_name()))
email = factory.LazyAttributeSequence(lambda u, n: '%s.%s_%d@%s'%( slugify(unidecode(u.first_name)),
slugify(unidecode(u.last_name)), n, fake.domain_name())) # type: ignore
username = factory.LazyAttribute(lambda u: u.email)
# Consider using PostGenerationMethodCall instead
@factory.post_generation
def set_password(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
obj.set_password( '%s+password' % obj.username ) # pylint: disable=no-value-for-parameter
obj.save()
class PersonFactory(factory.django.DjangoModelFactory):
class Meta:
model = Person
skip_postgeneration_save = True
user = factory.SubFactory(UserFactory)
name = factory.LazyAttribute(lambda p: normalize_name('%s %s'%(p.user.first_name, p.user.last_name)))
# Some i18n names, e.g., "शिला के.सी." have a dot at the end that is also part of the ASCII, e.g., "Shilaa Kesii."
# That trailing dot breaks extract_authors(). Avoid this issue by stripping the dot from the ASCII.
# Some others have a trailing semicolon (e.g., "உயிரோவியம் தங்கராஐ;") - strip those, too.
ascii = factory.LazyAttribute(lambda p: force_str(unidecode_name(p.name)).rstrip(".;"))
class Params:
with_bio = factory.Trait(biography = "\n\n".join(fake.paragraphs())) # type: ignore
@factory.post_generation
def default_aliases(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
make_alias = getattr(AliasFactory, 'create' if create else 'build')
make_alias(person=obj,name=obj.name)
make_alias(person=obj,name=obj.ascii)
if obj.name != obj.plain_name():
make_alias(person=obj,name=obj.plain_name())
if obj.ascii != obj.plain_ascii():
make_alias(person=obj,name=obj.plain_ascii())
@factory.post_generation
def default_emails(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
if extracted is None:
extracted = True
if create and extracted:
make_email = getattr(EmailFactory, 'create' if create else 'build')
make_email(person=obj, address=obj.user.email)
@factory.post_generation
def default_photo(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
import atexit
if obj.biography:
photo_name = obj.photo_name()
media_name = "%s/%s.jpg" % (settings.PHOTOS_DIRNAME, photo_name)
obj.photo = media_name
obj.photo_thumb = media_name
photodst = os.path.join(settings.PHOTOS_DIR, photo_name + '.jpg')
img = Image.new('RGB', (200, 200))
img.save(photodst)
def delete_file(file):
os.unlink(file)
atexit.register(delete_file, photodst)
obj.save()
class AliasFactory(factory.django.DjangoModelFactory):
class Meta:
model = Alias
@classmethod
def _create(cls, model_class, *args, **kwargs):
person = kwargs['person']
name = kwargs['name']
existing_aliases = set(model_class.objects.filter(person=person).values_list('name', flat=True))
if not name in existing_aliases:
obj = model_class(*args, **kwargs)
obj.save()
return obj
name = factory.Faker('name')
def fake_email_address(n):
address_field = [ f for f in Email._meta.fields if f.name == 'address'][0]
count = 0
while True:
address = '%s.%s_%d@%s' % (
slugify(unidecode(fake.first_name())),
slugify(unidecode(fake.last_name())),
n, fake.domain_name()
)
count += 1
if len(address) <= address_field.max_length:
break
if count >= 10:
raise RuntimeError("Failed generating a fake email address to fit in Email.address(max_length=%s)"%address_field.max_lenth)
return address
class EmailFactory(factory.django.DjangoModelFactory):
class Meta:
model = Email
django_get_or_create = ('address',)
address = factory.Sequence(fake_email_address)
person = factory.SubFactory(PersonFactory)
active = True
primary = False
origin = factory.LazyAttribute(lambda obj: obj.person.user.username if obj.person.user else '')
class PersonalApiKeyFactory(factory.django.DjangoModelFactory):
person = factory.SubFactory(PersonFactory)
endpoint = FuzzyChoice(v for v, n in PERSON_API_KEY_ENDPOINTS)
class Meta:
model = PersonalApiKey
skip_postgeneration_save = True
@factory.post_generation
def validate_model(obj, create, extracted, **kwargs):
"""Validate the model after creation
Passing validate_model=False will disable the validation.
"""
do_clean = True if extracted is None else extracted
if do_clean:
obj.full_clean()
class PersonApiKeyEventFactory(factory.django.DjangoModelFactory):
key = factory.SubFactory(PersonalApiKeyFactory)
person = factory.LazyAttribute(lambda o: o.key.person)
type = 'apikey_login'
desc = factory.Faker('sentence', nb_words=6)
class Meta:
model = PersonApiKeyEvent