etlup 4.3.0__tar.gz → 4.3.2__tar.gz
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.
- {etlup-4.3.0 → etlup-4.3.2}/PKG-INFO +1 -1
- {etlup-4.3.0 → etlup-4.3.2}/pyproject.toml +1 -1
- etlup-4.3.2/src/etlup/hybrid/HybridVisualInspection.py +96 -0
- etlup-4.3.2/src/etlup/hybrid/ProbeCardI2CConnection.py +73 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/SensorIV.py +29 -1
- {etlup-4.3.0 → etlup-4.3.2}/README.md +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/__about__.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/__init__.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/base_model.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/custom_types.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/example_formatter.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/fake/__init__.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/fake/fake_test_component.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/fake/fake_test_module.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/gantry/PickAndPlace.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/gantry/SubassemblyAlignment.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/gantry/__init__.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/hybrid/ETROCOpticalInspection.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/hybrid/HybridBaseline.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/hybrid/HybridIV.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/hybrid/HybridNoisewidth.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/hybrid/XRayInspection.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/hybrid/__init__.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/image_tests/ImageTest.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/image_tests/__init__.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/module/ModuleIV.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/module/ModulePcbOpticalInspection.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/module/__init__.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/plot_utils.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/ChargeCollection.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/CurrentStability.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/CurrentUniformity.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/GainCurve.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/GainLayerUniformity.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/InterpadResistance.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/InterpadWidth.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/MPVStability.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/OpticalInspection.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/SensorIrradiation.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/TestArrayCV.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/TestArrayIV.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/TimeResolution.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sensor/__init__.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/sequences.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/tamalero/Baseline.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/tamalero/Mux64Values.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/tamalero/Noisewidth.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/tamalero/ReadoutBoardCommunication.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/tamalero/__init__.py +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/templates/sensors_plot.html +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/templates/test_by_image.html +0 -0
- {etlup-4.3.0 → etlup-4.3.2}/src/etlup/upload.py +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from pydantic import ConfigDict, Field
|
|
2
|
+
from typing_extensions import Annotated, Literal, Union, Optional
|
|
3
|
+
|
|
4
|
+
from .. import base_model as bm, jinja_env
|
|
5
|
+
from ..custom_types import Image
|
|
6
|
+
from ..plot_utils import image_src
|
|
7
|
+
|
|
8
|
+
# How much residue is left on the pads, from none at all to a lot of it.
|
|
9
|
+
PadResidue = Literal['Clean', 'Light', 'Moderate', 'Heavy']
|
|
10
|
+
|
|
11
|
+
# A 1x1 PNG, just enough for the example below to be a real image.
|
|
12
|
+
_EXAMPLE_IMAGE = (
|
|
13
|
+
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGO4AAAA0gDR29kOtwAAAABJRU5ErkJggg=="
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
class HybridVisualInspectionV0(bm.ConstructionBase):
|
|
17
|
+
model_config = ConfigDict(json_schema_extra={
|
|
18
|
+
'examples': [
|
|
19
|
+
{
|
|
20
|
+
"component": "ET2.01-PT-NH21",
|
|
21
|
+
"name": "hybrid_visual_inspection",
|
|
22
|
+
"location": "KNU",
|
|
23
|
+
"user_created": "ypark",
|
|
24
|
+
"version": "v0",
|
|
25
|
+
"measurement_date": "2026-07-29T12:01:00+02:00",
|
|
26
|
+
"pad_residue": "Light",
|
|
27
|
+
"bump_damage": False,
|
|
28
|
+
"mechanical_damage": False,
|
|
29
|
+
"shifted_hybrids": False,
|
|
30
|
+
"image": _EXAMPLE_IMAGE,
|
|
31
|
+
"comment": "A little residue on the top left pads, otherwise fine.",
|
|
32
|
+
"passed": True,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"component": "ET2.01-PT-NH22",
|
|
36
|
+
"name": "hybrid_visual_inspection",
|
|
37
|
+
"location": "KNU",
|
|
38
|
+
"user_created": "ypark",
|
|
39
|
+
"version": "v0",
|
|
40
|
+
"measurement_date": "2026-07-29T12:05:00+02:00",
|
|
41
|
+
"mechanical_damage": True,
|
|
42
|
+
"passed": False,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
'table': 'test',
|
|
46
|
+
'category': 'Subassembly',
|
|
47
|
+
'component_types': [],
|
|
48
|
+
'module_types': [],
|
|
49
|
+
'description': (
|
|
50
|
+
'Visual inspection of a hybrid. Records how much residue is on the pads '
|
|
51
|
+
'(Clean, Light, Moderate or Heavy), whether there is bump damage, mechanical damage '
|
|
52
|
+
'or shifted hybrids, an overall passed verdict, and optionally a photograph, base64 '
|
|
53
|
+
'encoded, and a comment. Every field is optional, so only what was looked at needs to be sent.'
|
|
54
|
+
)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
name: Literal['hybrid_visual_inspection'] = 'hybrid_visual_inspection'
|
|
58
|
+
version: Literal["v0"] = "v0"
|
|
59
|
+
component: str
|
|
60
|
+
|
|
61
|
+
# None means it was not looked at, not that it was fine.
|
|
62
|
+
pad_residue: Optional[PadResidue] = None
|
|
63
|
+
bump_damage: Optional[bool] = None
|
|
64
|
+
mechanical_damage: Optional[bool] = None
|
|
65
|
+
shifted_hybrids: Optional[bool] = None
|
|
66
|
+
image: Optional[Image] = None
|
|
67
|
+
comment: Optional[str] = None
|
|
68
|
+
passed: Optional[bool] = None # None until somebody decides
|
|
69
|
+
|
|
70
|
+
def plot(self):
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
def html_display(self) -> str:
|
|
74
|
+
display_data = {
|
|
75
|
+
"passed": self.passed,
|
|
76
|
+
"pad_residue": self.pad_residue,
|
|
77
|
+
"bump_damage": self.bump_damage,
|
|
78
|
+
"mechanical_damage": self.mechanical_damage,
|
|
79
|
+
"shifted_hybrids": self.shifted_hybrids,
|
|
80
|
+
"comment": self.comment,
|
|
81
|
+
}
|
|
82
|
+
if self.image is None:
|
|
83
|
+
img_html = "<p>No image was given with this inspection.</p>"
|
|
84
|
+
else:
|
|
85
|
+
img_html = (
|
|
86
|
+
f'<img src="{image_src(self.image)}" alt="{self.component} visual inspection" '
|
|
87
|
+
'style="width: clamp(300px, 75vw, 1000px); height: auto;">'
|
|
88
|
+
)
|
|
89
|
+
template = jinja_env.get_template('test_by_image.html')
|
|
90
|
+
return template.render(
|
|
91
|
+
display_data=display_data,
|
|
92
|
+
img_html=img_html
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
HybridVisualInspectionType = Annotated[Union[HybridVisualInspectionV0], Field(discriminator="version")]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from pydantic import ConfigDict, Field
|
|
2
|
+
from typing_extensions import Annotated, Literal, Union, Optional
|
|
3
|
+
|
|
4
|
+
from .. import base_model as bm, jinja_env
|
|
5
|
+
|
|
6
|
+
class ProbeCardI2CConnectionV0(bm.ConstructionBase):
|
|
7
|
+
model_config = ConfigDict(json_schema_extra={
|
|
8
|
+
'examples': [
|
|
9
|
+
{
|
|
10
|
+
"component": "ET2.01-PT-NH21",
|
|
11
|
+
"name": "probe_card_i2c_connection",
|
|
12
|
+
"location": "KNU",
|
|
13
|
+
"user_created": "ypark",
|
|
14
|
+
"version": "v0",
|
|
15
|
+
"measurement_date": "2026-07-29T12:01:00+02:00",
|
|
16
|
+
"i2c_connection": True,
|
|
17
|
+
"current_digital": 0.12,
|
|
18
|
+
"current_analog": 0.35,
|
|
19
|
+
"comment": None,
|
|
20
|
+
"passed": True,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"component": "ET2.01-PT-NH22",
|
|
24
|
+
"name": "probe_card_i2c_connection",
|
|
25
|
+
"location": "KNU",
|
|
26
|
+
"user_created": "ypark",
|
|
27
|
+
"version": "v0",
|
|
28
|
+
"measurement_date": "2026-07-29T12:05:00+02:00",
|
|
29
|
+
"i2c_connection": False,
|
|
30
|
+
"comment": "No I2C response from the ETROC.",
|
|
31
|
+
"passed": False,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
'table': 'test',
|
|
35
|
+
'category': 'Subassembly',
|
|
36
|
+
'component_types': [],
|
|
37
|
+
'module_types': [],
|
|
38
|
+
'description': (
|
|
39
|
+
'Checks that a hybrid talks over I2C on the probe card. Records whether the I2C '
|
|
40
|
+
'connection was made, an overall passed verdict, and optionally the digital and analog '
|
|
41
|
+
'currents drawn and a comment.'
|
|
42
|
+
)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
name: Literal['probe_card_i2c_connection'] = 'probe_card_i2c_connection'
|
|
46
|
+
version: Literal["v0"] = "v0"
|
|
47
|
+
component: str
|
|
48
|
+
|
|
49
|
+
i2c_connection: bool
|
|
50
|
+
current_digital: Optional[float] = None
|
|
51
|
+
current_analog: Optional[float] = None
|
|
52
|
+
comment: Optional[str] = None
|
|
53
|
+
passed: Optional[bool] = None # None until somebody decides
|
|
54
|
+
|
|
55
|
+
def plot(self):
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
def html_display(self) -> str:
|
|
59
|
+
display_data = {
|
|
60
|
+
"passed": self.passed,
|
|
61
|
+
"i2c_connection": self.i2c_connection,
|
|
62
|
+
"current_digital": self.current_digital,
|
|
63
|
+
"current_analog": self.current_analog,
|
|
64
|
+
"comment": self.comment,
|
|
65
|
+
}
|
|
66
|
+
template = jinja_env.get_template('test_by_image.html')
|
|
67
|
+
return template.render(
|
|
68
|
+
display_data=display_data,
|
|
69
|
+
img_html=""
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
ProbeCardI2CConnectionType = Annotated[Union[ProbeCardI2CConnectionV0], Field(discriminator="version")]
|
|
@@ -81,4 +81,32 @@ class SensorIVV0(base_model.ConstructionBase):
|
|
|
81
81
|
display_data = display_data
|
|
82
82
|
)
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
class SensorIVV1(SensorIVV0):
|
|
85
|
+
model_config = ConfigDict(json_schema_extra={
|
|
86
|
+
'examples': [
|
|
87
|
+
{
|
|
88
|
+
"component": "FBK_LF1_ROL_054",
|
|
89
|
+
"name": "Sensor IV",
|
|
90
|
+
"measurement_date": "2023-01-01T12:00:00+01:00",
|
|
91
|
+
"location": "UT",
|
|
92
|
+
"user_created": "fsiviero",
|
|
93
|
+
"version": "v1",
|
|
94
|
+
"leakage_current_uA": 158.176,
|
|
95
|
+
"breakdown_voltage_V": 282.0,
|
|
96
|
+
"category": "BAD",
|
|
97
|
+
"gain_category": "BD3",
|
|
98
|
+
"current": [1.798e-9, 2.132e-9,2.389e-9,2.667e-9,2.991e-9,3.373e-9,3.882e-9,4.470e-9,5.163e-9,5.98e-9,6.888e-9,7.861e-9,8.972e-9,9.177e-9,1.135e-8,1.334e-8,1.591e-8,1.956e-8,2.418e-8,2.950e-8,4.237e-8,5.572e-6,0.0000257,0.0000342,0.0000405,0.0000441,0.0000454,0.0000519,0.0000652,0.0000757,0.00008891,0.0001137,0.000133,0.000151,0.000165,0.0001832,0.000201,0.000213,0.000224,0.000234,0.000245,0.000256,0.000271,0.000286,0.000301,0.000313,0.000325,0.000337,0.000349,0.000371],
|
|
99
|
+
"voltage": [0.0,2.0,4.0,6.0,8.0,10.0,12.0,14.0,16.0,18.0,20.0,22.0,23.0,25.0,26.0,28.0,30.0,32.0,34.0,36.0,38.0,40.0,41.0,43.0,45.0,47.0,49.0,50.0,55.0,60.0,65.0,70.0,75.0,80.0,85.0,90.0,95.0,100.0,105.0,110.0,115.0,120.0,125.0,130.0,135.0,140.0,145.0,150.0,155.0,160.0],
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
'table': 'test',
|
|
103
|
+
'category': 'LGAD',
|
|
104
|
+
'component_types': [],
|
|
105
|
+
'module_types': [],
|
|
106
|
+
'description': 'IV curves and other QC info of the sensors recieved from a vendor and tested by ETL sensor experts'
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
version: Literal["v1"] = "v1"
|
|
110
|
+
gain_category: Union[None, Literal["BD1", "BD2", "BD3", "BD4", "BD5", "BD6", "BD7", "BD8", "BD9", "BD10"]] = Field(None, validation_alias=AliasChoices('gain_category','Gain Category'))
|
|
111
|
+
|
|
112
|
+
SensorIVType = Annotated[Union[SensorIVV0, SensorIVV1], Field(discriminator="version")]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|