Blame view

flaskr/models.py 6.07 KB
f48f4a8f   Antoine Goutenoir   Optimize a bottle...
1
2
3
import enum
import shelve
from os.path import join, isfile
16f69d07   Antoine Goutenoir   Add an (unsecured...
4
5
from flask_admin.contrib.sqla import ModelView

a3e9d0fc   Antoine Goutenoir   Fix home plot leg...
6
from flaskr.core import generate_unique_id, models
1b39d5ec   Goutte   Add a skeleton fo...
7
8
9
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin, AnonymousUserMixin
from werkzeug.security import generate_password_hash, check_password_hash
6a9e49da   Antoine Goutenoir   Load the output a...
10
from yaml import safe_load as yaml_load
f48f4a8f   Antoine Goutenoir   Optimize a bottle...
11
12
13
14

from content import get_path


1b39d5ec   Goutte   Add a skeleton fo...
15

c10e71f4   Antoine Goutenoir   Document the models.
16
17
18
19
20
21
22
# These are not the emission "models" in the scientific meaning of the word.
# They are the SQL Database Models.
# These are also named Entities, in other conventions (we're following flasks")
# If you're looking for the Emission Models (aka scaling laws),
# look in `flaskr/laws/`.


1b39d5ec   Goutte   Add a skeleton fo...
23
24
25
db = SQLAlchemy()


c10e71f4   Antoine Goutenoir   Document the models.
26
27
class StatusEnum(enum.Enum):
    pending = 'pending'
03c194bf   Antoine Goutenoir   Actually implemen...
28
    working = 'working'
c10e71f4   Antoine Goutenoir   Document the models.
29
    success = 'success'
5b6d9d3d   Antoine Goutenoir   Add a method to t...
30
    failure = 'failure'
c10e71f4   Antoine Goutenoir   Document the models.
31
32


a1f12452   Antoine Goutenoir   Add the new conte...
33
34
35
36
37
38
39
class ScenarioEnum(enum.Enum):
    one_to_one = 'one_to_one'
    many_to_one = 'many_to_one'
    one_to_many = 'one_to_many'
    many_to_many = 'many_to_many'


c10e71f4   Antoine Goutenoir   Document the models.
40
41
class Estimation(db.Model):
    id = db.Column(db.Integer(), primary_key=True)
fa3d2b43   Antoine Goutenoir   Conflate the data...
42
43
44
45
46
    public_id = db.Column(
        db.Unicode(),
        default=lambda: generate_unique_id(),
        unique=True
    )
c10e71f4   Antoine Goutenoir   Document the models.
47
48
49
    email = db.Column(db.Unicode(1024))
    first_name = db.Column(db.Unicode(1024))  # Antoine
    last_name = db.Column(db.Unicode(1024))   # Goutenoir
16f69d07   Antoine Goutenoir   Add an (unsecured...
50
    institution = db.Column(db.Unicode(1024))   # IRAP
fa3d2b43   Antoine Goutenoir   Conflate the data...
51
    status = db.Column(db.Enum(StatusEnum), default=StatusEnum.pending)
8ae021a2   Antoine Goutenoir   Merge shelved cha...
52
    run_name = db.Column(db.Unicode(1024))   # JPGU 2020
c10e71f4   Antoine Goutenoir   Document the models.
53
54
55

    # City, Country
    # One address per line
16f69d07   Antoine Goutenoir   Add an (unsecured...
56
57
    origin_addresses = db.Column(db.UnicodeText())
    destination_addresses = db.Column(db.UnicodeText())
c10e71f4   Antoine Goutenoir   Document the models.
58

322609d8   Antoine Goutenoir   Prepare the Emiss...
59
60
61
    # For (single, not round) trips below this distance, use the train
    use_train_below_km = db.Column(db.Integer())

a1f12452   Antoine Goutenoir   Add the new conte...
62
    # One slug per line (or blank char?)
466912a2   Antoine Goutenoir   Prepare the estim...
63
64
65
    models_slugs = db.Column(db.UnicodeText())

    # Deprecated, we detect this scenario from the amount of locations.
c10e71f4   Antoine Goutenoir   Document the models.
66
67
    compute_optimal_destination = db.Column(db.Boolean())

a1f12452   Antoine Goutenoir   Add the new conte...
68
69
    # Outputs
    scenario = db.Column(db.Enum(ScenarioEnum), default=ScenarioEnum.many_to_many)
dc6abfd1   Antoine Goutenoir   Add a separate fi...
70
71
    output_yaml = db.Column(db.UnicodeText())  # deprecated, use shelve file
    informations = db.Column(db.UnicodeText())
fa3d2b43   Antoine Goutenoir   Conflate the data...
72
73
74
    warnings = db.Column(db.UnicodeText())
    errors = db.Column(db.UnicodeText())

dc6abfd1   Antoine Goutenoir   Add a separate fi...
75
76
77
78
79
80
81
82
83
    @property
    def origins_count(self):
        return self.origin_addresses.strip().count("\n") + 1

    @property
    def destinations_count(self):
        return self.destination_addresses.strip().count("\n") + 1

    @property
5b6d9d3d   Antoine Goutenoir   Add a method to t...
84
85
    def has_failed(self):
        return self.status == StatusEnum.failure
c10e71f4   Antoine Goutenoir   Document the models.
86

8ae021a2   Antoine Goutenoir   Merge shelved cha...
87
88
89
90
91
    def get_display_name(self):
        if self.run_name:
            return self.run_name
        return self.public_id

f48f4a8f   Antoine Goutenoir   Optimize a bottle...
92
93
94
95
96
97
98
99
100
101
102
    def get_output_filename(self):
        runs_dir = get_path("var/runs")
        return join(runs_dir, self.public_id)

    def set_output_dict(self, output):
        # with shelve.open(filename=self.get_output_filename(), protocol=2) as shelf:
        #     shelf['output'] = output
        shelf = shelve.open(filename=self.get_output_filename(), protocol=2)
        shelf['output'] = output
        shelf.close()

a3e9d0fc   Antoine Goutenoir   Fix home plot leg...
103
104
    _output_dict = None

6a9e49da   Antoine Goutenoir   Load the output a...
105
    def get_output_dict(self):
a3e9d0fc   Antoine Goutenoir   Fix home plot leg...
106
        if self._output_dict is None:
ca35720c   Antoine Goutenoir   Fix typo.
107
            if self.output_yaml is None:
f48f4a8f   Antoine Goutenoir   Optimize a bottle...
108
109
110
111
112
113
114
115
116
117
118
                output_filename = self.get_output_filename()
                if isfile(output_filename):
                    # with shelve.open(filename=output_filename,
                    #                  protocol=2) as shelf:
                    #     self._output_dict = shelf['output']
                    shelf = shelve.open(filename=output_filename, protocol=2)
                    self._output_dict = shelf['output']
                    # self._output_dict = copy(shelf['output'])
                    shelf.close()
                else:
                    self._output_dict = None
37e28f2c   Antoine Goutenoir   Improve resilience.
119
120
            else:
                self._output_dict = yaml_load(self.output_yaml)
f48f4a8f   Antoine Goutenoir   Optimize a bottle...
121
        return self._output_dict
a1f12452   Antoine Goutenoir   Add the new conte...
122

dc6abfd1   Antoine Goutenoir   Add a separate fi...
123
    @property
a1f12452   Antoine Goutenoir   Add the new conte...
124
125
126
    def is_one_to_one(self):
        return self.scenario == ScenarioEnum.one_to_one

dc6abfd1   Antoine Goutenoir   Add a separate fi...
127
    @property
a1f12452   Antoine Goutenoir   Add the new conte...
128
129
130
    def is_one_to_many(self):
        return self.scenario == ScenarioEnum.one_to_many

dc6abfd1   Antoine Goutenoir   Add a separate fi...
131
    @property
a1f12452   Antoine Goutenoir   Add the new conte...
132
133
    def is_many_to_one(self):
        return self.scenario == ScenarioEnum.many_to_one
6a9e49da   Antoine Goutenoir   Load the output a...
134

dc6abfd1   Antoine Goutenoir   Add a separate fi...
135
    @property
a1f12452   Antoine Goutenoir   Add the new conte...
136
137
    def is_many_to_many(self):
        return self.scenario == ScenarioEnum.many_to_many
f3694728   Antoine Goutenoir   Display a summary.
138

a3e9d0fc   Antoine Goutenoir   Fix home plot leg...
139
140
141
142
143
144
145
146
    _models = None

    def get_models(self):
        if self._models is None:
            mdl_slugs = self.models_slugs.split("\n")
            self._models = [m for m in models if m.slug in mdl_slugs]
        return self._models

6a9e49da   Antoine Goutenoir   Load the output a...
147

16f69d07   Antoine Goutenoir   Add an (unsecured...
148
149
150
151
class EstimationView(ModelView):
    # Show only name and email columns in list view
    column_list = (
        'public_id',
8ae021a2   Antoine Goutenoir   Merge shelved cha...
152
        'run_name',
16f69d07   Antoine Goutenoir   Add an (unsecured...
153
154
155
        'status',
        'first_name',
        'last_name',
466912a2   Antoine Goutenoir   Prepare the estim...
156
        'models_slugs',
a1f12452   Antoine Goutenoir   Add the new conte...
157
        'scenario',
dc6abfd1   Antoine Goutenoir   Add a separate fi...
158
159
        'origins_count',
        'destinations_count',
16f69d07   Antoine Goutenoir   Add an (unsecured...
160
161
162
163
164
165
166
167
        'warnings',
        'errors',
    )

    # Enable search functionality - it will search for terms in
    # name and email fields
    # column_searchable_list = ('name', 'email')

16f69d07   Antoine Goutenoir   Add an (unsecured...
168
169
170
    column_filters = ('first_name', 'last_name')


c10e71f4   Antoine Goutenoir   Document the models.
171
172
# USERS #######################################################################

1b39d5ec   Goutte   Add a skeleton fo...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
class User(db.Model, UserMixin):
    id = db.Column(db.Integer(), primary_key=True)
    username = db.Column(db.String())
    password = db.Column(db.String())

    def __init__(self, username, password):
        self.username = username
        self.set_password(password)

    def set_password(self, password):
        self.password = generate_password_hash(password)

    def check_password(self, value):
        return check_password_hash(self.password, value)

    @property
    def is_authenticated(self):
        if isinstance(self, AnonymousUserMixin):
            return False
        else:
            return True

    def is_active(self):
        return True

    def is_anonymous(self):
        if isinstance(self, AnonymousUserMixin):
            return True
        else:
            return False

    def get_id(self):
        return self.id

    def __repr__(self):
fa3d2b43   Antoine Goutenoir   Conflate the data...
208
        return '<User %r>' % self.username