@planning-inspectorate/data-model 2.49.0 → 2.50.0

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.
Files changed (31) hide show
  1. package/docs/README.md +23 -1
  2. package/docs/address.md +366 -0
  3. package/docs/applications-application-defs-address.md +108 -0
  4. package/docs/applications-application-defs-contact.md +98 -0
  5. package/docs/applications-application-defs-organisation.md +117 -0
  6. package/docs/applications-application-defs.md +3 -0
  7. package/docs/{application-update.md → applications-application-update.md} +22 -22
  8. package/docs/applications-application.md +2250 -0
  9. package/docs/applications-notify-email-defs-contact.md +93 -0
  10. package/docs/applications-notify-email-defs.md +3 -0
  11. package/docs/applications-notify-email.md +458 -0
  12. package/docs/applications-representation-definitions-contact.md +93 -0
  13. package/docs/applications-representation-definitions-representationdocument.md +152 -0
  14. package/docs/applications-representation-definitions.md +3 -0
  15. package/docs/applications-representation.md +834 -0
  16. package/package.json +1 -1
  17. package/pins_data_model/models/model_address.py +69 -0
  18. package/pins_data_model/models/model_applications_application.py +518 -0
  19. package/pins_data_model/models/model_applications_application_update.py +55 -0
  20. package/pins_data_model/models/model_applications_notify_email.py +124 -0
  21. package/pins_data_model/models/model_applications_representation.py +207 -0
  22. package/schemas/address.schema.json +87 -0
  23. package/schemas/{application-update.schema.json → applications-application-update.schema.json} +1 -1
  24. package/schemas/applications-application.schema.json +539 -0
  25. package/schemas/applications-notify-email.schema.json +118 -0
  26. package/schemas/applications-representation.schema.json +202 -0
  27. package/src/enums.cjs +147 -0
  28. package/src/enums.d.ts +131 -0
  29. package/src/enums.js +131 -0
  30. package/src/index.cjs +147 -0
  31. package/src/schemas.d.ts +678 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planning-inspectorate/data-model",
3
- "version": "2.49.0",
3
+ "version": "2.50.0",
4
4
  "description": "JSON Schemas for the Planning Inspectorate's Data Model",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -0,0 +1,69 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: address.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from enum import Enum
