zou 0.20.45__py3-none-any.whl → 0.20.47__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
zou/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.20.45"
1
+ __version__ = "0.20.47"
@@ -101,6 +101,13 @@ class PersonsResource(BaseModelsResource):
101
101
  raise
102
102
  except:
103
103
  raise WrongParameterException("Expiration date is not valid.")
104
+
105
+ if "email" in data:
106
+ try:
107
+ data["email"] = auth.validate_email(data["email"])
108
+ except auth.EmailNotValidException as e:
109
+ raise WrongParameterException(str(e))
110
+
104
111
  return data
105
112
 
106
113
  def update_data(self, data):
@@ -184,6 +191,13 @@ class PersonResource(BaseModelResource, ArgsMixin):
184
191
  raise
185
192
  except:
186
193
  raise WrongParameterException("Expiration date is not valid.")
194
+
195
+ if "email" in data:
196
+ try:
197
+ data["email"] = auth.validate_email(data["email"])
198
+ except auth.EmailNotValidException as e:
199
+ raise WrongParameterException(str(e))
200
+
187
201
  return data
188
202
 
189
203
  def check_delete_permissions(self, instance_dict):
@@ -30,6 +30,7 @@ from zou.app.blueprints.projects.resources import (
30
30
  ProductionBudgetResource,
31
31
  ProductionBudgetEntriesResource,
32
32
  ProductionBudgetEntryResource,
33
+ ProductionMonthTimeSpentsResource,
33
34
  )
34
35
 
35
36
  routes = [
@@ -127,6 +128,10 @@ routes = [
127
128
  "/data/projects/<project_id>/budgets/<budget_id>/entries/<entry_id>",
128
129
  ProductionBudgetEntryResource,
129
130
  ),
131
+ (
132
+ "/data/projects/<project_id>/budgets/time-spents",
133
+ ProductionMonthTimeSpentsResource,
134
+ ),
130
135
  ]
131
136
 
132
137
  blueprint = Blueprint("projects", "projects")
@@ -5,9 +5,11 @@ from flask_jwt_extended import jwt_required
5
5
  from zou.app.services import budget_service
6
6
  from zou.app.mixin import ArgsMixin
7
7
  from zou.app.services import (
8
+ persons_service,
8
9
  projects_service,
9
10
  schedule_service,
10
11
  tasks_service,
12
+ time_spents_service,
11
13
  user_service,
12
14
  )
13
15
  from zou.app.utils import permissions
@@ -1494,3 +1496,33 @@ class ProductionBudgetEntryResource(Resource, ArgsMixin):
1494
1496
  user_service.check_manager_project_access(project_id)
1495
1497
  budget_service.delete_budget_entry(entry_id)
1496
1498
  return "", 204
1499
+
1500
+
1501
+ class ProductionMonthTimeSpentsResource(Resource, ArgsMixin):
1502
+
1503
+ @jwt_required()
1504
+ def get(self, project_id):
1505
+ """
1506
+ Get aggregated time spents by month for given project.
1507
+ ---
1508
+ tags:
1509
+ - Projects
1510
+ parameters:
1511
+ - in: path
1512
+ name: project_id
1513
+ required: True
1514
+ type: string
1515
+ format: UUID
1516
+ x-example: a24a6ea4-ce75-4665-a070-57453082c25
1517
+ responses:
1518
+ 200:
1519
+ description: Aggregated time spents for given person and month
1520
+ 400:
1521
+ description: Wrong ID format
1522
+ """
1523
+ permissions.check_admin_permissions()
1524
+ self.check_id_parameter(project_id)
1525
+ user = persons_service.get_current_user()
1526
+ return time_spents_service.get_project_month_time_spents(
1527
+ project_id, user["timezone"]
1528
+ )
zou/app/config.py CHANGED
@@ -88,6 +88,7 @@ MAIL_USE_SSL = envtobool("MAIL_USE_SSL", False)
88
88
  MAIL_DEFAULT_SENDER = os.getenv(
89
89
  "MAIL_DEFAULT_SENDER", "no-reply@your-studio.com"
90
90
  )
91
+ MAIL_CHECK_DELIVERABILITY = envtobool("MAIL_CHECK_DELIVERABILITY", True)
91
92
  DOMAIN_NAME = os.getenv("DOMAIN_NAME", "localhost:8080")
