prefab 1.3.0__py3-none-any.whl → 1.4.0__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.
prefab/__init__.py CHANGED
@@ -5,7 +5,7 @@ Usage:
5
5
  import prefab as pf
6
6
  """
7
7
 
8
- __version__ = "1.3.0"
8
+ __version__ = "1.4.0"
9
9
 
10
10
  from . import compare, geometry, predict, read, shapes
11
11
  from .device import BufferSpec, Device
prefab/__main__.py CHANGED
@@ -17,9 +17,9 @@ def store_jwt(jwt, refresh_token):
17
17
  toml.dump({"access_token": jwt, "refresh_token": refresh_token}, toml_file)
18
18
  print(
19
19
  f"Token successfully stored in {prefab_file_path}.\n\n"
20
- "🎉 Welcome to PreFab!.\n"
20
+ "🎉 Welcome to PreFab.\n"
21
21
  "See our examples at https://docs.prefabphotonics.com/examples to start.\n"
22
- "Reach out to us at hi@prefabphotonics.com if you have any questions."
22
+ "Reach out to us at hi@prefabphotonics.com for support."
23
23
  )
24
24
 
25
25
 
@@ -35,6 +35,10 @@ class GracefulHTTPServer(HTTPServer):
35
35
  class CallbackHandler(BaseHTTPRequestHandler):
36
36
  """A request handler for the HTTP server that handles the JWT-auth callback."""
37
37
 
38
+ def log_message(self, format, *args):
39
+ """Suppress HTTP request logging."""
40
+ pass
41
+
38
42
  def do_GET(self):
39
43
  if self.path.startswith("/callback"):
40
44
  query_params = self.path.split("?")[1]
@@ -47,25 +51,12 @@ class CallbackHandler(BaseHTTPRequestHandler):
47
51
  if jwt_token and refresh_token:
48
52
  print("Token verified.")
49
53
  store_jwt(jwt_token, refresh_token)
50
- self.send_response_only(200, "OK")
51
- self.send_header("Content-type", "text/html")
54
+ self.send_response(302)
55
+ self.send_header(
56
+ "Location",
57
+ "https://www.prefabphotonics.com/auth/token-flow/success",
58
+ )
52
59
  self.end_headers()
53
- redirect_html = b"""
54
- <html>
55
- <head>
56
- <meta http-equiv="refresh" content="0;url=https://www.prefabphotonics.com/token-success">
57
- <style>
58
- body {
59
- background-color: #0A0A0A;
60
- color: #ffffff;
61
- }
62
- </style>
63
- </head>
64
- <body>
65
- </body>
66
- </html>
67
- """
68
- self.wfile.write(redirect_html)
69
60
  threading.Thread(target=self.server.shutdown).start()
70
61
  else:
71
62
  self.send_error(400, "Bad Request: Missing tokens in callback URL.")
@@ -78,15 +69,29 @@ def main():
78
69
  parser.add_argument(
79
70
  "--port", help="Port number for the HTTP server", type=int, default=8000
80
71
  )
72
+ parser.add_argument(
73
+ "--timeout", help="Timeout in seconds for authentication", type=int, default=300
74
+ )
81
75
  args = parser.parse_args()
82
76
 
83
77
  if args.command == "setup":
84
- webbrowser.open("https://www.prefabphotonics.com/token-flow")
78
+ webbrowser.open("https://www.prefabphotonics.com/auth/token-flow")
85
79
  httpd = GracefulHTTPServer(("localhost", args.port), CallbackHandler)
86
80
  print("Started token authentication flow on the web browser...")
87
- with suppress(KeyboardInterrupt):
88
- httpd.serve_forever()
89
- httpd.server_close()
81
+
82
+ def timeout_handler():
83
+ print("\nAuthentication timed out. Please run 'prefab setup' again.")
84
+ httpd.shutdown()
85
+
86
+ timer = threading.Timer(args.timeout, timeout_handler)
87
+ timer.start()
88
+
89
+ try:
90
+ with suppress(KeyboardInterrupt):
91
+ httpd.serve_forever()
92
+ finally:
93
+ timer.cancel()
94
+ httpd.server_close()
90
95
  else:
91
96
  print(f"Command {args.command} not recognized.")
92
97
 
prefab/compare.py CHANGED
@@ -1,6 +1,10 @@
1
- """Functions to measure the structural similarity between devices."""
1
+ """
2
+ Similarity metrics for comparing device structures.
2
3
 
3
- import warnings
4
+ This module provides various metrics for quantifying the similarity between two Device
5
+ objects, including general-purpose metrics (MSE) and binary-specific metrics (IoU,
6
+ Hamming distance, Dice coefficient).
7
+ """
4
8
 
5
9
  import numpy as np
6
10
 
@@ -9,8 +13,10 @@ from .device import Device
9
13
 
10
14
  def mean_squared_error(device_a: Device, device_b: Device) -> float:
11
15
  """
12
- Calculate the mean squared error (MSE) between two devices. A lower value indicates
13
- more similarity.
16
+ Calculate the mean squared error (MSE) between two devices.
17
+
18
+ MSE quantifies the average squared difference between corresponding pixels. Lower
19
+ values indicate greater similarity, with 0 representing identical devices.
14
20
 
15
21
  Parameters
16
22
  ----------
@@ -22,105 +28,87 @@ def mean_squared_error(device_a: Device, device_b: Device) -> float:
22
28
  Returns
23
29
  -------
24
30
  float