7
+ from typing import Any
8
+
9
+ from pydantic import BaseModel, ConfigDict, Field
10
+
11
+
12
+ class AddressType(Enum):
13
+ """
14
+ The type of thing this address is for.
15
+ """
16
+
17
+ site = "site"
18
+ neighbouring = "neighbouring"
19
+ organisation = "organisation"
20
+ contact = "contact"
21
+
22
+
23
+ class PinsAddressSchema(BaseModel):
24
+ """
25
+ A schema to define the structure of an Address object in PINS.
26
+ """
27
+
28
+ model_config = ConfigDict(
29
+ extra="allow",
30
+ )
31
+ addressDimKey: float = Field(..., examples=[12345])
32
+ """
33
+ Primary Key for an Address.
34
+ """
35
+ addressType: AddressType | None = Field(None, examples=["site"])
36
+ """
37
+ The type of thing this address is for.
38
+ """
39
+ caseReference: str = Field(..., examples=["CROWN/2025/12345"])
40
+ """
41
+ Business Key for the related case
42
+ """
43
+ caseId: str = Field(..., examples=["AAAAAAAA-1234-1234-1234-AAAAAAAAAAAA"])
44
+ """
45
+ The unique ID for the case this representation belongs to.
46
+ """
47
+ caseType: str = Field(..., examples=["Crown Development Application"])
48
+ """
49
+ The type of case this representation is for.
50
+ """
51
+ description: str | None = Field(None, examples=["The field behind the crown pub"])
52
+ """
53
+ Some sites may have a postcode, but do not have postal addresses.
54
+ """
55
+ line1: str | None = None
56
+ line2: str | None = None
57
+ townCity: str | None = None
58
+ county: str | None = None
59
+ postcode: str | None = None
60
+ country: str | None = None
61
+ easting: str | None = Field(None, examples=["358267"])
62
+ northing: str | None = Field(None, examples=["172797"])
63
+ latitudeWGS84: float | None = Field(None, examples=[51.452608])
64
+ longitudeWGS84: float | None = Field(None, examples=[-2.6019821])
65
+ UPRN: str | None = Field(None, examples=[100023336956])
66
+ """
67
+ The Unique Property Reference Number (UPRN) is a unique number (a geocode) for every addressable location—e.g., a building, a bus stop, a post box, a feature in the landscape, or a defibrillator—in Great Britain.
68
+ """
69
+ dependentRequired: Any | None = None
@@ -0,0 +1,518 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: applications-application.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from enum import Enum
7
+
8
+ from pydantic import AwareDatetime, BaseModel, ConfigDict, Field
9
+
10
+
11
+ class Type(Enum):
12
+ """
13
+ Type of application. Name displayed to users
14
+ """
15
+
16
+ Planning_permission = "Planning permission"
17
+ Outline_planning_permission_with_some_matters_reserved = (
18
+ "Outline planning permission with some matters reserved"
19
+ )
20
+ Outline_planning_permission_with_all_matters_reserved = (
21
+ "Outline planning permission with all matters reserved"
22
+ )
23
+ Approval_of_reserved_matters_following_outline_approval = (
24
+ "Approval of reserved matters following outline approval"
25
+ )
26
+ Planning_permission_and_listed_building_consent__LBC__for_alterations__extension_or_demolition_of_a_listed_building = "Planning permission and listed building consent (LBC) for alterations, extension or demolition of a listed building"
27
+
28
+
29
+ class SubType(Enum):
30
+ """
31
+ SubType applies to Planning permissions and LBC
32
+ """
33
+
34
+ Planning_permission = "Planning permission"
35
+ Listed_building_consent__LBC_ = "Listed building consent (LBC)"
36
+
37
+
38
+ class ApplicationStatus(Enum):
39
+ """
40
+ Current status of the case (enum)
41
+ """
42
+
43
+ New = "New"
44
+ Accepted = "Accepted"
45
+ Invalid = "Invalid"
46
+ Consultation_period_open = "Consultation period open"
47
+ Hearing_Inquiry_date_set = "Hearing/Inquiry date set"
48
+ Application_on_hold_awaiting_further_information = (
49
+ "Application on hold awaiting further information"
50
+ )
51
+ Report_awaited = "Report awaited"
52
+ Report_sent_to_Decision_Branch = "Report sent to Decision Branch"
53
+ Decision_awaited = "Decision awaited"
54
+ Decided = "Decided"
55
+ Withdrawn = "Withdrawn"
56
+ Declined_to_determine = "Declined to determine"
57
+ Closed___invalid = "Closed - invalid"
58
+ Closed___opened_in_error = "Closed - opened in error"
59
+
60
+
61
+ class ApplicationStage(Enum):
62
+ """
63
+ Current stage of the case (enum)
64
+ """
65
+
66
+ Accepted = "Accepted"
67
+ Consultation = "Consultation"
68
+ Procedure_choice = "Procedure choice"
69
+ Written_representations = "Written representations"
70
+ Inquiry = "Inquiry"
71
+ Hearing_Inquiry_date_set = "Hearing/Inquiry date set"
72
+ Final_decision = "Final decision"
73
+
74
+
75
+ class Category(Enum):
76
+ """
77
+ Application category (enum)
78
+ """
79
+
80
+ Major_Development = "Major Development"
81
+ Buildings_over_1000_square_metres = "Buildings over 1000 square metres"
82
+ Development_of_a_site_above_1_hectare = "Development of a site above 1 hectare"
83
+ Dwellings_numbering_10_or_more = "Dwellings numbering 10 or more"
84
+ Dwellings_of_0_5_hectare_or_more = "Dwellings of 0.5 hectare or more"
85
+ Minerals = "Minerals"
86
+ Waste = "Waste"
87
+ Non_Major_Development = "Non-Major Development"
88
+ Buildings_less_than_1000_square_metres = "Buildings less than 1000 square metres"
89
+ Development_of_a_site_less_than_1_hectare = (
90
+ "Development of a site less than 1 hectare"
91
+ )
92
+ Dwellings_numbering_between_1_and_9 = "Dwellings numbering between 1 and 9"
93
+ Dwellings_of_less_than_0_5_hectare = "Dwellings of less than 0.5 hectare"
94
+ Change_of_use = "Change of use"
95
+ Relevant_demolition = "Relevant demolition"
96
+ Other = "Other"
97
+ Listed_building_consent_to_alter_extend = "Listed building consent to alter/extend"
98
+ Listed_building_consent_to_demolish = "Listed building consent to demolish"
99
+
100
+
101
+ class DecisionOutcome(Enum):
102
+ """
103
+ As displayed to users
104
+ """
105
+
106
+ Approved = "Approved"
107
+ Approved_with_conditions = "Approved with conditions"
108
+ Refused = "Refused"
109
+ Withdrawn = "Withdrawn"
110
+
111
+
112
+ class EiaScreeningOutcome(Enum):
113
+ """
114
+ What was the outcome of the Environmental Impact Assessment
115
+ """
116
+
117
+ required = "required"
118
+ not_required = "not required"
119
+
120
+
121
+ class Procedure(Enum):
122
+ """
123
+ Name displayed to users
124
+ """
125
+
126
+ Written_Representations = "Written Representations"
127
+ Hearing = "Hearing"
128
+ Inquiry = "Inquiry"
129
+
130
+
131
+ class RoleType(Enum):
132
+ """
133
+ Agent or Applicant details
134
+ """
135
+
136
+ agent = "agent"
137
+ applicant = "applicant"
138
+
139
+
140
+ class ContactPreference(Enum):
141
+ email = "email"
142
+ post = "post"
143
+
144
+
145
+ class Contact(BaseModel):
146
+ model_config = ConfigDict(
147
+ extra="allow",
148
+ )
149
+ contactId: str = Field(..., examples=["AAAAAAAA-1234-1234-1234-AAAAAAAAAAAA"])
150
+ """
151
+ Source PK for Contact
152
+ """
153
+ contactPreference: ContactPreference | None = Field(None, examples=["email"])
154
+ writtenRepOrgName: str | None = None
155
+ """
156
+ Organisation Name used for written-representation on behalf of an organisation
157
+ """
158
+ writtenRepJobTitleorRole: str | None = None
159
+ """
160
+ Job Title or Role used for written-representation on behalf of an organisation
161
+ """
162
+
163
+
164
+ class Address(BaseModel):
165
+ model_config = ConfigDict(
166
+ extra="allow",
167
+ )
168
+ line1: str | None = None
169
+ line2: str | None = None
170
+ townCity: str | None = None
171
+ county: str | None = None
172
+ postcode: str
173
+
174
+
175
+ class Organisation(BaseModel):
176
+ model_config = ConfigDict(
177
+ extra="allow",
178
+ )
179
+ roleType: RoleType | None = Field(None, examples=["agent"])
180
+ """
181
+ Agent or Applicant details
182
+ """
183
+ organisationId: str = Field(..., examples=["AAAAAAAA-1234-1234-1234-AAAAAAAAAAAA"])
184
+ """
185
+ Source PK for Organisation
186
+ """
187
+ organisationName: str | None = None
188
+ organisationAddress: list[Address] | None = None
189
+ contacts: list[Contact] | None = None
190
+ """
191
+ An Organisation may be linked to one or more Contacts
192
+ """
193
+
194
+
195
+ class CrownDevelopmentApplication(BaseModel):
196
+ """
197
+ Main application details for Crown Development Project
198
+ """
199
+
200
+ model_config = ConfigDict(
201
+ extra="allow",
202
+ )
203
+ id: str = Field(..., examples=["AAAAAAAA-1234-1234-1234-AAAAAAAAAAAA"])
204
+ """
205
+ Internal Identifier UUID
206
+ """
207
+ reference: str = Field(..., examples=["CROWN/2025/12345"])
208
+ """
209
+ External Identifier: CROWN/YYYY/XXXXXXX
210
+ """
211
+ createdDate: AwareDatetime
212
+ """
213
+ Date the case was created
214
+ """
215
+ updatedDate: AwareDatetime | None = None
216
+ """
217
+ Date the case was updated
218
+ """
219
+ type: Type = Field(
220
+ ..., examples=["Outline planning permission with some matters reserved"]
221
+ )
222
+ """
223
+ Type of application. Name displayed to users
224
+ """
225
+ subType: SubType | None = Field(None, examples=["Listed building consent (LBC)"])
226
+ """
227
+ SubType applies to Planning permissions and LBC
228
+ """
229
+ linkedParentId: str | None = Field(
230
+ None, examples=["AAAAAAAA-1234-1234-1234-AAAAAAAAAAAA"]
231
+ )
232
+ """
233
+ Self-referencial for parent to children relationship
234
+ """
235
+ description: str | None = None
236
+ """
237
+ Description of the project
238
+ """
239
+ primaryLPACode: str | None = Field(None, examples=["Z0116"])
240
+ """
241
+ Primary Planning Body code
242
+ """
243
+ secondaryLPACode: str | None = Field(None, examples=["Z0116"])
244
+ """
245
+ Secondary LPAs when project overlaps authorities
246
+ """
247
+ hasAgent: bool
248
+ """
249
+ Is an agent assigned to the case on behalf of the applicant
250
+ """
251
+ organisations: list[Organisation] | None = None
252
+ """
253
+ Applications can have one or more organisaitons associated with them.
254
+ """
255
+ siteAddress: list[Address] | None = None
256
+ """
257
+ Site Address details
258
+ """
259
+ siteEasting: str | None = Field(None, examples=["216600"])
260
+ """
261
+ Easting of the site, if known
262
+ """
263
+ siteNorthing: str | None = Field(None, examples=["771200"])
264
+ """
265
+ Northing of the site, if known
266
+ """
267
+ siteArea: float | None = Field(None, examples=[4.44])
268
+ """
269
+ Site area in hectares
270
+ """
271
+ expectedDateOfSubmission: AwareDatetime | None = None
272
+ """
273
+ Date case officer expects the application to be submitted (NB: cases are created before document submissions as applicants upload directly)
274
+ """
275
+ applicationStatus: ApplicationStatus | None = None
276
+ """
277
+ Current status of the case (enum)
278
+ """
279
+ applicationStage: ApplicationStage | None = None
280
+ """
281
+ Current stage of the case (enum)
282
+ """
283
+ nationallyImportant: bool | None = None
284
+ """
285
+ Site is nationally important (Yes/No)
286
+ """
287
+ nationallyImportantConfirmationDate: AwareDatetime | None = None
288
+ """
289
+ Date the application's national importance was confirmed
290
+ """
291
+ notNationallyImportantEmailSent: bool | None = None
292
+ """
293
+ Flags if a notNationallyImportant email has been sent
294
+ """
295
+ containsDistressingContent: bool | None = None
296
+ """
297
+ Highlights the cases as containing distressing content
298
+ """
299
+ lpaReference: str | None = None
300
+ """
301
+ LPA cross reference. Reference number for the case as known by the Local Planning Authority (LPA)
302
+ """
303
+ category: Category | None = None
304
+ """
305
+ Application category (enum)
306
+ """
307
+ isGreenBelt: bool | None = None
308
+ """
309
+ Is the site in green belt land
310
+ """
311
+ healthAndSafetyIssue: bool | None = None
312
+ """
313
+ Does the Site has H&S Issue
314
+ """
315
+ applicationReceivedDate: AwareDatetime | None = None
316
+ """
317
+ Date the application was received
318
+ """
319
+ applicationReceivedDateEmailSent: bool | None = None
320
+ """
321
+ Flags if an applicationReceived email has been sent
322
+ """
323
+ applicationAcceptedDate: AwareDatetime | None = None
324
+ """
325
+ Date the application was accepted
326
+ """
327
+ lpaQuestionnaireSentDate: AwareDatetime | None = None
328
+ """
329
+ Date the lpa questionnaire was sent
330
+ """
331
+ lpaQuestionnaireReceivedDate: AwareDatetime | None = None
332
+ """
333
+ Date the lpa questionnaire was received
334
+ """
335
+ lpaQuestionnaireReceivedEmailSent: bool | None = None
336
+ """
337
+ Flags if an lpaQuestionnaireReceived email has been sent
338
+ """
339
+ publishDate: AwareDatetime | None = None
340
+ """
341
+ Date the application was published to the portal
342
+ """
343
+ pressNoticeDate: AwareDatetime | None = None
344
+ """
345
+ Date the press notice was published
346
+ """
347
+ neighboursNotifiedByLpaDate: AwareDatetime | None = None
348
+ """
349
+ Date the neighbours were notified by the LPA
350
+ """
351
+ siteNoticeByLpaDate: AwareDatetime | None = None
352
+ """
353
+ Date the site notice was erected by the LPA
354
+ """
355
+ targetDecisionDate: AwareDatetime | None = None
356
+ """
357
+ Date the application should be decided by
358
+ """
359
+ extendedTargetDecisionDate: AwareDatetime | None = None
360
+ """
361
+ Extended date by which the application should be decided
362
+ """
363
+ recoveredDate: AwareDatetime | None = None
364
+ """
365
+ Date the application was recovered by the Secretary of State
366
+ """
367
+ recoveredReportSentDate: AwareDatetime | None = None
368
+ """
369
+ Date the Inspector's report was sent to the Secretary of State
370
+ """
371
+ withdrawnDate: AwareDatetime | None = None
372
+ """
373
+ Date application was withdrawn
374
+ """
375
+ decisionDate: AwareDatetime | None = None
376
+ """
377
+ Date the application was decided on
378
+ """
379
+ originalDecisionDate: AwareDatetime | None = None
380
+ """
381
+ Date of the original decision if later quashed
382
+ """
383
+ decisionOutcome: DecisionOutcome | None = None
384
+ """
385
+ As displayed to users
386
+ """
387
+ turnedAwayDate: AwareDatetime | None = None
388
+ """
389
+ Date application was turned away
390
+ """
391
+ representationsPublishDate: AwareDatetime | None = None
392
+ """
393
+ Date the representations was publish
394
+ """
395
+ representationsPeriodStartDate: AwareDatetime | None = None
396
+ """
397
+ Start date of the representation period (starts at 00:00)
398
+ """
399
+ representationsPeriodEndDate: AwareDatetime | None = None
400
+ """
401
+ End date of the representation period (ends at 23:59)
402
+ """
403
+ inspector1Id: str | None = None
404
+ """
405
+ EntraID for Inspector
406
+ """
407
+ inspector2Id: str | None = None
408
+ """
409
+ EntraID for Inspector
410
+ """
411
+ inspector3Id: str | None = None
412
+ """
413
+ EntraID for Inspector
414
+ """
415
+ assessorInspectorId: str | None = None
416
+ """
417
+ EntraID for Assessor
418
+ """
419
+ caseOfficerId: str | None = None
420
+ """
421
+ EntraID for Case Officer
422
+ """
423
+ planningOfficerId: str | None = None
424
+ """
425
+ EntraID for Planning Officer
426
+ """
427
+ eiaScreening: bool | None = None
428
+ """
429
+ Does the application need an Environmental Impact Assessment
430
+ """
431
+ eiaScreeningOutcome: EiaScreeningOutcome | None = None
432
+ """
433
+ What was the outcome of the Environmental Impact Assessment
434
+ """
435
+ environmentalStatementReceivedDate: AwareDatetime | None = None
436
+ """
437
+ Date the environmental statement was received
438
+ """
439
+ siteIsVisibleFromPublicLand: bool | None = None
440
+ """
441
+ Site is visible from public land (Yes/No or TRUE/FALSE tbc)
442
+ """
443
+ procedure: Procedure | None = None
444
+ """
445
+ Name displayed to users
446
+ """
447
+ procedureNotificationDate: AwareDatetime | None = None
448
+ eventDate: AwareDatetime | None = None
449
+ eventPrepDuration: float | None = Field(None, examples=[1234.56])
450
+ eventSittingDuration: float | None = Field(None, examples=[1234.56])
451
+ eventReportingDuration: float | None = Field(None, examples=[1234.56])
452
+ eventVenue: str | None = None
453
+ eventNotificationDate: AwareDatetime | None = None
454
+ eventIssuesReportPublishedDate: AwareDatetime | None = None
455
+ eventStatementsDate: AwareDatetime | None = None
456
+ eventCaseManagementConferenceDate: AwareDatetime | None = None
457
+ eventPreMeetingDate: AwareDatetime | None = None
458
+ eventProofsOfEvidenceDate: AwareDatetime | None = None
459
+ hasApplicationFee: bool | None = None
460
+ """
461
+ Application has associated Fee (Yes/No or TRUE/FALSE tbc)
462
+ """
463
+ applicationFee: float | None = None
464
+ """
465
+ The amount to be payed by the Applicant
466
+ """
467
+ applicationFeeReceivedDate: AwareDatetime | None = None
468
+ """
469
+ Date the application fee was received
470
+ """
471
+ eligibleForFeeRefund: bool | None = None
472
+ """
473
+ Is the applicant eligible for a refund on the fee
474
+ """
475
+ applicationFeeRefundAmount: float | None = None
476
+ """
477
+ The amount to be refunded to the Applicant
478
+ """
479
+ applicationFeeRefundDate: AwareDatetime | None = None
480
+ """
481
+ Date the application fee was refunded
482
+ """
483
+ siteVisitDate: AwareDatetime | None = None
484
+ """
485
+ Date the site was/is going to be visited by the inspector
486
+ """
487
+ cilLiable: bool | None = None
488
+ """
489
+ Is the application liable for a community infrastructure levy
490
+ """
491
+ cilAmount: float | None = None
492
+ """
493
+ The amount for the community infrastructure levy
494
+ """
495
+ bngExempt: bool | None = None
496
+ """
497
+ Is the site exempt from the Biodiversity Net Gain
498
+ """
499
+ hasCostsApplications: bool | None = None
500
+ """
501
+ If a party is making a cost claim against another for unreasonable behaviour
502
+ """
503
+ costsApplicationsComment: str | None = None
504
+ """
505
+ Details about the cost application
506
+ """
507
+ environmentalImpactAssessment: bool | None = None
508
+ """
509
+ Does the application have an Environmental Impact Assessment - used for context in emails to LPAs
510
+ """
511
+ developmentPlan: bool | None = None
512
+ """
513
+ Is the application a standard development plan - used for context in emails to LPAs
514
+ """
515
+ rightOfWay: bool | None = None
516
+ """
517
+ Does the application apply to rights of way - used for context in emails to LPAs
518
+ """
@@ -0,0 +1,55 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: applications-application-update.schema.json
3
+
4
+ from __future__ import annotations
5
+
6
+ from enum import Enum
7
+
8
+ from pydantic import AwareDatetime, BaseModel, ConfigDict, Field
9
+
10
+
11
+ class ApplicationUpdateStatus(Enum):
12
+ """
13
+ Application Update Status. Name displayed to users, e.g. Draft
14
+ """
15
+
16
+ Draft = "Draft"
17
+ Published = "Published"
18
+ Unpublished = "Unpublished"
19
+
20
+
21
+ class ApplicationUpdateSchema(BaseModel):
22
+ """
23
+ Application Update for Casework Project
24
+ """
25
+
26
+ model_config = ConfigDict(
27
+ extra="allow",
28
+ )
29
+ id: str = Field(..., examples=["AAAAAAAA-1234-1234-1234-AAAAAAAAAAAA"])
30
+ """
31
+ Primary key
32
+ """
33
+ caseReference: str = Field(..., examples=["CROWN/2025/12345"])
34
+ """
35
+ Business Key for the related case
36
+ """
37
+ caseId: str = Field(..., examples=["AAAAAAAA-1234-1234-1234-AAAAAAAAAAAA"])
38
+ """
39
+ The unique ID for the case this Application Update belongs to.
40
+ """
41
+ caseType: str = Field(..., examples=["Crown Development Application"])
42
+ """
43
+ The type of case this Application Update is for.
44
+ """
45
+ applicationUpdateStatus: ApplicationUpdateStatus
46
+ """
47
+ Application Update Status. Name displayed to users, e.g. Draft
48
+ """
49
+ details: str
50
+ """
51
+ Application Update text description.
52
+ """
53
+ firstPublished: AwareDatetime | None = None
54
+ unpublishedDate: AwareDatetime | None = None
55
+ lastEdited: AwareDatetime | None = None