92
93
  DOMAIN_PROTOCOL = os.getenv("DOMAIN_PROTOCOL", "https")
93
94
 
@@ -7,6 +7,7 @@ from sqlalchemy.exc import DataError
7
7
  from sqlalchemy.orm import aliased
8
8
 
9
9
  from zou.app.models.day_off import DayOff
10
+ from zou.app.models.department import Department
10
11
  from zou.app.models.project import Project
11
12
  from zou.app.models.task import Task
12
13
  from zou.app.models.task_type import TaskType
@@ -535,3 +536,38 @@ def get_timezoned_interval(start, end):
535
536
  """
536
537
  timezone = user_service.get_timezone()
537
538
  return date_helpers.get_timezoned_interval(start, end, timezone)
539
+
540
+
541
+ def get_project_month_time_spents(project_id, timezone=None):
542
+ """
543
+ Get aggregated time spents by department by person by month for given
544
+ project.
545
+ """
546
+ data = {}
547
+ query = (
548
+ TimeSpent.query
549
+ .join(Task)
550
+ .join(TaskType, TaskType.id == Task.task_type_id)
551
+ .join(Department, Department.id == TaskType.department_id)
552
+ .filter(Task.project_id == project_id)
553
+ .add_columns(Department.id)
554
+ .order_by(TimeSpent.date)
555
+ )
556
+
557
+ for time_spent, department_id in query.all():
558
+ date_key = date_helpers.get_simple_string_with_timezone_from_date(
559
+ time_spent.date, timezone
560
+ )[0:7]
561
+ if department_id not in data:
562
+ data[department_id] = { "total": 0 }
563
+ if time_spent.person_id not in data[department_id]:
564
+ data[department_id][time_spent.person_id] = { "total": 0 }
565
+ if date_key not in data[department_id][time_spent.person_id]:
566
+ data[department_id][time_spent.person_id][date_key] = 0
567
+
568
+ data[department_id][time_spent.person_id][date_key] += \
569
+ time_spent.duration
570
+ data[department_id]["total"] += time_spent.duration
571
+ data[department_id][time_spent.person_id]["total"] += \
572
+ time_spent.duration
573
+ return data
zou/app/utils/auth.py CHANGED
@@ -23,9 +23,13 @@ def encrypt_password(password):
23
23
  return flask_bcrypt.generate_password_hash(password)
24
24
 
25
25
 
26
- def validate_email(email):
26
+ def validate_email(
27
+ email, check_deliverability=config.MAIL_CHECK_DELIVERABILITY
28
+ ):
27
29
  try:
28
- return email_validator.validate_email(email).normalized
30
+ return email_validator.validate_email(
31
+ email, check_deliverability=check_deliverability
32
+ ).normalized
29
33
  except email_validator.EmailNotValidError as e:
30
34
  raise EmailNotValidException(str(e))
31
35
 
zou/cli.py CHANGED
@@ -195,8 +195,8 @@ def create_admin(email, password):
195
195
  except auth.PasswordTooShortException:
196
196
  print("Password is too short.")
197
197
  sys.exit(1)
198
- except auth.EmailNotValidException:
199
- print("Email is not valid.")
198
+ except auth.EmailNotValidException as e:
199
+ print(f"Email is not valid: {e}")
200
200
  sys.exit(1)
201
201
  except IsUserLimitReachedException:
202
202
  print(f"User limit reached (limit {config.USER_LIMIT}).")
@@ -8,6 +8,12 @@ Create Date: 2025-05-02 16:08:57.078114
8
8
 
9
9
  from alembic import op
10
10
  import sqlalchemy as sa
11
+ from alembic import op
12
+ import sqlalchemy as sa
13
+ from zou.migrations.utils.base import BaseMixin
14
+ from sqlalchemy.ext.declarative import declarative_base
15
+ from sqlalchemy.dialects.postgresql import JSONB
16
+ from sqlalchemy.orm.session import Session
11
17
 
12
18
 
13
19
  # revision identifiers, used by Alembic.
@@ -16,6 +22,37 @@ down_revision = "e7e633bd6fa2"
16
22
  branch_labels = None
17
23
  depends_on = None
18
24
 
25
+ base = declarative_base()
26
+
27
+
28
+ class Task(base, BaseMixin):
29
+ """
30
+ Describes a task done by a CG artist on an entity of the CG production.
31
+ The task has a state and assigned to people. It handles notion of time like
32
+ duration, start date and end date.
33
+ """
34
+
35
+ __tablename__ = "task"
36
+ name = sa.Column(sa.String(80), nullable=False)
37
+ description = sa.Column(sa.Text())
38
+
39
+ priority = sa.Column(sa.Integer, default=0)
40
+ difficulty = sa.Column(sa.Integer, default=3, nullable=False)
41
+ duration = sa.Column(sa.Float, default=0)
42
+ estimation = sa.Column(sa.Float, default=0)
43
+ completion_rate = sa.Column(sa.Integer, default=0)
44
+ retake_count = sa.Column(sa.Integer, default=0)
45
+ sort_order = sa.Column(sa.Integer, default=0)
46
+ start_date = sa.Column(sa.DateTime)
47
+ due_date = sa.Column(sa.DateTime)
48
+ real_start_date = sa.Column(sa.DateTime)
49
+ end_date = sa.Column(sa.DateTime)
50
+ done_date = sa.Column(sa.DateTime)
51
+ last_comment_date = sa.Column(sa.DateTime)
52
+ nb_assets_ready = sa.Column(sa.Integer, default=0)
53
+ data = sa.Column(JSONB)
54
+ nb_drawings = sa.Column(sa.Integer, default=0)
55
+
19
56
 
20
57
  def upgrade():
21
58
  # ### commands auto generated by Alembic - please adjust! ###
@@ -33,6 +70,13 @@ def upgrade():
33
70
  )
34
71
 
35
72
  with op.batch_alter_table("task", schema=None) as batch_op:
73
+ session = Session(bind=op.get_bind())
74
+ session.query(Task).where(Task.difficulty == None).update(
75
+ {
76
+ Task.difficulty: 3,
77
+ }
78
+ )
79
+ session.commit()
36
80
  batch_op.alter_column(
37
81
  "difficulty",
38
82
  existing_type=sa.INTEGER(),
@@ -32,8 +32,6 @@ def upgrade():
32
32
 
33
33
  def downgrade():
34
34
  # ### commands auto generated by Alembic - please adjust! ###
35
- with op.batch_alter_table("task", schema=None) as batch_op:
36
- batch_op.alter_column(
37
- "difficulty", existing_type=sa.INTEGER(), nullable=True
38
- )
35
+ with op.batch_alter_table("budget_entry", schema=None) as batch_op:
36
+ batch_op.drop_column("exceptions")
39
37
  # ### end Alembic commands ###
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zou
3
- Version: 0.20.45
3
+ Version: 0.20.47
4
4
  Summary: API to store and manage the data of your animation production
5
5
  Home-page: https://zou.cg-wire.com
6
6
  Author: CG Wire
@@ -1,11 +1,11 @@
1
- zou/__init__.py,sha256=Q5HONztOdexYtfGvT0Sz0XIpt7YVrmTkt1mgM6IHQjM,24
2
- zou/cli.py,sha256=jj7gHYLKYxlOPIWH69tGYjPtJ43bhg6L5b9ueLkXuH4,22387
1
+ zou/__init__.py,sha256=d3ifraY4SFtace5KlJP00nLQYi316cHYzwCge7c-x3s,24
2
+ zou/cli.py,sha256=8YdBqJKEulAZ_1ohTdmpt_lf8EMjDmYiH8l0jVNlfG0,22397
3
3
  zou/debug.py,sha256=1fawPbkD4wn0Y9Gk0BiBFSa-CQe5agFi8R9uJYl2Uyk,520
4
4
  zou/event_stream.py,sha256=yTU1Z3r55SiYm8Y5twtJIo5kTnhbBK-XKc8apdgvzNw,8291
5
5
  zou/job_settings.py,sha256=_aqBhujt2Q8sXRWIbgbDf-LUdXRdBimdtTc-fZbiXoY,202
6
6
  zou/app/__init__.py,sha256=zGmaBGBHSS_Px34I3_WZmcse62G_AZJArjm4F6TwmRk,7100
7
7
  zou/app/api.py,sha256=Esgni_0-tAaE3msWxNMEdUS_wwIdElM0P2GrjhaHbCk,3727
8
- zou/app/config.py,sha256=eXVrmZf550Tk0fiN0Asfrhel0StesTDLTAYU6LdM3n4,6747
8
+ zou/app/config.py,sha256=6Yka0ox6GFOOYZavSDxAiFAslgFMJs12wpypPDjxjXs,6820
9
9
  zou/app/mixin.py,sha256=MGRrwLLRjWQtXHZ1YTaMgR5Jc8khnOrFqkvy2hzP5QY,5211
10
10
  zou/app/swagger.py,sha256=Jr7zsMqJi0V4FledODOdu-aqqVE02jMFzhqVxHK0_2c,54158
11
11
  zou/app/blueprints/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -45,7 +45,7 @@ zou/app/blueprints/crud/notification.py,sha256=A-KNH0IDNCXlE4AddNxvmsD_7a9HqHGo_
45
45
  zou/app/blueprints/crud/organisation.py,sha256=P1yzIwVB1AE0-ZfiZAVZkUl7hshIwV8OL0NF3DZS7gQ,1340
46
46
  zou/app/blueprints/crud/output_file.py,sha256=tz0NOoEUobNa8RMjl195S6uNP7PsPM-ajMOYWdHUhhE,3968
47
47
  zou/app/blueprints/crud/output_type.py,sha256=Uu7Q5iv-4SZDnxHkLk0vUE1N4k0bBUivXQUTsc58BU8,2012
48
- zou/app/blueprints/crud/person.py,sha256=k1EcYxD5C5p7tquAvJUpD2873-ITeF2ogMNIYRxWuDo,9427
48
+ zou/app/blueprints/crud/person.py,sha256=Ot1lTdMRm7BWaOuuTGGm-vrT9SlTlLueOJKR8aEBogY,9869
49
49
  zou/app/blueprints/crud/playlist.py,sha256=he8iXoWnjBVXzkB_y8aGnZ6vQ_7hGSf-ALofLFoqx1U,1890
50
50
  zou/app/blueprints/crud/plugin.py,sha256=azDWurAX8KUD4FXwhCpo8q0qRUVG8TG4Dg8oib1aOzc,356
51
51
  zou/app/blueprints/crud/preview_background_file.py,sha256=TRJlVQ3nGOYVkA6kxIlNrip9bjkUaknVNCIUYw8uJYk,2451
@@ -96,8 +96,8 @@ zou/app/blueprints/playlists/__init__.py,sha256=vuEk1F3hFHsmuKWhdepMoLyOzmNKDn1Y
96
96
  zou/app/blueprints/playlists/resources.py,sha256=mF3gmlWpe9YKyyKVRUXYtvTCk7OguWIMVaCN_J_JPS4,17636
97
97
  zou/app/blueprints/previews/__init__.py,sha256=ihC6OQ9AUjnZ2JeMnjRh_tKGO0UmAjOwhZnOivc3BnQ,4460
98
98
  zou/app/blueprints/previews/resources.py,sha256=uyjfW3vyE2a1PPXO8MsHP8-3jhuVKHt3oi2pYsq-ZIw,53376
99
- zou/app/blueprints/projects/__init__.py,sha256=setMMX-aPrAUUuRJCdH2kJaYMwSMB6XbT9Tx6c63dBY,4489
100
- zou/app/blueprints/projects/resources.py,sha256=fPtUb16ptifM1iplMhaDajB6RhRqp0cJQvnEZPwlEx4,44024
99
+ zou/app/blueprints/projects/__init__.py,sha256=KhzIn5HvemfvsP5yJBMImdsEuTA_P806kRpoNbAdfIs,4643
100
+ zou/app/blueprints/projects/resources.py,sha256=7WAJU0Y7-IzDvsybsPk826yGEQZA84nbGy0xfn-_d8g,44955
101
101
  zou/app/blueprints/search/__init__.py,sha256=QCjQIY_85l_orhdEiqav_GifjReuwsjZggN3V0GeUVY,356
102
102
  zou/app/blueprints/search/resources.py,sha256=_QgRlUuxCPgY-ip5r2lGFtXNcGSE579JsCSrVf8ajVU,3093
103
103
  zou/app/blueprints/shots/__init__.py,sha256=EcG9qmAchlucqg1M6-RqWGfuKpa5Kq6RgyLZNSsjUr4,4225
@@ -222,7 +222,7 @@ zou/app/services/status_automations_service.py,sha256=tVio7Sj7inhvKS4UOyRhcdpwr_
222
222
  zou/app/services/sync_service.py,sha256=iWxx1kOGEXympHmSBBQWtDZWNtumdxp8kppee0OefMo,41811
223
223
  zou/app/services/tasks_service.py,sha256=D-u-8W3rIg00Nqp7MuG1WSOcPANE4XXliKpVwm5NbVU,69815
224
224
  zou/app/services/telemetry_services.py,sha256=xQm1h1t_JxSFW59zQGf4NuNdUi1UfMa_6pQ-ytRbmGA,1029
225
- zou/app/services/time_spents_service.py,sha256=H9X-60s6oqtY9rtU-K2jKwUSljfkdGlf_9wMr3iVfIA,15158
225
+ zou/app/services/time_spents_service.py,sha256=sjyDqQKDpnmDm-lPLCd2FxYBE6pOVZEgommwZcAjGk8,16498
226
226
  zou/app/services/user_service.py,sha256=rvo_e_JkPdTqIOE3FETXlUXnuS8n0lLyovTpwApyt8I,51470
227
227
  zou/app/stores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
228
228
  zou/app/stores/auth_tokens_store.py,sha256=-qOJPybLHvnMOq3PWk073OW9HJwOHGhFLZeOIlX1UVw,1290
@@ -231,7 +231,7 @@ zou/app/stores/publisher_store.py,sha256=ggpb68i_wCfcuWicmxv8B1YPLXwHmcZo2reqcLn
231
231
  zou/app/stores/queue_store.py,sha256=udbZSm3Rfwi-zwSRzVz-0qjdrVYbUWA8WwuIsdQikn8,669
232
232
  zou/app/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
233
233
  zou/app/utils/api.py,sha256=28ys2SMso1wt0q7r-4ohx9Izx-cKHxQhCmxfTvTMeFs,705
234
- zou/app/utils/auth.py,sha256=DZfZSr1Ulge0UK3hfvOWsMo3_d7RVP_llV118u9BtUI,870
234
+ zou/app/utils/auth.py,sha256=o9lOGgj3nkfsupfhLBre5fUuT1HBZgXVJU06lrdZGag,996
235
235
  zou/app/utils/cache.py,sha256=MRluTvGG67ybOkyzgD70B6PGKMdRyFdTc0AYy3dEQe8,1210
236
236
  zou/app/utils/chats.py,sha256=ORngxQ3IQQF0QcVFJLxJ-RaU4ksQ9-0M8cmPa0pc0Ho,4302
237
237
  zou/app/utils/colors.py,sha256=LaGV17NL_8xY0XSp8snGWz5UMwGnm0KPWXyE5BTMG6w,200
@@ -407,7 +407,7 @@ zou/migrations/versions/cf3d365de164_add_entity_version_model.py,sha256=n3k3ojRQ
407
407
  zou/migrations/versions/cf6cec6d6bf5_add_status_field_to_preview_file.py,sha256=0c8_OghAaaM0R6bKbs7MADvOkZ1sFE3SVp_nNB2ACgQ,950
408
408
  zou/migrations/versions/d25118cddcaa_modify_salary_scale_model.py,sha256=hjrfR0tnxAAfVgAG_Fqi2He4PqDyoqX6pOaj5TrmEJc,3814
409
409
  zou/migrations/versions/d80267806131_task_status_new_column_is_default.py,sha256=7HtK0bfBUh9MrJIbpUgz6S-Ye_R_4DbHILpODMBVVwE,2610
410
- zou/migrations/versions/d80f02824047_add_plugin_revision.py,sha256=xaVdA7_a3MXXu1McNqpBstN_HF1oyp9i2RO4rYBbkSs,1944
410
+ zou/migrations/versions/d80f02824047_add_plugin_revision.py,sha256=p_OYtHamUwSiWJxY00UwOVWoiCuqIac73nW6nVNBdXw,3534
411
411
  zou/migrations/versions/d8dcd5196d57_add_casting_label.py,sha256=TO4dlWblBzwAcs9Vx4fJVoMsdy2XuF7OncFn8N6BSe8,687
412
412
  zou/migrations/versions/de8a3de227ef_.py,sha256=3spU6b2kSApcMi9NomIRQGmoNtYos137krVrmdJWLCQ,1319
413
413
  zou/migrations/versions/deeacd38d373_for_projecttaskstatuslink_set_default_.py,sha256=eJsmrxTv1AP47_M0wXzUxIUf3xr904WY05MNYmnCcCg,1821
@@ -416,7 +416,7 @@ zou/migrations/versions/df9f8a147e80_change_file_size_to_big_integer.py,sha256=o
416
416
  zou/migrations/versions/e1ef93f40d3d_.py,sha256=6qs4bZPzh9pBM8MgAtogz1pXqjrvyBpwkNr-1w4RzRo,708
417
417
  zou/migrations/versions/e29638428dfd_add_schedule_item_table.py,sha256=M9ZoAmc-wpZsgbzdMIFeFmHPNxST8NR2L-VlcjZ3hIU,2711
418
418
  zou/migrations/versions/e3f6db74cc1e_.py,sha256=dIFNZuDzemSZRcbn9m5b8HnjCNR0ufiGwLkQEjFFcco,907
419
- zou/migrations/versions/e7e633bd6fa2_add_exceptions_to_budget_entries.py,sha256=rcG1DNHVvXRQ6mp8Z4XW_bcCDBoBriUm33ufcd1zmx4,1036
419
+ zou/migrations/versions/e7e633bd6fa2_add_exceptions_to_budget_entries.py,sha256=ab1K8GHcMLkaYW4TkMUQnZcDg9RlD3YLtpVS0jpyps8,978
420
420
  zou/migrations/versions/e839d6603c09_add_person_id_to_shot_history.py,sha256=MFKReFog5-kR2ftgY7J7Gd3slcMHpPUCyzCGw0Wr-5U,1295
421
421
  zou/migrations/versions/ee2373fbe3a4_.py,sha256=_m4Awx8OxqCTN-deyq8dx9xvDEcNumibrqZ_7DXav-o,5666
422
422
  zou/migrations/versions/f0567e8d0c62_.py,sha256=ZsyaVPAUrN1biNNxdQbOyGjG3KjoBiHXM3CcuLJxwac,1138
@@ -446,9 +446,9 @@ zou/remote/normalize_movie.py,sha256=zNfEY3N1UbAHZfddGONTg2Sff3ieLVWd4dfZa1dpnes
446
446
  zou/remote/playlist.py,sha256=AsDo0bgYhDcd6DfNRV6r6Jj3URWwavE2ZN3VkKRPbLU,3293
447
447
  zou/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
448
448
  zou/utils/movie.py,sha256=d67fIL9dVBKt-E_qCGXRbNNdbJaJR5sHvZeX3hf8ldE,16559
449
- zou-0.20.45.dist-info/licenses/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
450
- zou-0.20.45.dist-info/METADATA,sha256=yvpu1v7afWpMCHzg5A3GGMEO6O5CUYzWsYdc2ws0L_w,6826
451
- zou-0.20.45.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
452
- zou-0.20.45.dist-info/entry_points.txt,sha256=PelQoIx3qhQ_Tmne7wrLY-1m2izuzgpwokoURwSohy4,130
453
- zou-0.20.45.dist-info/top_level.txt,sha256=4S7G_jk4MzpToeDItHGjPhHx_fRdX52zJZWTD4SL54g,4
454
- zou-0.20.45.dist-info/RECORD,,
449
+ zou-0.20.47.dist-info/licenses/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
450
+ zou-0.20.47.dist-info/METADATA,sha256=vpHO5UNC_iBIrLrSzzgqIC1RTFE5bqLgp513rmkAyc8,6826
451
+ zou-0.20.47.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
452
+ zou-0.20.47.dist-info/entry_points.txt,sha256=PelQoIx3qhQ_Tmne7wrLY-1m2izuzgpwokoURwSohy4,130
453
+ zou-0.20.47.dist-info/top_level.txt,sha256=4S7G_jk4MzpToeDItHGjPhHx_fRdX52zJZWTD4SL54g,4
454
+ zou-0.20.47.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5