25
- The mean squared error between two devices.
31
+ The mean squared error. Range: [0, ∞), where 0 indicates identical devices.
26
32
  """
27
33
  return float(np.mean((device_a.device_array - device_b.device_array) ** 2))
28
34
 
29
35
 
30
36
  def intersection_over_union(device_a: Device, device_b: Device) -> float:
31
37
  """
32
- Calculates the Intersection over Union (IoU) between two binary devices. A value
33
- closer to 1 indicates more similarity (more overlap).
38
+ Calculate the Intersection over Union (IoU) between two binary devices.
39
+
40
+ Also known as the Jaccard index. IoU measures the overlap between two binary masks
41
+ as the ratio of their intersection to their union. Higher values indicate greater
42
+ similarity.
34
43
 
35
44
  Parameters
36
45
  ----------
37
46
  device_a : Device
38
- The first device (binarized).
47
+ The first device (should be binarized for meaningful results).
39
48
  device_b : Device
40
- The second device (binarized).
49
+ The second device (should be binarized for meaningful results).
41
50
 
42
51
  Returns
43
52
  -------
44
53
  float
45
- The Intersection over Union between two devices.
46
-
47
- Warnings
48
- --------
49
- UserWarning
50
- If one or both devices are not binarized.
54
+ The IoU score. Range: [0, 1], where 1 indicates perfect overlap.
51
55
  """
52
- if not device_a.is_binary or not device_b.is_binary:
53
- warnings.warn(
54
- "One or both devices are not binarized.", UserWarning, stacklevel=2
55
- )
56
-
57
- return np.sum(
58
- np.logical_and(device_a.device_array, device_b.device_array)
59
- ) / np.sum(np.logical_or(device_a.device_array, device_b.device_array))
56
+ intersection_sum = float(
57
+ np.sum(np.logical_and(device_a.device_array, device_b.device_array))
58
+ )
59
+ union_sum = float(
60
+ np.sum(np.logical_or(device_a.device_array, device_b.device_array))
61
+ )
62
+ return intersection_sum / union_sum
60
63
 
61
64
 
62
65
  def hamming_distance(device_a: Device, device_b: Device) -> int:
63
66
  """
64
- Calculates the Hamming distance between two binary devices. A lower value indicates
65
- more similarity. The Hamming distance is calculated as the number of positions at
66
- which the corresponding pixels are different.
67
+ Calculate the Hamming distance between two binary devices.
68
+
69
+ The Hamming distance is the count of positions where corresponding pixels differ.
70
+ Lower values indicate greater similarity, with 0 representing identical devices.
67
71
 
68
72
  Parameters
69
73
  ----------
70
74
  device_a : Device
71
- The first device (binarized).
75
+ The first device (should be binarized for meaningful results).
72
76
  device_b : Device
73
- The second device (binarized).
77
+ The second device (should be binarized for meaningful results).
74
78
 
75
79
  Returns
76
80
  -------
77
81
  int
78
- The Hamming distance between two devices.
79
-
80
- Warnings
81
- --------
82
- UserWarning
83
- If one or both devices are not binarized.
82
+ The number of differing pixels. Range: [0, total_pixels], where 0 indicates
83
+ identical devices.
84
84
  """
85
- if not device_a.is_binary or not device_b.is_binary:
86
- warnings.warn(
87
- "One or both devices are not binarized.", UserWarning, stacklevel=2
88
- )
89
-
90
- return int(np.sum(device_a.device_array != device_b.device_array))
85
+ diff_array = device_a.device_array != device_b.device_array
86
+ return int(np.sum(diff_array))
91
87
 
92
88
 
93
89
  def dice_coefficient(device_a: Device, device_b: Device) -> float:
94
90
  """
95
- Calculates the Dice coefficient between two binary devices. A value closer to 1
96
- indicates more similarity. The Dice coefficient is calculated as twice the number of
97
- pixels in common divided by the total number of pixels in the two devices.
91
+ Calculate the Dice coefficient between two binary devices.
92
+
93
+ Also known as the Sørensen-Dice coefficient or F1 score. The Dice coefficient
94
+ measures similarity as twice the intersection divided by the sum of the sizes of
95
+ both sets. Higher values indicate greater similarity.
98
96
 
99
97
  Parameters
100
98
  ----------
101
99
  device_a : Device
102
- The first device (binarized).
100
+ The first device (should be binarized for meaningful results).
103
101
  device_b : Device
104
- The second device (binarized).
102
+ The second device (should be binarized for meaningful results).
105
103
 
106
104
  Returns
107
105
  -------
108
106
  float
109
- The Dice coefficient between two devices.
110
-
111
- Warnings
112
- --------
113
- UserWarning
114
- If one or both devices are not binarized.
107
+ The Dice coefficient. Range: [0, 1], where 1 indicates perfect overlap.
115
108
  """
116
- if not device_a.is_binary or not device_b.is_binary:
117
- warnings.warn(
118
- "One or both devices are not binarized.", UserWarning, stacklevel=2
119
- )
120
-
121
- intersection = 2.0 * np.sum(
122
- np.logical_and(device_a.device_array, device_b.device_array)
109
+ intersection_sum = float(
110
+ np.sum(np.logical_and(device_a.device_array, device_b.device_array))
123
111
  )
124
- size_a = np.sum(device_a.device_array)
125
- size_b = np.sum(device_b.device_array)
126
- return intersection / (size_a + size_b)
112
+ size_a_sum = float(np.sum(device_a.device_array))
113
+ size_b_sum = float(np.sum(device_b.device_array))
114
+ return (2.0 * intersection_sum) / (size_a_sum + size_b_sum)