class DummyTransport(object): def __init__(self): self.lose_connection_called = Deferred() def loseConnection(self): self.lose_connection_called.callback(None)
def put(self, router_type="", router_token="", uaid="", chid=""): """HTTP PUT Update router type/data for a UAID. """ self.start_time = time.time() if not self._validate_auth(uaid): return self._write_response( 401, 109, message="Invalid Authentication") params = self._load_params() self.uaid = uaid router_data = params if router_type not in self.ap_settings.routers or not router_data: log.msg("Invalid parameters", **self._client_info()) return self._write_response( 400, 108, message="Invalid arguments") router = self.ap_settings.routers[router_type] valid, router_token = router.check_token(router_token) if not valid: newUrl = self._relocate(router_type, router_token, uaid, chid) return self._write_response( 301, 0, "Location: %s" % newUrl, headers={"Location": newUrl}) self.add_header("Content-Type", "application/json") d = Deferred() d.addCallback(router.register, router_data) d.addCallback(self._save_router_data, router_type) d.addCallback(self._success) d.addErrback(self._router_fail_err) d.addErrback(self._response_err) d.callback(uaid)
def cachedZipResource(self, request, name, url, segments): archivePath = self.config.CachedResources.child("{0}.zip".format(name)) if archivePath.exists(): d = Deferred() d.callback(None) else: d = http_download(archivePath, url) def readFromArchive(_): filePath = ZipArchive(archivePath.path) for segment in segments: filePath = filePath.child(segment) return filePath.getContent() def notFoundHandler(f): f.trap(KeyError) request.setResponseCode(http.NOT_FOUND) set_response_header( request, HeaderName.contentType, ContentType.plain ) return b"Not found." d.addCallback(readFromArchive) d.addErrback(notFoundHandler) return d
def create_keychain(self): """ The guid generation can take a while. While it's doing that we will open a port to allow a UI to connect and listen for generation to complete. """ print "Generating GUID, this may take a few minutes..." d = Deferred() api = GUIDGenerationListener(d) site = Site(api, timeout=None) connector = reactor.listenTCP(18470, site, interface="127.0.0.1") start = time.time() g = GUID() d.callback((round(time.time() - start, 2), connector)) self.guid = g.guid self.guid_privkey = g.privkey self.signing_key = nacl.signing.SigningKey(self.guid_privkey) self.guid_signed_pubkey = g.signed_pubkey self.db.set_key("guid", self.guid_privkey, self.guid_signed_pubkey) self.bitcoin_master_privkey = bitcointools.bip32_master_key(bitcointools.sha256(self.guid_privkey)) self.bitcoin_master_pubkey = bitcointools.bip32_privtopub(self.bitcoin_master_privkey) self.db.set_key("bitcoin", self.bitcoin_master_privkey, self.bitcoin_master_pubkey) self.encryption_key = PrivateKey(self.guid_privkey) self.encryption_pubkey = self.encryption_key.public_key.encode()
class _Producer(object): implements(IPullProducer) deferred = None def __init__(self, body, consumer): """:param body: an iterable of strings""" # check to see if we can determine the length try: len(body) # iterator? self.length = sum([len(fragment) for fragment in body]) self.body = iter(body) except TypeError: self.length = UNKNOWN_LENGTH self.body = body self.deferred = Deferred() self.consumer = consumer def resumeProducing(self): try: chunk = self.body.next() except StopIteration, e: self.consumer.unregisterProducer() if self.deferred is not None: self.deferred.callback(self.consumer) self.deferred = None return self.consumer.write(chunk)
def noop(id, data, config, runsettings): """ Do nothing """ d = Deferred() d.callback(True) return d
class SubprocessProtocol(protocol.ProcessProtocol): """Twisted-friendly subprocess.""" def __init__(self, args, environment): self.deferred = Deferred() self.buffer = StringIO() reactor.spawnProcess(self, args[0], args, self.clean_environ(environment)) def outReceived(self, data): self.buffer.write(data) def errReceived(self, data): self.outReceived(data) def processEnded(self, status): self.deferred.callback(self.buffer.getvalue()) @staticmethod def clean_environ(environ): """Filter non-string items from environ, as reactor.spawnProcess cannot handle them.""" for k, v in environ.items(): if type(v) not in [str, unicode]: environ.pop(k) return environ
class WebSocketConnection(WebSocketProtocol): def __init__(self, stateObject): self.state = stateObject self.opcode = TEXT WebSocketProtocol.__init__(self, WebSocketReceiver(self)) self.finished = Deferred() self.pingLoop = LoopingCall(self.doPing) def doPing(self): self.receiver.transport.sendFrame(PING, '') def write(self, data): self.receiver.transport.sendFrame(self.opcode, data) def sendFrame(self, opcode, data): self.receiver.transport.sendFrame(opcode, data) def writeSequence(self, data): for chunk in data: self.write(chunk) def connectionLost(self, reason): if self.pingLoop.running: self.pingLoop.stop() self.finished.callback(self)
def test_producer_send_messages_no_acks(self): first_part = 19 client = Mock() ret = Deferred() client.send_produce_request.return_value = ret client.topic_partitions = {self.topic: [first_part, 101, 102, 103]} client.metadata_error_for_topic.return_value = False msgs = [self.msg("one"), self.msg("two")] ack_timeout = 5 producer = Producer(client, ack_timeout=ack_timeout, req_acks=PRODUCER_ACK_NOT_REQUIRED) d = producer.send_messages(self.topic, msgs=msgs) # Check the expected request was sent msgSet = create_message_set( make_send_requests(msgs), producer.codec) req = ProduceRequest(self.topic, first_part, msgSet) client.send_produce_request.assert_called_once_with( [req], acks=producer.req_acks, timeout=ack_timeout, fail_on_error=False) # Check results when "response" fires self.assertNoResult(d) ret.callback([]) result = self.successResultOf(d) self.assertEqual(result, None) producer.stop()
def test_producer_cancel_one_request_getting_topic(self): # Test cancelling a request after it's begun to be processed client = Mock() client.topic_partitions = {} ret = Deferred() client.load_metadata_for_topics.return_value = ret msgs = [self.msg("one"), self.msg("two")] msgs2 = [self.msg("three"), self.msg("four")] batch_n = 4 producer = Producer(client, batch_every_n=batch_n, batch_send=True) d1 = producer.send_messages(self.topic, msgs=msgs) # Check that no request was sent self.assertFalse(client.send_produce_request.called) # This will trigger the metadata lookup d2 = producer.send_messages(self.topic, msgs=msgs2) d1.cancel() self.failureResultOf(d1, CancelledError) # Check that still no request was sent self.assertFalse(client.send_produce_request.called) self.assertNoResult(d2) # Setup the client's topics and trigger the metadata deferred client.topic_partitions = {self.topic: [0, 1, 2, 3]} client.metadata_error_for_topic.return_value = False ret.callback(None) # Expect that only the msgs2 messages were sent msgSet = create_message_set( make_send_requests(msgs2), producer.codec) req = ProduceRequest(self.topic, 1, msgSet) client.send_produce_request.assert_called_once_with( [req], acks=producer.req_acks, timeout=producer.ack_timeout, fail_on_error=False) producer.stop()
def sync_box(self, root_box): """ Start syncing the named box. """ logging.debug("WebServer, sync_box for root_box {0}".format(root_box)) return_d = Deferred() if root_box in self.syncs: logging.error("sync_box: returning from cache") indxsync = self.syncs[root_box] return_d.callback(indxsync) else: def err_cb(failure): logging.error("WebServer, sync_box error getting token: {0} {1}".format(failure, failure.value)) # FIXME do something with the error? return_d.errback(failure) self.syncs[root_box] = None # reserve the slot def store_cb(root_store): indxsync = IndxSync(root_store, self.database, self.server_url, self.keystore, self) self.syncs[root_box] = indxsync return_d.callback(indxsync) # assign ourselves a new token to access the root box using the @indx user # this only works because the "create_root_box" function gave this user read permission # this doesn't work in the general case. def token_cb(token): token.get_store().addCallbacks(store_cb, err_cb) self.tokens.new("@indx","",root_box,"IndxSync","/","::1", self.server_id).addCallbacks(token_cb, return_d.errback) return return_d
class Engine: def __init__(self, controller): self._ctrl = controller self._ctrl.add_engine(self) self.deferred = Deferred() def _signal(self, name, *args, **keywords): self._ctrl.signal(name, *args, **keywords) def __stop(self): self._ctrl.remove_engine(self) def _success(self, result=None): self.__stop() self.deferred.callback(result) def _failure(self, fail='Engine failed'): self.__stop() self.deferred.errback(fail) def abort(self): """Aborts this engine, does not emit a signal.""" self.__stop() def send(self, something): return self._ctrl.send(something) def sendall(self, something): return self._ctrl.sendall(something)
class SpoolingSignalProtocol(Protocol): def __init__(self, *args, **kwargs): self.spooling = SpoolingProtocol() self.signaling = SignalProtocol(*args, **kwargs) self.finished = None def connectionMade(self): self.finished = Deferred() def connectionLost(self, reason): if reason.type is ProcessTerminated: self.finished.errback(reason.value) else: self.finished.callback(reason.value) def dataReceived(self, data): self.signaling.dataReceived(data) self.spooling.dataReceived(data) def extReceived(self, fd, data): self.signaling.extReceived(fd, data) self.spooling.extReceived(fd, data) def flush(self): return self.spooling.flush()
def start(self): # We need to run 4 commands in a row, and each of them can fail d = Deferred() def chain(args, description, failMessage): d.addCallback(self._spawnProcess, args, description, failMessage) for serviceName in ['manager', 'worker']: chain(["flumotion", "-C", self._confDir, "-L", self._logDir, "-R", self._runDir, "create", serviceName, "admin", str(self._port)], _('Creating %s ...') % serviceName, _("Could not create %s." % serviceName)) chain(["flumotion", "-C", self._confDir, "-L", self._logDir, "-R", self._runDir, "start", serviceName, "admin"], _('Starting %s ...' % serviceName), _("Could not start %s." % serviceName)) d.addErrback(lambda f: None) def done(result): self._finished() d.addCallback(done) # start chain d.callback(None) return d
def put(self, uaid=""): """HTTP PUT Update router type/data for a UAID. """ self.start_time = time.time() if not self._validate_auth(uaid): return self._write_response( 401, 109, message="Invalid Authentication") params = self._load_params() self.uaid = uaid router_type = params.get("type") router_data = params.get("data") if router_type not in self.ap_settings.routers or not router_data: log.msg("Invalid parameters", **self._client_info()) return self._write_response( 400, 108, message="Invalid arguments") self.add_header("Content-Type", "application/json") router = self.ap_settings.routers[router_type] d = Deferred() d.addCallback(router.register, router_data) d.addCallback(self._save_router_data, router_type) d.addCallback(self._success) d.addErrback(self._router_fail_err) d.addErrback(self._response_err) d.callback(uaid)
def test_log_while_connecting(self): connect_d = Deferred() real_connect = self.endpoint.connect.side_effect def _delay_connect(factory): d = real_connect(factory) connect_d.addCallback(lambda _: d) return connect_d self.endpoint.connect.side_effect = _delay_connect client = ScribeClient(self.endpoint) d = client.log('category', 'message') self.assertEqual(self.client_proto.client.Log.call_count, 0) d2 = client.log('category', 'message') self.assertEqual(self.client_proto.client.Log.call_count, 0) connect_d.callback(None) self.assertEqual(self.assertFired(d), ttypes.ResultCode.OK) self.assertEqual(self.assertFired(d2), ttypes.ResultCode.OK) self.assertEqual(self.client_proto.client.Log.call_count, 2)
def test_rewind_blocks_on_deferreds_returned_by_ops(self): """ rewind will serialize operations waiting on any deferreds returned before running the next operation. """ called = [0] def op(op_d): called[0] += 1 return op_d op_d1 = Deferred() self.undo.push(op, op_d1) op_d2 = Deferred() self.undo.push(op, op_d2) d = self.undo.rewind() self.assertEqual(called[0], 1) self.assertNoResult(d) op_d2.callback(None) self.assertEqual(called[0], 2) self.assertNoResult(d) op_d1.callback(None) self.successResultOf(d)
def get_package(self, request, from_ip=None): commands = self._parse_request(request) d = Deferred() d.callback(commands) return d
def stop_daemon(self, host_id): """ Stops a running daemon. :param host_id: the hash id of the host :type host_id: string """ main_deferred = Deferred() host = self.get_host(host_id) if not host: main_deferred.callback((False, _("Daemon doesn't exist"))) return main_deferred try: def on_connect(connected, c): if not connected: main_deferred.callback((False, _("Daemon not running"))) return c.daemon.shutdown() main_deferred.callback((True, )) def on_connect_failed(reason): main_deferred.callback((False, reason)) host, port, user, password = host[1:5] c = Client() d = c.connect(host, port, user, password) d.addCallback(on_connect, c) d.addErrback(on_connect_failed) except: main_deferred.callback((False, "An error occurred")) return main_deferred
class TestBase(object): def __init__(self, conn, iTag, testType): self._conn = conn self._iTag = iTag self._testType = testType self._data = [] def _activate(self): pass def _deactivate(self): pass def _run(self): raise NotImplementedError def run(self, _): self._deferred = Deferred() self._conn.reactor.callLater(1, self._activate) self._conn.reactor.callLater(2, self._run) return self._deferred def _done(self): self._deactivate() self._deferred.callback(None) def __str__(self): return json.dumps({'type' : self._testType, 'data' : self._data})
def scale_down(self): global overlay n_workers = len(overlay.aws.workers) d = Deferred() for i in range(1, 1 + n_workers / 2): d.addCallback(overlay.aws.term_worker(overlay.aws.workers[i])) d.callback(0);
def test_double_subscribe(self): handler = ApplicationSession() MockTransport(handler) event0 = Deferred() event1 = Deferred() subscription0 = yield handler.subscribe( lambda: event0.callback(42), u'com.myapp.topic1') subscription1 = yield handler.subscribe( lambda: event1.callback('foo'), u'com.myapp.topic1') # same topic, same ID self.assertTrue(subscription0.id == subscription1.id) # do a publish (MockTransport fakes the acknowledgement # message) and then do an actual publish event. The IDs # are the same, so we just do one Event. publish = yield handler.publish( u'com.myapp.topic1', options=types.PublishOptions(acknowledge=True, exclude_me=False), ) handler.onMessage(message.Event(subscription0.id, publish.id)) # ensure we actually got both callbacks self.assertTrue(event0.called, "Missing callback") self.assertTrue(event1.called, "Missing callback")
class DummyClient(DatagramProtocol): def __init__(self, *args, **kwargs): self.ready = Deferred() def startProtocol(self): self.ready.callback(None)
def test_deferPreCommit(self): """ If callables passed to L{IAsyncTransaction.preCommit} return L{Deferred}s, they will defer the actual commit operation until it has fired. """ txn = self.createTransaction() d = Deferred() def wait(): wait.started = True def executed(it): wait.sqlResult = it # To make sure the _underlying_ commit operation was Deferred, we # have to execute some SQL to make sure it happens. return (d.addCallback(lambda ignored: txn.execSQL("some test sql")) .addCallback(executed)) wait.started = False wait.sqlResult = None txn.preCommit(wait) result = self.resultOf(txn.commit()) self.flushHolders() self.assertEquals(wait.started, True) self.assertEquals(wait.sqlResult, None) self.assertEquals(result, []) d.callback(None) # allow network I/O for pooled / networked implementation; there should # be the commit message now. self.flushHolders() self.assertEquals(len(result), 1) self.assertEquals(wait.sqlResult, [[1, "some test sql"]])
def testTriggerSystemEvent4(self): # make sure interleaved event types do not interfere with each other. # Old cReactor code had a single defer_list for all event types. l = [] l2 = [] d = Deferred() d2 = Deferred() def _returnDeferred(d=d): return d def _returnDeferred2(d2=d2): return d2 def _appendToList(l=l): l.append(1) def _appendToList2(l2=l2): l2.append(1) r = reactor self.addTrigger("before", "event1", _returnDeferred) self.addTrigger("after", "event1", _appendToList) self.addTrigger("before", "event2", _returnDeferred2) self.addTrigger("after", "event2", _appendToList2) r.fireSystemEvent("event1") # event1 should be waiting on deferred 'd' r.fireSystemEvent("event2") # event2 should be waiting on deferred 'd2' self.assertEquals(len(l), 0, "Event should not have fired yet.") self.assertEquals(len(l2), 0, "Event should not have fired yet.") d.callback(None) # event1 should run "during" and "after" stages # event2 should still be waiting on d2 self.assertEquals(len(l), 1) self.assertEquals(len(l2), 0) d2.callback(None) # event2 should run "during" and "after" stages self.assertEquals(len(l), 1) self.assertEquals(len(l2), 1)
def testTriggerSystemEvent2(self): # one of the "before" trigger functions returns a deferred. A later # "before" trigger fires the deferred. A third before runs. Then a # "during" should be run. One of the failure modes for the old # cReactor code is to start the "during" as soon as the deferred # fires, rather than waiting for the "before" phase to be finished l = [] d = Deferred() d2 = Deferred() def _returnDeferred(d=d): return d def _fireDeferred(d=d): d.callback(None) def _returnDeferred2(d2=d2): return d2 def _appendToList(l=l): l.append(1) r = reactor # to test this properly, the triggers must fire in this sequence: # _returnDeferred, _fireDeferred, _returnDeferred2 . cReactor happens # to run triggers in the order in which they were added. self.addTrigger("before", "defer2", _returnDeferred) self.addTrigger("before", "defer2", _fireDeferred) self.addTrigger("before", "defer2", _returnDeferred2) self.addTrigger("during", "defer2", _appendToList) self.addTrigger("after", "defer2", _appendToList) r.fireSystemEvent("defer2") self.assertEquals(len(l), 0, "Event should not have fired yet.") d2.callback(None) self.assertEquals(len(l), 2)
def testTriggerSystemEvent3(self): # make sure reactor can survive the loss of an event type while # waiting for a before-trigger's Deferred to fire l = [] d = Deferred() d2 = Deferred() def _returnDeferred(d=d): return d def _appendToList(l=l): l.append(1) def _ignore(failure): return None r = reactor b1 = self.addTrigger("before", "defer3", _returnDeferred) b2 = self.addTrigger("after", "defer3", _appendToList) r.fireSystemEvent("defer3") self.assertEquals(len(l), 0, "Event should not have fired yet.") self.removeTrigger(b1) self.removeTrigger(b2) try: d.callback(None) # cReactor gives errback to deferred except ValueError: pass self.assertEquals(len(l), 0) d.addErrback(_ignore)
def get(self, tid): """ Used to get a token by the BaseHandler, and whenever a handler needs to token (usually because it wants to access the store object). tid -- The ID of the Token to get, it must have already been created, usually by the get_token call to the AuthHandler. """ return_d = Deferred() if self.tokens.get(tid) is not None: # already in cache, return existing return_d.callback(self.tokens.get(tid)) return return_d # otherwise check the db def token_cb(token_tuple): if token_tuple is None: return_d.callback(None) return username, password, boxid, appid, origin, clientip, server_id = token_tuple token = Token(self.db, username, password, boxid, appid, origin, clientip, server_id) self.add(token) return_d.callback(token) return self.db.get_token(tid).addCallbacks(token_cb, return_d.errback) return return_d
def test_subsequentBeforeTriggerFiresPriorBeforeDeferred(self): """ If a trigger added to the C{'before'} phase of an event calls back a L{Deferred} returned by an earlier trigger in the C{'before'} phase of the same event, the remaining C{'before'} triggers for that event should be run and any further L{Deferred}s waited on before proceeding to the C{'during'} events. """ eventType = 'test' events = [] firstDeferred = Deferred() secondDeferred = Deferred() def firstBeforeTrigger(): return firstDeferred def secondBeforeTrigger(): firstDeferred.callback(None) def thirdBeforeTrigger(): events.append('before') return secondDeferred def duringTrigger(): events.append('during') self.addTrigger('before', eventType, firstBeforeTrigger) self.addTrigger('before', eventType, secondBeforeTrigger) self.addTrigger('before', eventType, thirdBeforeTrigger) self.addTrigger('during', eventType, duringTrigger) self.assertEqual(events, []) reactor.fireSystemEvent(eventType) self.assertEqual(events, ['before']) secondDeferred.callback(None) self.assertEqual(events, ['before', 'during'])
def test_multipleBeforeReturnDeferred(self): """ If more than one trigger added to the C{'before'} phase of an event return L{Deferred}s, the C{'during'} phase should be delayed until they are all called back. """ firstDeferred = Deferred() secondDeferred = Deferred() eventType = 'test' events = [] def firstBeforeTrigger(): return firstDeferred def secondBeforeTrigger(): return secondDeferred def duringTrigger(): events.append('during') self.addTrigger('before', eventType, firstBeforeTrigger) self.addTrigger('before', eventType, secondBeforeTrigger) self.addTrigger('during', eventType, duringTrigger) self.assertEqual(events, []) reactor.fireSystemEvent(eventType) self.assertEqual(events, []) firstDeferred.callback(None) self.assertEqual(events, []) secondDeferred.callback(None) self.assertEqual(events, ['during'])
class Locations(YomboLibrary): """ Manages locations for a gateway. """ @property def locations_sorted(self): return OrderedDict( sorted(self.locations.items(), key=lambda x: x[1].label)) def __contains__(self, location_requested): """ Checks to if a provided location ID or machine_label exists. >>> if '0kas02j1zss349k1' in self._Locations: or: >>> if 'some_location_name' in self.Locations: :raises YomboWarning: Raised when request is malformed. :raises KeyError: Raised when request is not found. :param location_requested: The location id or machine_label to search for. :type location_requested: string :return: Returns true if exists, otherwise false. :rtype: bool """ try: self.get_meta(location_requested) return True except: return False def __getitem__(self, location_requested): """ Attempts to find the location requested using a couple of methods. >>> location = self.Locations['0kas02j1zss349k1'] #by uuid or: >>> location = self.Locations['alpnum'] #by name :raises YomboWarning: Raised when request is malformed. :raises KeyError: Raised when request is not found. :param location_requested: The location ID or machine_label to search for. :type location_requested: string :return: A pointer to the location type instance. :rtype: instance """ return self.get_meta(location_requested) def __setitem__(self, **kwargs): """ Sets are not allowed. Raises exception. :raises Exception: Always raised. """ raise Exception("Not allowed.") def __delitem__(self, **kwargs): """ Deletes are not allowed. Raises exception. :raises Exception: Always raised. """ raise Exception("Not allowed.") def __iter__(self): """ iter locations. """ return self.locations.__iter__() def __len__(self): """ Returns an int of the number of locations configured. :return: The number of locations configured. :rtype: int """ return len(self.locations) def __str__(self): """ Returns the name of the library. :return: Name of the library :rtype: string """ return self.locations.__str__() def keys(self): """ Returns the keys (location ID's) that are configured. :return: A list of location IDs. :rtype: list """ return list(self.locations.keys()) def items(self): """ Gets a list of tuples representing the locations configured. :return: A list of tuples. :rtype: list """ return list(self.locations.items()) def values(self): return list(self.locations.values()) def _init_(self, **kwargs): """ Setups up the basic framework. Nothing is loaded in here until the Load() stage. """ self.load_deferred = None # Prevents loader from moving on past _load_ until we are done. self.locations = {} self.location_search_attributes = [ 'location_id', 'gateway_id', 'location', 'machine_label', 'destination', 'data_type', 'status' ] self.load_deferred = Deferred() self._load_locations_from_database() return self.load_deferred # def _load_(self): # """ # Loads all locations from DB to various arrays for quick lookup. # """ def _stop_(self, **kwargs): """ Cleans up any pending deferreds. """ if hasattr(self, 'load_deferred'): if self.load_deferred is not None and self.load_deferred.called is False: self.load_deferred.callback( 1) # if we don't check for this, we can't stop! @inlineCallbacks def _load_locations_from_database(self): """ Loads locations from database and sends them to :py:meth:`import_location <Locations.import_location>` This can be triggered either on system startup or when new/updated locations have been saved to the database and we need to refresh existing locations. """ locations = yield self._LocalDB.get_locations() for location in locations: self.import_location(location.__dict__) self.load_deferred.callback(10) def import_location(self, location, test_location=False): """ Add a new locations to memory or update an existing locations. **Hooks called**: * _location_before_load_ : If added, sends location dictionary as 'location' * _location_before_update_ : If updated, sends location dictionary as 'location' * _location_loaded_ : If added, send the location instance as 'location' * _location_updated_ : If updated, send the location instance as 'location' :param location: A dictionary of items required to either setup a new location or update an existing one. :type input: dict :param test_location: Used for unit testing. :type test_location: bool :returns: Pointer to new input. Only used during unittest """ # logger.debug("location: {location}", location=location) global_invoke_all('_locations_before_import_', called_by=self, **{'location': location}) location_id = location["id"] if location_id not in self.locations: global_invoke_all('_location_before_load_', called_by=self, **{'location': location}) self.locations[location_id] = Location(self, location) global_invoke_all('_location_loaded_', called_by=self, **{'location': self.locations[location_id]}) elif location_id not in self.locations: global_invoke_all('_location_before_update_', called_by=self, **{'location': location}) self.locations[location_id].update_attributes(location) global_invoke_all('_location_updated_', called_by=self, **{'location': self.locations[location_id]}) def remove_location(self, location_id): """ Remove a location from memory. :param location_id: :return: """ if location_id in self.locations: del self.locations[location_id] def area_label( self, area_id: dict( type=str, help="Area ID (location) to use for prepending to label"), label: dict(type=str, help="Label to prepend Area to.") ) -> dict(type=str, help="The result of: area + label"): """ Adds an area label to a provided string (label). """ if area_id in self.locations: area_label = self.locations[area_id].label if area_label.lower() != "none" and area_label is not None: return "%s %s" % (area_label, label) return label def full_label( self, location_id: dict(type=str, help="Location ID to use for prepending to label"), area_id: dict( type=str, help="Area ID (location) to use for prepending to label"), label: dict(type=str, help="Label to prepend Location and Area to.") ) -> dict(type=str, help="The result of: location + area + label"): """ Adds location and area to a provided string (label). """ output = "" if location_id in self.locations: location_label = self.locations[location_id].label if location_label.lower() != "none" and location_label is not None: output = location_label if area_id in self.locations: area_label = self.locations[area_id].label if area_label.lower() != "none" and area_label is not None: return "%s %s %s" % (output, area_label, label) return "%s %s" % (output, label) def get_all(self): """ Returns a copy of the locations list. :return: """ return self.locations.copy() def get(self, location_requested, location_type=None, limiter=None, status=None): """ Performs the actual search. .. note:: Can use the built in methods below or use get_meta/get to include 'location_type' limiter: >>> self.Locations['13ase45'] or: >>> self.Locations['numeric'] :raises YomboWarning: For invalid requests. :raises KeyError: When item requested cannot be found. :param location_requested: The location ID or location label to search for. :type location_requested: string :param limiter_override: Default: .89 - A value between .5 and .99. Sets how close of a match it the search should be. :type limiter_override: float :param status: Deafult: 1 - The status of the location to check for. :type status: int :return: Pointer to requested location. :rtype: dict """ if limiter is None: limiter = .89 if limiter > .99999999: limiter = .99 elif limiter < .10: limiter = .10 if status is None: status = 1 if location_requested in self.locations: item = self.locations[location_requested] if item.status != status: raise KeyError( "Requested location found, but has invalid status: %s" % item.status) return item else: attrs = [{ 'field': 'location_id', 'value': location_requested, 'limiter': limiter, }, { 'field': 'machine_label', 'value': location_requested, 'limiter': limiter, }, { 'field': 'label', 'value': location_requested, 'limiter': limiter, }] try: # logger.debug("Get is about to call search...: %s" % location_requested) # found, key, item, ratio, others = self._search(attrs, operation="highest") found, key, item, ratio, others = do_search_instance( attrs, self.locations, self.location_search_attributes, limiter=limiter, operation="highest") # logger.debug("found location by search: others: {others}", others=others) if location_type is not None: for other in others: if other[ 'value'].location_type == location_type and other[ 'ratio'] > limiter: return other['value'] else: if found: return item raise KeyError("Location not found: %s" % location_requested) except YomboWarning as e: raise KeyError('Searched for %s, but had problems: %s' % (location_requested, e)) def search(self, _limiter=None, _operation=None, **kwargs): """ Search for location based on attributes for all locations. :param limiter_override: Default: .89 - A value between .5 and .99. Sets how close of a match it the search should be. :type limiter_override: float :param status: Deafult: 1 - The status of the location to check for. :return: """ return search_instance(kwargs, self.locations, self.location_search_attributes, _limiter, _operation) @inlineCallbacks def add_location(self, data, **kwargs): """ Add a location at the Yombo server level, not at the local gateway level. :param data: :param kwargs: :return: """ location_results = yield self._YomboAPI.request( 'POST', '/v1/location', data) if location_results['code'] > 299: results = { 'status': 'failed', 'msg': "Couldn't add location", 'apimsg': location_results['content']['message'], 'apimsghtml': location_results['content']['html_message'], } return results results = { 'status': 'success', 'msg': "Location type added.", 'location_id': location_results['data']['id'], } data['id'] = location_results['data']['id'] data['updated_at'] = time() data['created_at'] = time() self._LocalDB.insert_locations(data) self.import_location(data) return results @inlineCallbacks def edit_location(self, location_id, data, **kwargs): """ Edit a location at the Yombo server level, not at the local gateway level. :param data: :param kwargs: :return: """ location_results = yield self._YomboAPI.request( 'PATCH', '/v1/location/%s' % (location_id), data) if location_results['code'] > 299: results = { 'status': 'failed', 'msg': "Couldn't edit location", 'apimsg': location_results['content']['message'], 'apimsghtml': location_results['content']['html_message'], } return results results = { 'status': 'success', 'msg': "Device type edited.", 'location_id': location_results['data']['id'], } if location_id in self.locations: self.locations[location_id].update_attributes(data) self.locations[location_id].save_to_db(data) return results @inlineCallbacks def delete_location(self, location_id, **kwargs): """ Delete a location at the Yombo server level, not at the local gateway level. :param location_id: The location ID to delete. :param kwargs: :return: """ location_results = yield self._YomboAPI.request( 'DELETE', '/v1/location/%s' % location_id) if location_results['code'] > 299: results = { 'status': 'failed', 'msg': "Couldn't delete location", 'apimsg': location_results['content']['message'], 'apimsghtml': location_results['content']['html_message'], } return results results = { 'status': 'success', 'msg': "Location deleted.", 'location_id': location_id, } self.remove_location(location_id) self._LocalDB.delete_locations(location_id) return results
def closure(future, adapt): if isinstance(future, Deferred): d = Deferred() future.addCallback(lambda r: d.callback(adapt(r))) return d return adapt(future)