PK!q77radar_server/__init__.pyfrom radar_server.radar import Radar from radar_server import fields from radar_server.query import Query from radar_server.action import Action from radar_server.record import Record from radar_server.interface import Interface from radar_server.union import Union from radar_server import utils from radar_server.exceptions import QueryErrors, ActionErrors, RecordIsNull ''' Radar -> Query+Action (records[requested], **params) Record (query, fields[requested], index, **params) Field (query, record, fields[requested_within], index[record index], **params) ''' PK!LƎ/EEradar_server/action.pyfrom radar_server.query import Query class Action(Query): pass PK!Kradar_server/exceptions.pyclass FieldNotFound(Exception): pass class MissingApplyMethod(Exception): pass class RecordKeyError(Exception): pass class QueryError(Exception): pass class ActionError(Exception): pass class QueryErrors(Exception): def __init__(self, *messages, code=None): self.messages = list(messages) self.code = code def for_json(self): return { 'errors': [{'message': message, 'code': self.code} for message in self.messages] } class ActionErrors(QueryErrors): pass class RecordIsNull(Exception): pass class OperationNotFound(Exception): pass PK!B33radar_server/fields/__init__.pyfrom radar_server.fields.field import Field from radar_server.fields.float import Float from radar_server.fields.integer import Int from radar_server.fields.string import String from radar_server.fields.array import Array from radar_server.fields.boolean import Bool from radar_server.fields.obj import Obj PK!e<0\\radar_server/fields/array.pyimport functools from .field import Field __all__ = 'Array', def cast_array(cast): @functools.wraps(cast) def apply(value): return list(map(cast, value)) return apply class Array(Field): __slots__ = Field.__slots__ def __init__(self, *a, cast=str, **kw): super().__init__(*a, cast=cast_array(cast), **kw) PK!)a/radar_server/fields/boolean.pyfrom .field import Field __all__ = 'Bool', class Bool(Field): __slots__ = Field.__slots__ def __init__(self, *a, cast=bool, **kw): super().__init__(*a, cast=cast, **kw) PK!.00radar_server/fields/field.pyfrom vital.debug import preprX __all__ = 'Field', def default_cast(x): return x def default_resolver(field_name, state, record=None, query=None, **context): try: return state[field_name] except (KeyError, TypeError): raise KeyError( f'Key `{field_name}` not found in Record `{record.__NAME__}` of ' f'Query `{query.__NAME__}`.' ) class Field(object): __slots__ = 'key', 'cast', 'resolver', 'not_null', 'default', '__NAME__' def __init__( self, resolver=default_resolver, key=False, not_null=False, default=None, cast=default_cast ): """ @key: Universally unique field which identifies your Schema """ self.resolver = resolver self.not_null = not_null self.cast = cast self.default = default self.key = key self.__NAME__ = None __repr__ = preprX('__NAME__', 'key', address=False) def __call__(self, value=None): if value is not None: try: return self.cast(value) if not isinstance(value, self.cast) else value except TypeError: return self.cast(value) else: if self.default is None: if self.not_null: raise ValueError(f'Field `{self.__NAME__}` cannot be null.') else: return None else: return self.default def copy(self): return self.__class__( self.resolver, key=self.key, not_null=self.not_null, default=self.default, cast=self.cast ) def resolve(self, state, **context): output = self.resolver(self.__NAME__, state, **context) return self.__call__(output) PK!radar_server/fields/float.pyfrom .field import Field __all__ = 'Float', class Float(Field): __slots__ = Field.__slots__ def __init__(self, *a, cast=float, **kw): super().__init__(*a, cast=cast, **kw) PK!@{radar_server/fields/integer.pyfrom .field import Field __all__ = 'Int', class Int(Field): __slots__ = Field.__slots__ def __init__(self, *a, cast=int, **kw): super().__init__(*a, cast=cast, **kw) PK!kGGradar_server/fields/obj.pyfrom .field import Field from ..interface import Interface from ..exceptions import FieldNotFound from ..utils import to_js_key __all__ = 'Obj', class Obj(Field, Interface): __slots__ = Field.__slots__ def __init__(self, not_null=False, default=None, cast=dict): def resolver(state, fields=None, **context): return { to_js_key(field.__NAME__): field.resolve(state[self.__NAME__], **context) for field in self.get_fields(fields) } super().__init__( resolver, key=False, not_null=not_null, default=default, cast=cast ) def get_fields(self, fields): if not fields: for field in self.fields: yield field else: for field_name in fields: field = getattr(self, field_name) if field in self.fields: yield field else: raise FieldNotFound(f'Field "{field}" was not found in ' f'the object "{self.__NAME__}"') def resolve(self, state, **context): return self.__call__(self.resolver(state, **context)) def copy(self): return self.__class__(not_null=self.not_null, default=self.default, cast=self.cast) ''' from radar_server import Record, fields from vital.debug import Timer class MyObj(fields.Obj): foo = fields.String() class MyRecord(Record): uid = fields.Int(key=True) my = MyObj() my = MyObj() my.__NAME__ = 'my' my.resolve({'my': {'foo': 'bar', 'bar': 'baz'}}) MyRecord().resolve({'my': None}, {'my': {'foo': 'bar', 'bar': 'baz'}, 'uid': 1234}) Timer(my.resolve, state={'my': {'foo': 'bar', 'bar': 'baz'}}).time(1E4) ''' PK!radar_server/fields/string.pyfrom .field import Field __all__ = 'String', class String(Field): __slots__ = Field.__slots__ def __init__(self, *a, cast=str, **kw): super().__init__(*a, cast=cast, **kw) PK!Z;;radar_server/interface.pyimport json from vital.debug import preprX from .exceptions import MissingApplyMethod from .fields import Field from .utils import to_js_keys, to_js_shape, get_class_attrs __all__ = 'get_fields', 'Interface' JS_TPL = '''import {{createInterface}} from 'react-radar_server' export default createInterface({{ name: '{name}', fields: {shape} }})''' def get_fields(attrs): for k, v in attrs.items(): field = attrs[k] is_interface = hasattr(field, '__is_radar_interface__') if is_interface or isinstance(attrs[k], Field): field.__NAME__ = k yield field class MetaInterface(type): def __new__(cls, name, bases, attrs): attrs['fields'] = tuple(get_fields(attrs)) return super().__new__(cls, name, bases, attrs) class Interface(object, metaclass=MetaInterface): __repr__ = preprX('fields', address=False) __is_radar_interface__ = True def __new__(cls, *a, **kw): interface = super().__new__(cls) interface.__init__(*a, **kw) interface.fields = tuple( field for k, v in get_class_attrs(interface.__class__) if k == 'fields' for field in v ) return interface def copy(self): return self.__class__() def to_js(self, indent=2, plugins=None): shape = {} for field in self.fields: if isinstance(field, self.__class__): shape[field.__NAME__] = field.to_js() else: shape[field.__NAME__] = field.default if plugins: for plugin in plugins: shape = plugin(shape) output = JS_TPL.format(name=self.__class__.__name__, shape=to_js_shape(shape, indent)) return to_js_keys(output) ''' from radar_server import Interface, fields class MyInterface(Interface): foo = fields.String(key=True) bar = fields.Int() class MySubInterface(MyInterface): baz = fields.Array() MySubInterface() from vital.debug import Timer Timer(MySubInterface).time(1E5) ''' PK!@ߋradar_server/query.pyfrom vital.debug import preprX from .record import Record from .interface import Interface from .exceptions import ( QueryError, QueryErrors, ActionErrors, RecordIsNull, MissingApplyMethod ) from .utils import to_python_key, to_js_key, get_class_attrs __all__ = 'transform_deep_keys', 'Query' def transform_deep_keys(props): return { to_python_key(key): ( val if not isinstance(val, dict) else transform_deep_keys(val) ) for key, val in props.items() } def get_records(attrs): for k, v in attrs.items(): record = attrs[k] if isinstance(record, Record): record.__NAME__ = k yield record class MetaQuery(type): def __new__(cls, name, bases, attrs): attrs['records'] = tuple(get_records(attrs)) return super().__new__(cls, name, bases, attrs) class Query(object, metaclass=MetaQuery): def __init__(self, callback=None): self._callback = callback __repr__ = preprX('records', address=False) def __new__(cls, *a, **kw): query = super().__new__(cls) query.__init__(*a, **kw) query.records = tuple( record for k, record in get_class_attrs(query.__class__) if isinstance(record, (Record, Interface)) ) if not len(query.records): raise QueryError( f'Query `{cls.__name__}` does not have any assigned Records. ' 'Queries must include returnable Records.' ) try: setattr(query, '__call__', query.apply) except AttributeError: raise MissingApplyMethod( f'Query {name} is missing an `apply` method. All queries must ' 'include an `apply` method which returns state for the records.' ) return query def get_required_records(self, records): if records: try: for record_name, fields in records.items(): yield ( record_name, getattr(self, record_name).get_required_fields(fields) ) except AttributeError: raise QueryError( f'Record `{record_name}` not found in ' f'Query `{self.__class__.__name__}`.' ) else: for record in self.records: yield ( record.__NAME__, getattr(self, record.__NAME__).get_required_fields() ) def resolve(self, records, props): required_records = dict( self.get_required_records(transform_deep_keys(records) or {}) ) # executes the apply function which is meant to fetch the result of # the actual query task state = self.apply(required_records, **transform_deep_keys(props)) state = {} if state is None else state output = {} for record_name, fields in required_records.items(): try: result = getattr(self, record_name).resolve( fields, state[record_name], query=self ) except RecordIsNull: result = None output[to_js_key(record_name)] = result if self._callback: return self._callback(output, query=self) else: return output def copy(self): return self.__class__(callback=self._callback) ''' from radar_server import Interface, Record, Query, fields from vital.debug import Timer class MyInterface(Interface): foo = fields.String(key=True) bar = fields.Int() class MySubInterface(MyInterface): baz = fields.Array() MySubInterface() Timer(MySubInterface).time(1E4) class MyRecord(Record): implements = [MySubInterface] boz = fields.Float() MyRecord() Timer(MyRecord).time(1E4) MyRecord.fields MyRecord().resolve({'foo': None}, {'foo': 'bar', 'bar': 'baz'}) Timer(MyRecord().resolve, fields={'foo': None}, state={'foo': 'bar', 'bar': 'baz'}).time(1E4) class MyQuery(Query): my = MyRecord() def apply(*args, **kwargs): return {'foo': 'bar', 'bar': 1, 'baz': ['a', 'b'], 'boz': 1.0} class MyQueries(Query): my = MyRecord(many=True) def apply(*args, **kwargs): return [{'foo': 'bar', 'bar': 1, 'baz': ['a', 'b'], 'boz': 1.0}, {'foo': 'bar', 'bar': 2, 'baz': ['c', 'd'], 'boz': 2.0}] MyQuery().resolve({'my': {'foo': None}}, {}) MyQueries().resolve({'my': {'foo': None}}, {}) Timer(MyQueries().resolve, records={'my': {'foo': None}}, props={}).time(1E4) Timer(MyQuery().resolve, records={'my': {}}, props={}).time(1E4) ''' PK! u= = radar_server/radar.pytry: import ujson as json except ImportError: import json from radar_server.exceptions import ( QueryError, ActionError, ActionErrors, QueryErrors, OperationNotFound ) empty_dict = {} class Radar(object): __slots__ = 'queries', 'raises' def __init__(self, queries=None, raises=True): self.queries = {} if queries: self.install_query(*queries) self.raises = raises def __call__(self, state, is_json=True): return self.resolve(state, is_json=is_json) def resolver(self, *a, **kw): def apply(cls): self.install_query(cls(*a, **kw)) return cls return apply query = resolver action = query def add(self, *queries): for query in queries: query_name = ( query.__NAME__ if hasattr(query, '__NAME__') else query.__class__.__name__ ) query.__NAME__ = query_name self.queries[query_name] = query install_query = add install_action = add def remove(self, *queries): for query in queries: del self.queries[query.name] def resolve_query(self, query_data): # query_requires = query_data.get('contains', empty_dict) query_requires = query_data.get('requires', empty_dict) query_params = query_data.get('props', empty_dict) query = self.get_query(query_data['name']) result = {} try: result = query.resolve(query_requires, query_params) except (QueryError, ActionError, ActionErrors, QueryErrors): result = None except Exception as e: if self.raises: raise e return result def resolve(self, operations, is_json=True): operations = json.loads(operations) \ if isinstance(operations, str) else operations out = [] add_out = out.append for operation in operations: if operation is None: add_out(None) elif operation['name'] in self.queries: add_out(self.resolve_query(operation)) else: raise OperationNotFound( f'A query with the name "{operation["name"]}" was not found.' ) return out PK!kYradar_server/record.pyfrom vital.debug import preprX from .fields import Field, Obj from .exceptions import FieldNotFound, RecordKeyError, RecordIsNull from .interface import Interface from .utils import to_js_key, to_js_shape __all__ = 'Record', 'get_interface_fields', def get_interface_fields(record): fields = record.fields for interface_cls in record.implements: for field in interface_cls().fields: if field not in fields: setattr(record, field.__NAME__, field) yield field class Record(Interface): def __init__(self, many=False, callback=None): """ @many: will return #list if @many is |True| """ super().__init__() self._many = many self._callback = callback __repr__ = preprX('__NAME__', 'fields', address=False) def __new__(cls, *a, **kw): record = super().__new__(cls) record.__init__(*a, **kw) if hasattr(record, 'implements'): fields = get_interface_fields(record) record.fields = tuple((*fields, *record.fields)) for field in record.fields: if isinstance(field, Field) and field.key is True: record._key = field return record raise RecordKeyError(f'Record `{cls.__name__}` does not have a Key field.') def get_field(self, field_name): field = getattr(self, field_name) if isinstance(field, (Field, Record)): return field raise FieldNotFound(f'Field named `{field_name}` was not found in ' f'Record `{self.__NAME__}`') def get_required_field(self, field, child_fields=None): if isinstance(field, Record): yield field.__NAME__, field.get_required_fields(child_fields) elif isinstance(field, Obj): yield ( field.__NAME__, { child_field.__NAME__: dict(self.get_required_field( child_field, child_fields[child_field.__NAME__] if child_fields else None )) for child_field in field.fields if child_fields and child_field.__NAME__ in child_fields } ) else: yield field.__NAME__, None def get_required_fields(self, input_fields=None): #: TODO: tailcall optimiztaion w/ while loop output = {} if input_fields is None or not len(input_fields): for field in self.fields: for k, v in self.get_required_field(field): output[k] = v else: for field_name, child_fields in input_fields.items(): # field_name = to_python_key(field_name) field = self.get_field(field_name) for k, v in self.get_required_field(field, child_fields): output[k] = v return output def resolve_field(self, field_name, state, fields=None, record=None, **context): field = self.get_field(field_name) if isinstance(field, Record): try: return field.resolve(fields, state, record=self, **context) except RecordIsNull: return None else: if fields is None: return field.resolve(state, record=self, **context) return field.resolve(state, record=self, fields=fields, **context) def resolve_fields(self, fields, state, **context): if fields: fields = fields.items() if hasattr(fields, 'items') else fields for field_name, nested in fields: if nested is not None: yield ( field_name, self.resolve_field(field_name, state, fields=nested, **context) ) else: yield ( field_name, self.resolve_field(field_name, state, **context) ) else: for field in self.fields: yield ( field.__NAME__, self.resolve_field(field.__NAME__, state, **context) ) def _resolve(self, fields, state, index=None, **context): state = self.reduce(state, fields=fields, index=index, **context) or {} if not isinstance(state, dict): raise TypeError('Data returned by `reduce` methods must be of type' f'`dict`. "{state}" is not a dict in Record: ' f'{self.__class__.__name__}') output = { to_js_key(name): value for name, value in self.resolve_fields(fields, state, **context) } key_name = to_js_key(self._key.__NAME__) if key_name not in fields: output[key_name] = self.resolve_field( self._key.__NAME__, state, fields=fields, **context ) if output[key_name] is None: raise RecordKeyError( f'Record `{self.__NAME__}` did not have a Key field ' 'with a value. Your Key field cannot ever return None.' ) try: return self._callback(self, output) except TypeError: return output def _resolve_many(self, *a, index=None, **kw): ''' includes index outside of kwargs in order to ignore it ''' index = 0 output = [] add_output = output.append while True: try: add_output(self._resolve(*a, index=index, **kw)) except IndexError: break index += 1 return output def resolve(self, fields, state, **context): if self._many: resolver = self._resolve_many else: resolver = self._resolve return resolver(fields, state, **context) def clear(self): for field in self.fields: field.clear() return self def reduce(self, state, index=None, **context): if context.get('record'): state = state[self.__NAME__] if state is None: raise RecordIsNull() if index is None: return state else: return state[index] def copy(self): cls = self.__class__(callback=self._callback, many=self._many) return cls ''' from radar_server import Interface, Record, fields class MyInterface(Interface): foo = fields.String(key=True) bar = fields.Int() class MySubInterface(MyInterface): baz = fields.Array() MySubInterface() from vital.debug import Timer Timer(MySubInterface).time(1E4) class MyRecord(Record): implements = [MySubInterface] boz = fields.Float() MyRecord() Timer(MyRecord).time(1E4) MyRecord.fields MyRecord().resolve({'foo': None}, {'foo': 'bar', 'bar': 'baz'}) Timer(MyRecord().resolve, fields={'foo': None}, state={'foo': 'bar', 'bar': 'baz'}).time(1E4) class MyNestedRecord(Record): implements = [MySubInterface] boz = fields.Float() class MyRecord(Record): uid = fields.String(key=True) nested = MyNestedRecord(many=True) Timer(MyRecord().resolve, fields={'nested': {'foo': None}, 'uid': None}}, state={'nested': [{ 'foo': 'bar', 'bar': 'baz'}], 'uid': 1}).time(1E4) ''' PK!86radar_server/union.pyfrom .exceptions import RecordIsNull from .interface import Interface from .record import Record from .fields import Field from .query import get_records from .utils import get_class_attrs, to_js_key class Union(Record): def __new__(cls, *a, **kw): union = super(Interface, cls).__new__(cls) union.__init__(*a, **kw) union.fields = tuple( record for k, record in get_class_attrs(union.__class__) if isinstance(record, (Record, Interface)) ) if not len(union.fields): raise TypeError( f'Union `{cls.__name__}` does not have any assigned Records. ' 'Unions must include returnable Records.' ) if not hasattr(union, 'get_record_type'): raise TypeError( 'Union `{cls.__name__}` does not have a `get_record_type` method.' 'Unions require a `get_record_type` method which ' 'returns a string specifying the proper Record to ' 'resolve for each resolution.' ) return union @property def records(self): return self.fields def get_field(self, field_name): field = getattr(self, field_name) if isinstance(field, Record): return field raise FieldNotFound(f'Field named `{field_name}` was not found in ' f'Record `{self.__NAME__}`') def resolve_field(self, field_name, state, fields=None, record=None, **context): field = self.get_field(field_name) try: return field.resolve(fields, state, **context) except RecordIsNull: return None def resolve_fields(self, fields, state, **context): # TODO: only resolve if record type is in @fields fields = fields or {} record_type = self.get_record_type(state, fields=fields, **context) if record_type is None: raise TypeError('Unions must return a string from their ' '`get_record_type` method specifying the proper Record' 'to resolve for each invocation. Check the ' f'`get_record_type` method of {self.__class__.__name__}') yield to_js_key(record_type), self.resolve_field( record_type, state, fields=fields.get(record_type), **context ) def _resolve(self, fields, state, index=None, **context): state = self.reduce(state, fields=fields, index=index, **context) or {} if not isinstance(state, dict): raise TypeError('Data returned by `reduce` methods must be of type' f'`dict`. "{state}" is not a dict in Record: ' f'{self.__class__.__name__}') output = dict(self.resolve_fields(fields, state, **context)) try: return self._callback(output, self) except TypeError: return output ''' from radar_server import Interface, Record, Query, Union, fields from vital.debug import Timer class MyInterface(Interface): foo = fields.String(key=True) bar = fields.Int() class MySubInterface(MyInterface): baz = fields.Array() MySubInterface() from vital.debug import Timer Timer(MySubInterface).time(1E4) class MyRecord(Record): implements = [MySubInterface] boz = fields.Float() class MyRecord2(Record): boz = fields.Float(key=True) class MyUnion(Union): my = MyRecord() your = MyRecord2() @staticmethod def get_record_type(state, *a, **kw): return 'your' if state.get('your') else 'my' MyUnion().resolve({'my': {'foo': None}}, {'my': {'foo': 'bar'}}) class MyUnionMany(Union): my = MyRecord(many=True) your = MyRecord2() @staticmethod def get_record_type(state, *a, **kw): return 'your' if state.get('your') else 'my' MyUnionMany().resolve({'my': {'foo': None}}, {'my': [{'foo': 'bar'}]}) class MyRecordMany(Record): key = fields.String(key=True) my = MyUnion(many=True) MyRecordMany().resolve({'my': {'my': {'foo': None}, 'your': {'boz': None}}}, {'my': [{'my': {'foo': 'bar'}}, {'my': {'foo': 'bar2'}}, {'your': {'boz': 1.0}}], 'key': 1}) ''' PK!oQTradar_server/utils.pyimport re import json from vital.cache import memoize from vital.tools import strings as string_tools __all__ = ( 'to_js_keys', 'transform_keys', 'to_js_shape', 'get_class_attrs', 'to_js_key', 'to_python_key' ) js_keys_re = re.compile(r"""([^\\])"([A-Za-z]+[A-Za-z0-9_]*?)":""") js_records_re = re.compile(r"""(:\s*)(")([A-Za-z0-9_]*?.fields)(")""") def to_js_keys(output): return js_records_re.sub(r'\1\3', js_keys_re.sub(r'\1\2:', output)) @memoize def to_js_key(key): camel = list(string_tools.underscore_to_camel(key)) next_char = 0 while True: try: char = camel[next_char] if char == '_': next_char += 1 continue if char.islower(): break camel[next_char] = char.lower() break except IndexError: break return ''.join(camel) @memoize def to_python_key(key): return string_tools.camel_to_underscore(key) def transform_keys(key, truthy_falsy, to_js=True): return string_tools.camel_to_underscore(key) if to_js is False else to_snake(key) def to_js_shape(shape, indent): return '\n'.join( (' ' * indent) + line if idx > 0 else line for idx, line in enumerate(json.dumps(shape, indent=indent).split('\n')) ) def get_class_attrs(base_cls): for cls in reversed(base_cls.__mro__): if cls != type and cls != object: for items in cls.__dict__.items(): yield items PK!QP55$radar_server-0.1.1.dist-info/LICENSEThe MIT License (MIT) Copyright (c) 2017 Jared Lunde Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.PK!Hu)GTU"radar_server-0.1.1.dist-info/WHEEL HM K-*ϳR03rOK-J,/R(O-)$qzd&Y)r$UV&UrPK!HO4U%radar_server-0.1.1.dist-info/METADATAMO1MhB & b@Tun?lE]P#7nMgPf%{5vxm8^S2.dUAq9#t" os/V&3i2~_7է~;9qurLT@Aw e"ꧼ 2aA0V |a~!G,;PK!H3p#radar_server-0.1.1.dist-info/RECORDɎH{? t/>`&ٌ O?Jj<=)"$1te[NA[1%0>K"],z|7^65czauº٧f/ߚe;y:lԮ } \{N`;#vWjUQGuZ\`lJSr08<[e]P6u.S9,4:d$ʢ$, &g)/x4zmDw̎6(`CG6r] M ctAe!W,^b?< Fƽ!5 4^w^w61גJ+MKc0l[ k9 9WpBo7\M|{u9%t1V5.^z蒆'fb' coT6ŖZ]3K*;*px}Lw D=9WZo#?חm~ /j %[]0CQT[H9zwQ!y6B]YO`šM6* #dχś`u5yI9O\kJ)WoiSr1fzmP:A$?U"PK!q77radar_server/__init__.pyPK!LƎ/EEmradar_server/action.pyPK!Kradar_server/exceptions.pyPK!B33radar_server/fields/__init__.pyPK!e<0\\ radar_server/fields/array.pyPK!)a/radar_server/fields/boolean.pyPK!.00 radar_server/fields/field.pyPK!radar_server/fields/float.pyPK!@{radar_server/fields/integer.pyPK!kGG radar_server/fields/obj.pyPK!radar_server/fields/string.pyPK!Z;;radar_server/interface.pyPK!@ߋ#radar_server/query.pyPK! u= = 6radar_server/radar.pyPK!kY<@radar_server/record.pyPK!86]radar_server/union.pyPK!oQT~nradar_server/utils.pyPK!QP55$tradar_server-0.1.1.dist-info/LICENSEPK!Hu)GTU",yradar_server-0.1.1.dist-info/WHEELPK!HO4U%yradar_server-0.1.1.dist-info/METADATAPK!H3p#7{radar_server-0.1.1.dist-info/RECORDPK9