rmm commited on
Commit
96df9de
·
1 Parent(s): 380d10c

docs: docstrings, typehints for input_handling

Browse files
call_models/input_handling.py CHANGED
@@ -6,6 +6,9 @@ import hashlib
6
  import logging
7
 
8
  import streamlit as st
 
 
 
9
  import cv2
10
  import numpy as np
11
 
@@ -25,6 +28,47 @@ allowed_image_types = ['jpg', 'jpeg', 'png', 'webp']
25
 
26
  # autogenerated class to hold the input data
27
  class InputObservation:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  def __init__(self, image=None, latitude=None, longitude=None, author_email=None, date=None, time=None, date_option=None, time_option=None, uploaded_filename=None):
29
  self.image = image
30
  self.latitude = latitude
@@ -84,19 +128,49 @@ class InputObservation:
84
  def from_dict(data):
85
  return InputObservation(data["image"], data["latitude"], data["longitude"], data["author_email"], data["date"], data["time"], data["date_option"], data["time_option"], data["uploaded_filename"])
86
 
87
- # define function to validate number, allowing signed float
88
  def is_valid_number(number:str) -> bool:
 
 
 
 
 
 
 
 
 
89
  pattern = r'^[-+]?[0-9]*\.?[0-9]+$'
90
  return re.match(pattern, number) is not None
91
 
92
 
93
  # Function to validate email address
94
- def is_valid_email(email):
 
 
 
 
 
 
 
 
 
95
  pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
96
  return re.match(pattern, email) is not None
97
 
98
  # Function to extract date and time from image metadata
99
- def get_image_datetime(image_file):
 
 
 
 
 
 
 
 
 
 
 
 
100
  try:
101
  image = Image.open(image_file)
102
  exif_data = image._getexif()
@@ -104,8 +178,9 @@ def get_image_datetime(image_file):
104
  for tag, value in exif_data.items():
105
  if ExifTags.TAGS.get(tag) == 'DateTimeOriginal':
106
  return value
107
- except Exception as e:
108
- st.warning("Could not extract date from image metadata.")
 
109
  return None
110
 
111
 
@@ -120,7 +195,23 @@ spoof_metadata = {
120
  }
121
 
122
  #def display_whale(whale_classes:List[str], i:int, viewcontainer=None):
123
- def setup_input(viewcontainer: st.delta_generator.DeltaGenerator=None, _allowed_image_types: list=None, ):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
  if viewcontainer is None:
126
  viewcontainer = st.sidebar
 
6
  import logging
7
 
8
  import streamlit as st
9
+ from streamlit.runtime.uploaded_file_manager import UploadedFile # for type hinting
10
+ from streamlit.delta_generator import DeltaGenerator
11
+
12
  import cv2
13
  import numpy as np
14
 
 
28
 
29
  # autogenerated class to hold the input data
30
  class InputObservation:
31
+ """
32
+ A class to hold an input observation and associated metadata
33
+
34
+ Attributes:
35
+ image (Any):
36
+ The image associated with the observation.
37
+ latitude (float):
38
+ The latitude where the observation was made.
39
+ longitude (float):
40
+ The longitude where the observation was made.
41
+ author_email (str):
42
+ The email of the author of the observation.
43
+ date (str):
44
+ The date when the observation was made.
45
+ time (str):
46
+ The time when the observation was made.
47
+ date_option (str):
48
+ Additional date option for the observation.
49
+ time_option (str):
50
+ Additional time option for the observation.
51
+ uploaded_filename (Any):
52
+ The uploaded filename associated with the observation.
53
+
54
+ Methods:
55
+ __str__():
56
+ Returns a string representation of the observation.
57
+ __repr__():
58
+ Returns a string representation of the observation.
59
+ __eq__(other):
60
+ Checks if two observations are equal.
61
+ __ne__(other):
62
+ Checks if two observations are not equal.
63
+ __hash__():
64
+ Returns the hash of the observation.
65
+ to_dict():
66
+ Converts the observation to a dictionary.
67
+ from_dict(data):
68
+ Creates an observation from a dictionary.
69
+ from_input(input):
70
+ Creates an observation from another input observation.
71
+ """
72
  def __init__(self, image=None, latitude=None, longitude=None, author_email=None, date=None, time=None, date_option=None, time_option=None, uploaded_filename=None):
