Skip to content

Commit

Permalink
Refactor requests with specific handlers and remove kit
Browse files Browse the repository at this point in the history
  • Loading branch information
oscgonfer committed Oct 23, 2024
1 parent 4f99f3c commit d8ce996
Show file tree
Hide file tree
Showing 14 changed files with 228 additions and 63 deletions.
16 changes: 10 additions & 6 deletions smartcitizen_connector/__init__.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
from .models import (Sensor, Measurement, Kit, Owner, Location,
HardwareInfo, Postprocessing, Data, Device)
from .models import (Sensor, Measurement, Owner, User, Location,
HardwareInfo, Postprocessing, Data, Device, Experiment)
from .handler import HttpHandler
from .device import SCDevice#, get_devices
from .sensor import SCSensor, get_sensors
from .measurement import SCMeasurement, get_measurements
from .sensor import SensorHandler, get_sensors
from .measurement import MeasurementHandler, get_measurements
from .experiment import ExperimentHandler, get_experiments
from .search import search_by_query, global_search
from .user import UserHandler, get_users

__all__ = [
"Device",
"Kit",
"Sensor",
"Measurement",
"User",
"Owner",
"Location",
"Data",
"Postprocessing",
"HardwareInfo"
"HardwareInfo",
"Experiment"
]

__version__ = '1.1.3'
2 changes: 2 additions & 0 deletions smartcitizen_connector/_config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class Config():
DEVICES_URL = API_URL + 'devices/'
SENSORS_URL = API_URL + 'sensors/'
MEASUREMENTS_URL = API_URL + 'measurements/'
EXPERIMENTS_URL = API_URL + 'experiments/'
USERS_URL = API_URL + 'users/'
FRONTEND_URL = 'https://smartcitizen.me/kits/'
BASE_POSTPROCESSING_URL='https://raw.githubusercontent.com/fablabbcn/smartcitizen-data/master/'
API_SEARCH_URL = API_URL + "search?q="
Expand Down
1 change: 1 addition & 0 deletions smartcitizen_connector/experiment/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .experiment import ExperimentHandler, get_experiments
42 changes: 42 additions & 0 deletions smartcitizen_connector/experiment/experiment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from smartcitizen_connector.models import Experiment
from smartcitizen_connector._config import config
from smartcitizen_connector.tools import *
from pydantic import TypeAdapter
from typing import Optional, List
from smartcitizen_connector.handler import HttpHandler

# TODO - Can this inherit from experiment?
class ExperimentHandler(HttpHandler):

def __init__(self, id: int = None, **kwargs):
self.id = id
super().__init__(config.EXPERIMENTS_URL)

if self.id is not None:
r = self.get()
self.model = TypeAdapter(Experiment).validate_python(r.json())
else:
self.model = Experiment(**kwargs)

def __getattr__(self, attr):
return self.model.__getattribute__(attr)

def get_experiments():
isn = True
result = list()
url = config.EXPERIMENTS_URL

while isn:
r = get(url)
r.raise_for_status()
# If status code OK, retrieve data
h = process_headers(r.headers)
result += TypeAdapter(List[Experiment]).validate_python(r.json())

if 'next' in h:
if h['next'] == url: isn = False
elif h['next'] != url: url = h['next']
else:
isn = False

return result
1 change: 1 addition & 0 deletions smartcitizen_connector/handler/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .httphandler import HttpHandler
58 changes: 58 additions & 0 deletions smartcitizen_connector/handler/httphandler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from requests import get, patch, post, delete
from os import environ
from smartcitizen_connector.tools import logger
from typing import Optional
import json

class HttpHandler:
url: Optional[str] = None

def __init__(self, path: str):
self.path = path
self.__set_headers__()
if self.id is not None:
self.url = f'{self.path}{self.id}'

def __set_headers__(self):

self.headers = {
'Content-type': 'application/json'
}

if 'SC_BEARER' not in environ:
logger.warning('No Auth Bearer set. Will not be able to POST, PATCH, DELETE. Include it environment variable with SC_BEARER')
return False

logger.info('Using Auth Bearer')
self.headers['Authorization'] = 'Bearer ' + environ['SC_BEARER']

return True

def get(self):
r = get(self.url)
r.raise_for_status()
return r

def patch(self, property: str):
r = patch(self.url,
data=self.model.json(include=property,
exclude_none=True),
headers = self.headers
)
r.raise_for_status()
return r

def post(self):
r = post(self.path,
data=self.model.json(exclude_none=True),
headers = self.headers)

r.raise_for_status()
return r

def delete(self):
r = delete(self.url,
headers = self.headers)

r.raise_for_status()
return r
2 changes: 1 addition & 1 deletion smartcitizen_connector/measurement/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .measurement import SCMeasurement, get_measurements
from .measurement import MeasurementHandler, get_measurements
32 changes: 15 additions & 17 deletions smartcitizen_connector/measurement/measurement.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
from smartcitizen_connector.models import (Sensor, Measurement)
from smartcitizen_connector.models import Measurement
from smartcitizen_connector._config import config
from smartcitizen_connector.tools import *
from pydantic import TypeAdapter
from typing import List
from requests import get
from typing import Optional, List
from smartcitizen_connector.handler import HttpHandler

class SCMeasurement:
id: int
url: str
page: str
json: Measurement
# TODO - Can this inherit from Measurement?
class MeasurementHandler(HttpHandler):

def __init__(self, id):
def __init__(self, id: int = None, **kwargs):
self.id = id
self.url = f'{config.SENSORS_URL}{self.id}'
self.method = 'async'
r = self.__safe_get__(self.url)
self.json = TypeAdapter(Sensor).validate_python(r.json())
super().__init__(config.MEASUREMENTS_URL)

