1717from .spec .utilities import get_spec
1818from .spec .td import ThingDescription
1919from .decorators import tag
20- from .sockets import Sockets , SocketSubscriber , socket_handler_loop
20+ from .sockets import Sockets
2121
2222from .default_views .extensions import ExtensionList
2323from .default_views .tasks import TaskList , TaskView
2424from .default_views .docs import docs_blueprint , SwaggerUIView
25+ from .default_views .root import RootView
26+ from .default_views .sockets import socket_handler
2527
2628from ..core .utilities import get_docstring
2729
30+ import weakref
2831import logging
2932
3033
@@ -72,7 +75,7 @@ def __init__(
7275
7376 # Logging handler
7477 # TODO: Add cleanup code
75- self .log_handler = LabThingLogger (self )
78+ self .log_handler = LabThingLogger ()
7679 logging .getLogger ().addHandler (self .log_handler )
7780
7881 self .spec = APISpec (
@@ -87,6 +90,12 @@ def __init__(
8790 if app is not None :
8891 self .init_app (app )
8992
93+ def __enter__ (self ):
94+ return self
95+
96+ def __exit__ (self , * args , ** kwargs ):
97+ self .app = None
98+
9099 @property
91100 def description (self ,):
92101 return self ._description
@@ -128,11 +137,9 @@ def version(self, version: str):
128137 def init_app (self , app ):
129138 self .app = app
130139
131- app .teardown_appcontext (self .teardown )
132-
133140 # Register Flask extension
134141 app .extensions = getattr (app , "extensions" , {})
135- app .extensions [EXTENSION_NAME ] = self
142+ app .extensions [EXTENSION_NAME ] = weakref . ref ( self )
136143
137144 # Flask error formatter
138145 if self .format_flask_exceptions :
@@ -154,12 +161,9 @@ def init_app(self, app):
154161 self .sockets = Sockets (app )
155162 self ._create_base_sockets ()
156163
157- def teardown (self , exception ):
158- pass
159-
160164 def _create_base_routes (self ):
161165 # Add root representation
162- self .app . add_url_rule ( self ._complete_url ("/" , "" ), "root" , self . root )
166+ self .add_view ( RootView , self ._complete_url ("/" , "" ), endpoint = "root" )
163167 # Add thing descriptions
164168 self .app .register_blueprint (
165169 docs_blueprint , url_prefix = f"{ self .url_prefix } /docs"
@@ -175,19 +179,7 @@ def _create_base_routes(self):
175179 self .add_view (TaskView , "/tasks/<task_id>" , endpoint = TASK_ENDPOINT )
176180
177181 def _create_base_sockets (self ):
178- self .sockets .add_view (self ._complete_url ("" , "" ), self ._socket_handler )
179-
180- def _socket_handler (self , ws ):
181- # Create a socket subscriber
182- wssub = SocketSubscriber (ws )
183- self .subscribers .add (wssub )
184- logging .info (f"Added subscriber { wssub } " )
185- # Start the socket connection handler loop
186- socket_handler_loop (ws )
187- # Remove the subscriber once the loop returns
188- self .subscribers .remove (wssub )
189- logging .info (f"Removed subscriber { wssub } " )
190- logging .debug (list (self .subscribers ))
182+ self .sockets .add_view (self ._complete_url ("" , "" ), socket_handler )
191183
192184 # Device stuff
193185
@@ -309,6 +301,8 @@ def _register_view(self, app, view, *urls, endpoint=None, **kwargs):
309301
310302 # There might be a better way to do this than _rules_by_endpoint,
311303 # but I can't find one so this will do for now. Skipping PYL-W0212
304+ # FIXME: There is a MASSIVE memory leak or something going on in APISpec!
305+ # This is grinding tests to a halt, and is really annoying... Should be fixed.
312306 flask_rules = app .url_map ._rules_by_endpoint .get (endpoint ) # skipcq: PYL-W0212
313307 for flask_rule in flask_rules :
314308 self .spec .path (** rule_to_apispec_path (flask_rule , view , self .spec ))
@@ -345,8 +339,3 @@ def add_root_link(self, view, rel, kwargs=None, params=None):
345339 if params is None :
346340 params = {}
347341 self .thing_description .add_link (view , rel , kwargs = kwargs , params = params )
348-
349- # Description
350- def root (self ):
351- """Root representation"""
352- return self .thing_description .to_dict ()
0 commit comments