Completed
Push — main ( c0c994...7dc7dc )
by Jochen
03:36
created

byceps.services.ticketing.ticket_code_service   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 73
Duplicated Lines 0 %

Test Coverage

Coverage 96%

Importance

Changes 0
Metric Value
eloc 30
dl 0
loc 73
ccs 24
cts 25
cp 0.96
rs 10
c 0
b 0
f 0
wmc 8

4 Functions

Rating   Name   Duplication   Size   Complexity  
A _generate_ticket_code_not_in() 0 11 3
A _generate_ticket_code() 0 6 1
A generate_ticket_codes() 0 12 2
A _verify_total_matches() 0 12 2
1
"""
2
byceps.services.ticketing.ticket_code_service
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2020 Jochen Kupperschmidt
6
:License: Modified BSD, see LICENSE for details.
7
"""
8
9 1
from random import sample
10 1
from typing import Set
11
12 1
from .transfer.models import TicketCode
13
14
15 1
def generate_ticket_codes(quantity: int) -> Set[TicketCode]:
16
    """Generate a number of ticket codes."""
17 1
    codes: Set[TicketCode] = set()
18
19 1
    for _ in range(quantity):
20 1
        code = _generate_ticket_code_not_in(codes)
21 1
        codes.add(code)
22
23
    # Check if the correct number of codes has been generated.
24 1
    _verify_total_matches(codes, quantity)
25
26 1
    return codes
27
28
29 1
def _generate_ticket_code_not_in(
30
    codes: Set[TicketCode], *, max_attempts: int = 4
31
) -> TicketCode:
32
    """Generate ticket codes and return the first one not in the set."""
33 1
    for _ in range(max_attempts):
34 1
        code = _generate_ticket_code()
35 1
        if code not in codes:
36 1
            return code
37
38 1
    raise TicketCodeGenerationFailed(
39
        f'Could not generate unique ticket code after {max_attempts} attempts.'
40
    )
41
42
43 1
_CODE_ALPHABET = 'BCDFGHJKLMNPQRSTVWXYZ'
44 1
_CODE_LENGTH = 5
45
46
47 1
def _generate_ticket_code() -> TicketCode:
48
    """Generate a ticket code.
49
50
    Generated codes are not necessarily unique!
51
    """
52 1
    return TicketCode(''.join(sample(_CODE_ALPHABET, _CODE_LENGTH)))
53
54
55 1
def _verify_total_matches(
56
    codes: Set[TicketCode], requested_quantity: int
57
) -> None:
58
    """Verify if the number of generated codes matches the number of
59
    requested codes.
60
61
    Raise an exception if they do not match.
62
    """
63 1
    actual_quantity = len(codes)
64 1
    if actual_quantity != requested_quantity:
65
        raise TicketCodeGenerationFailed(
66
            f'Number of generated ticket codes ({actual_quantity}) '
67
            f'does not match requested amount ({requested_quantity}).'
68
        )
69
70
71 1
class TicketCodeGenerationFailed(Exception):
72
    """Generating one or more unique ticket codes has failed."""
73