def __safe_get__(self, url):
r = get(url)
r.raise_for_status()
if self.id is not None:
r = self.get()
self.model = TypeAdapter(Measurement).validate_python(r.json())
else:
self.model = Measurement(**kwargs)

return r
def __getattr__(self, attr):
return self.model.__getattribute__(attr)

def get_measurements():
isn = True
Expand All @@ -40,4 +37,5 @@ def get_measurements():
elif h['next'] != url: url = h['next']
else:
isn = False

return result
5 changes: 3 additions & 2 deletions smartcitizen_connector/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .models import (Sensor, Measurement, Kit, Owner, Location, Metric,
HardwareInfo, HardwarePostprocessing, Postprocessing, Data, Device, HardwareStatus, Policy)
from .models import (Sensor, Measurement, Owner, User, Location, Metric,
HardwareInfo, HardwarePostprocessing, Postprocessing,
Data, Device, HardwareStatus, Policy, Experiment)
58 changes: 39 additions & 19 deletions smartcitizen_connector/models/models.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from datetime import datetime
from typing import Optional, List, Dict
from typing import Optional, List, Dict, Any
from pydantic import BaseModel

class Measurement(BaseModel):
id: int
uuid: str
name: str
description: str
definition: Optional[str] = None

class Metric(BaseModel):
id: Optional[int] = None
Expand All @@ -20,26 +22,19 @@ class Metric(BaseModel):

class Sensor(BaseModel):
id: int
uuid: str
name: str
description: str
unit: Optional[str] = None
measurement_id: Optional[int] = None
measurement: Optional[Measurement] = None
datasheet: Optional[str] = None
unit_definition: Optional[str] = None
value: Optional[float] = None
prev_value: Optional[float] = None
last_reading_at: Optional[datetime] = None
tags: Optional[List[str]] = []
default_key: Optional[str] = []

class Kit(BaseModel):
id: int
slug: str
name: str
description: str
created_at: datetime
updated_at: datetime
sensors: Optional[List[Sensor]] = None

class Owner(BaseModel):
id: int
username: str
Expand All @@ -48,8 +43,8 @@ class Owner(BaseModel):

class Location(BaseModel):
city: Optional[str] = None
country_code: str
country: str
country_code: Optional[str] = None
country: Optional[str] = None
exposure: Optional[str] = None
elevation: Optional[float] = None
geohash: Optional[str] = None
Expand Down Expand Up @@ -103,9 +98,9 @@ class Notifications(BaseModel):
stopped_publishing: bool

class Policy(BaseModel):
is_private: bool
precise_location: bool
enable_forwarding: bool
is_private: Any
precise_location: Any
enable_forwarding: Any

class Device(BaseModel):
id: int
Expand All @@ -117,12 +112,37 @@ class Device(BaseModel):
hardware: HardwareInfo
system_tags: List[str]
user_tags: List[str]
# data_policy: Policy
data_policy: Optional[Policy] = None
notify: Notifications
last_reading_at: Optional[datetime] = None
created_at: Optional[datetime] = None
updated_at: datetime
owner: Owner
data: Data
owner: Optional[Owner] = None
data: Optional[Data] = None
location: Optional[Location]= None
device_token: str = 'FILTERED'

class Experiment(BaseModel):
id: Optional[int] = None
name: str
description: Optional[str] = ''
owner_id: Optional[int] = None
active: Optional[bool] = None
is_test: bool
starts_at: Optional[datetime] = None
ends_at: Optional[datetime] = None
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
device_ids: Optional[List[int]] = None

class User(BaseModel):
id: int
uuid: str
username: str
role: Optional[str] = ""
devices: Optional[List[Device]] = None
profile_picture: str
location: Location
updated_at: datetime
forwarding_token: str
forwarding_username: str
2 changes: 1 addition & 1 deletion smartcitizen_connector/sensor/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .sensor import SCSensor, get_sensors
from .sensor import SensorHandler, get_sensors
32 changes: 15 additions & 17 deletions smartcitizen_connector/sensor/sensor.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
from smartcitizen_connector.models import (Sensor, Measurement)
from smartcitizen_connector.models import Sensor
from smartcitizen_connector._config import config
from smartcitizen_connector.tools import *
from pydantic import TypeAdapter
from typing import List
from requests import get
from typing import Optional, List
from smartcitizen_connector.handler import HttpHandler

class SCSensor:
id: int
url: str
page: str
json: Sensor
class SensorHandler(HttpHandler):

def __init__(self, id):
def __init__(self, id: int = None, **kwargs):
self.id = id
self.url = f'{config.SENSORS_URL}{self.id}'
self.method = 'async'
r = self.__safe_get__(self.url)
self.json = TypeAdapter(Sensor).validate_python(r.json())
super().__init__(config.SENSORS_URL)

def __safe_get__(self, url):
r = get(url)
r.raise_for_status()
if self.id is not None:
r = self.get()
self.model = TypeAdapter(Sensor).validate_python(r.json())
else:
self.model = Sensor(**kwargs)

return r
def __getattr__(self, attr):
return self.model.__getattribute__(attr)

def get_sensors():
isn = True
result = list()
url = config.SENSORS_URL

while isn:
r = get(url)
r.raise_for_status()
Expand All @@ -40,4 +37,5 @@ def get_sensors():
elif h['next'] != url: url = h['next']
else:
isn = False

return result
1 change: 1 addition & 0 deletions smartcitizen_connector/user/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .user import UserHandler, get_users
Loading

0 comments on commit d8ce996

Please sign in to comment.