73
  self.image = image
74
  self.latitude = latitude
 
128
  def from_dict(data):
129
  return InputObservation(data["image"], data["latitude"], data["longitude"], data["author_email"], data["date"], data["time"], data["date_option"], data["time_option"], data["uploaded_filename"])
130
 
131
+
132
  def is_valid_number(number:str) -> bool:
133
+ """
134
+ Check if the given string is a valid number (int or float, sign ok)
135
+
136
+ Args:
137
+ number (str): The string to be checked.
138
+
139
+ Returns:
140
+ bool: True if the string is a valid number, False otherwise.
141
+ """
142
  pattern = r'^[-+]?[0-9]*\.?[0-9]+$'
143
  return re.match(pattern, number) is not None
144
 
145
 
146
  # Function to validate email address
147
+ def is_valid_email(email:str) -> bool:
148
+ """
149
+ Validates if the provided email address is in a correct format.
150
+
151
+ Args:
152
+ email (str): The email address to validate.
153
+
154
+ Returns:
155
+ bool: True if the email address is valid, False otherwise.
156
+ """
157
  pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
158
  return re.match(pattern, email) is not None
159
 
160
  # Function to extract date and time from image metadata
161
+ def get_image_datetime(image_file: UploadedFile) -> str | None:
162
+ """
163
+ Extracts the original date and time from the EXIF metadata of an uploaded image file.
164
+
165
+ Args:
166
+ image_file (UploadedFile): The uploaded image file from which to extract the date and time.
167
+
168
+ Returns:
169
+ str: The original date and time as a string if available, otherwise None.
170
+
171
+ Raises:
172
+ Warning: If the date and time could not be extracted from the image metadata.
173
+ """
174
  try:
175
  image = Image.open(image_file)
176
  exif_data = image._getexif()
 
178
  for tag, value in exif_data.items():
179
  if ExifTags.TAGS.get(tag) == 'DateTimeOriginal':
180
  return value
181
+ except Exception as e: # FIXME: what types of exception?
182
+ st.warning(f"Could not extract date from image metadata. (file: {image_file.name})")
183
+ # TODO: add to logger
184
  return None
185
 
186
 
 
195
  }
196
 
197
  #def display_whale(whale_classes:List[str], i:int, viewcontainer=None):
198
+ def setup_input(
199
+ viewcontainer: DeltaGenerator=None,
200
+ _allowed_image_types: list=None, ) -> InputObservation:
201
+ """
202
+ Sets up the input interface for uploading an image and entering metadata.
203
+
204
+ It provides input fields for an image upload, lat/lon, author email, and date-time.
205
+ In the ideal case, the image metadata will be used to populate location and datetime.
206
+
207
+ Parameters:
208
+ viewcontainer (DeltaGenerator, optional): The Streamlit container to use for the input interface. Defaults to st.sidebar.
209
+ _allowed_image_types (list, optional): List of allowed image file types for upload. Defaults to allowed_image_types.
210
+
211
+ Returns:
212
+ InputObservation: An object containing the uploaded image and entered metadata.
213
+
214
+ """
215
 
216
  if viewcontainer is None:
217
  viewcontainer = st.sidebar
docs/input_handling.md CHANGED
@@ -1,2 +1,8 @@
 
 
 
 
 
 
1
 
2
  ::: call_models.input_handling
 
1
+ This module focuses on image and metadata entry:
2
+
3
+ - UI elements to upload an image and populate the metadata (or edit the
4
+ auto-discovered metadata)
5
+ - a container class for an observation
6
+
7
 
8
  ::: call_models.input_handling