diff --git a/code/zato-common/src/zato/common/rate_limiting/__init__.py b/code/zato-common/src/zato/common/rate_limiting/__init__.py index 87ae4aa5a7..7741c54792 100644 --- a/code/zato-common/src/zato/common/rate_limiting/__init__.py +++ b/code/zato-common/src/zato/common/rate_limiting/__init__.py @@ -1,13 +1,11 @@ # -*- coding: utf-8 -*- """ -Copyright (C) 2019, Zato Source s.r.o. https://zato.io +Copyright (C) 2023, Zato Source s.r.o. https://zato.io Licensed under LGPLv3, see LICENSE.txt for terms and conditions. """ -from __future__ import absolute_import, division, print_function, unicode_literals - # stdlib from contextlib import closing from logging import getLogger @@ -25,29 +23,20 @@ from zato.common.rate_limiting.common import Const, DefinitionItem, ObjectInfo from zato.common.rate_limiting.limiter import Approximate, Exact, RateLimitStateDelete, RateLimitStateTable -# Python 2/3 compatibility -from zato.common.py23_.past.builtins import unicode - +# ################################################################################################################################ # ################################################################################################################################ -# Type checking -import typing - -if typing.TYPE_CHECKING: - - # stdlib - from typing import Callable - - # Zato +if 0: from zato.common.rate_limiting.limiter import BaseLimiter + from zato.common.typing_ import callable_, dict_, list_, strdict from zato.distlock import LockManager # For pyflakes BaseLimiter = BaseLimiter - Callable = Callable LockManager = LockManager # ################################################################################################################################ +# ################################################################################################################################ logger = getLogger(__name__) @@ -59,15 +48,20 @@ class DefinitionParser: """ @staticmethod - def get_lines(definition, object_id, object_type, object_name, parse_only=False): - # type: (unicode, int, unicode, unicode, bool) -> list + def get_lines( + definition, # type: str + object_id, # type: int + object_type, # type: str + object_name, # type: str + parse_only=False # type: bool + ) -> 'list_[DefinitionItem]': if not parse_only: out = [] - definition = definition if isinstance(definition, unicode) else definition.decode('utf8') + definition = definition if isinstance(definition, str) else definition.decode('utf8') - for idx, orig_line in enumerate(definition.splitlines(), 1): # type: int, unicode + for idx, orig_line in enumerate(definition.splitlines(), 1): # type: int, str line = orig_line.strip() if (not line) or line.startswith('#'): @@ -76,7 +70,7 @@ def get_lines(definition, object_id, object_type, object_name, parse_only=False) line = line.split('=') if len(line) != 2: raise ValueError('Invalid definition line `{}`; (idx:{})'.format(orig_line, idx)) - from_, rate_info = line # type: unicode, unicode + from_, rate_info = line # type: str, str from_ = from_.strip() if from_ != Const.from_any: @@ -88,7 +82,7 @@ def get_lines(definition, object_id, object_type, object_name, parse_only=False) rate = Const.rate_any unit = Const.Unit.day # This is arbitrary but it does not matter because there is no rate limit in effect else: - rate, unit = rate_info.split('/') # type: unicode, unicode + rate, unit = rate_info.split('/') # type: str, str rate = int(rate.strip()) unit = unit.strip() @@ -117,23 +111,26 @@ def get_lines(definition, object_id, object_type, object_name, parse_only=False) # ################################################################################################################################ @staticmethod - def check_definition(definition): - # type: (unicode) + def check_definition(definition:'str') -> 'list_[DefinitionItem]': DefinitionParser.get_lines(definition.strip(), None, None, None, True) # ################################################################################################################################ @staticmethod - def check_definition_from_input(input_data): - # type: (dict) + def check_definition_from_input(input_data:'strdict') -> 'None': rate_limit_def = input_data.get('rate_limit_def') or '' if rate_limit_def: DefinitionParser.check_definition(rate_limit_def) # ################################################################################################################################ - def parse(self, definition, object_id, object_type, object_name): - # type: (unicode, int, unicode, unicode) -> list + def parse( + self, + definition, # type: str + object_id, # type: int + object_type, # type: str + object_name # type: str + ) -> 'list_[DefinitionItem]': return DefinitionParser.get_lines(definition.strip(), object_id, object_type, object_name) # ################################################################################################################################ @@ -144,30 +141,28 @@ class RateLimiting: """ __slots__ = 'parser', 'config_store', 'lock', 'sql_session_func', 'global_lock_func', 'cluster_id' - def __init__(self): + def __init__(self) -> 'None': self.parser = DefinitionParser() # type: DefinitionParser - self.config_store = {} # type: dict + self.config_store = {} # type: dict_[str, BaseLimiter] self.lock = RLock() self.global_lock_func = None # type: LockManager - self.sql_session_func = None # type: Callable + self.sql_session_func = None # type: callable_ self.cluster_id = None # type: int # ################################################################################################################################ - def _get_config_key(self, object_type, object_name): - # type: (unicode, unicode) -> unicode + def _get_config_key(self, object_type:'str', object_name:'str') -> 'str': return '{}:{}'.format(object_type, object_name) # ################################################################################################################################ - def _get_config_by_object(self, object_type, object_name): - # type: (unicode, unicode) -> BaseLimiter - return self.config_store.get(self._get_config_key(object_type, object_name)) + def _get_config_by_object(self, object_type:'str', object_name:'str') -> 'BaseLimiter': + config_key = self._get_config_key(object_type, object_name) + return self.config_store.get(config_key) # ################################################################################################################################ - def _create_config(self, object_dict, definition, is_exact): - # type: (dict, unicode, bool) -> BaseLimiter + def _create_config(self, object_dict:'strdict', definition:'str', is_exact:'bool') -> 'BaseLimiter': object_id = object_dict['id'] object_type = object_dict['type_'] @@ -209,17 +204,16 @@ def _create_config(self, object_dict, definition, is_exact): # ################################################################################################################################ - def create(self, object_dict, definition, is_exact): - # type: (dict, unicode, bool) + def create(self, object_dict:'strdict', definition:'str', is_exact:'bool') -> 'None': config = self._create_config(object_dict, definition, is_exact) self.config_store[config.get_config_key()] = config # ################################################################################################################################ - def check_limit(self, cid, object_type, object_name, from_, needs_warn=True): + def check_limit(self, cid:'str', object_type:'str', object_name:'str', from_:'str', needs_warn:'bool'=True) -> 'None': """ Checks if input object has already reached its allotted usage limit. """ - # type: (unicode, unicode, unicode, unicode) + # type: (str, str, str, str) with self.lock: config = self._get_config_by_object(object_type, object_name) @@ -235,7 +229,7 @@ def check_limit(self, cid, object_type, object_name, from_, needs_warn=True): # ################################################################################################################################ - def _delete_from_odb(self, object_type, object_id): + def _delete_from_odb(self, object_type:'str', object_id:'int') -> 'None': with closing(self.sql_session_func()) as session: session.execute(RateLimitStateDelete().where(and_( RateLimitStateTable.c.object_type==object_type, @@ -245,12 +239,10 @@ def _delete_from_odb(self, object_type, object_id): # ################################################################################################################################ - def _delete(self, object_type, object_name, remove_parent): + def _delete(self, object_type:'str', object_name:'str', remove_parent:'bool') -> 'None': """ Deletes configuration for input data, optionally deleting references to it from all objects that depended on it. Must be called with self.lock held. """ - # type: (unicode, unicode, bool) - config_key = self._get_config_key(object_type, object_name) limiter = self.config_store[config_key] # type: BaseLimiter del self.config_store[config_key] @@ -263,10 +255,9 @@ def _delete(self, object_type, object_name, remove_parent): # ################################################################################################################################ - def _set_new_parent(self, parent_type, old_parent_name, new_parent_type, new_parent_name): + def _set_new_parent(self, parent_type:'str', old_parent_name:'str', new_parent_type:'str', new_parent_name:'str') -> 'None': """ Sets new parent for all configuration entries matching the old one. Must be called with self.lock held. """ - # type: (unicode, unicode, unicode, unicode) for child_config in self.config_store.values(): # type: BaseLimiter object_info = child_config.object_info @@ -289,10 +280,9 @@ def _set_new_parent(self, parent_type, old_parent_name, new_parent_type, new_par # ################################################################################################################################ - def edit(self, object_type, old_object_name, object_dict, definition, is_exact): + def edit(self, object_type:'str', old_object_name:'str', object_dict:'strdict', definition:'str', is_exact:'bool') -> 'None': """ Changes, in place, an existing configuration entry to input data. """ - # type: (unicode, unicode, dict, unicode, bool) # Note the whole of this operation is under self.lock to make sure the update is atomic # from our callers' perspective. @@ -325,39 +315,35 @@ def edit(self, object_type, old_object_name, object_dict, definition, is_exact): # ################################################################################################################################ - def delete(self, object_type, object_name): + def delete(self, object_type:'str', object_name:'str') -> 'None': """ Deletes configuration for input object and clears out parent references to it. """ - # type: (unicode, unicode) with self.lock: self._delete(object_type, object_name, True) # ################################################################################################################################ - def _get_config(self, object_type, object_name): + def _get_config(self, object_type:'str', object_name:'str') -> 'None': """ Returns configuration for the input object, assumming we have it at all. """ - # type: (unicode, unicode) -> BaseLimiter config_key = self._get_config_key(object_type, object_name) return self.config_store.get(config_key) # ################################################################################################################################ - def get_config(self, object_type, object_name): - # type: (unicode, unicode) -> BaseLimiter + def get_config(self, object_type:'str', object_name:'str') -> 'BaseLimiter': with self.lock: return self._get_config(object_type, object_name) # ################################################################################################################################ - def has_config(self, object_type, object_name): - # type: (unicode, unicode) -> bool + def has_config(self, object_type:'str', object_name:'str') -> 'bool': with self.lock: return bool(self._get_config(object_type, object_name)) # ################################################################################################################################ - def cleanup(self): + def cleanup(self) -> 'None': """ Invoked periodically by the scheduler - goes through all configuration elements and cleans up all time periods that are no longer needed. """ diff --git a/code/zato-common/src/zato/common/rate_limiting/common.py b/code/zato-common/src/zato/common/rate_limiting/common.py index d6c94ffe88..8776bb5fec 100644 --- a/code/zato-common/src/zato/common/rate_limiting/common.py +++ b/code/zato-common/src/zato/common/rate_limiting/common.py @@ -1,12 +1,16 @@ # -*- coding: utf-8 -*- """ -Copyright (C) 2019, Zato Source s.r.o. https://zato.io +Copyright (C) 2023, Zato Source s.r.o. https://zato.io Licensed under LGPLv3, see LICENSE.txt for terms and conditions. """ -from __future__ import absolute_import, division, print_function, unicode_literals +# ################################################################################################################################ +# ################################################################################################################################ + +if 0: + from zato.common.typing_ import any_, strset # ################################################################################################################################ # ################################################################################################################################ @@ -34,7 +38,7 @@ class Unit: day = 'd' @staticmethod - def all_units(): + def all_units() -> 'strset': return {Const.Unit.minute, Const.Unit.hour, Const.Unit.day} # ################################################################################################################################ @@ -45,10 +49,9 @@ class ObjectInfo: """ __slots__ = 'type_', 'id', 'name' - def __init__(self): - self.type_ = None # type: str - self.id = None # type: int - self.name = None # type: str + type_:'str' + id:'int' + name:'str' # ################################################################################################################################ # ################################################################################################################################ @@ -56,16 +59,15 @@ def __init__(self): class DefinitionItem: __slots__ = 'config_line', 'from_', 'rate', 'unit', 'object_id', 'object_type', 'object_name' - def __init__(self): - self.config_line = None # type: int - self.from_ = None # type: object - self.rate = None # type: int - self.unit = None # type: str - self.object_id = None # type: int - self.object_type = None # type: str - self.object_name = None # type: str + config_line:'int' + from_:'any_' + rate:'int' + unit:'str' + object_id:'int' + object_type:'str' + object_name:'str' - def __repr__(self): + def __repr__(self) -> 'str': return '<{} at {}; line:{}, from:{}, rate:{}, unit:{} ({} {} {})>'.format( self.__class__.__name__, hex(id(self)), self.config_line, self.from_, self.rate, self.unit, self.object_id, self.object_name, self.object_type) diff --git a/code/zato-common/src/zato/common/rate_limiting/limiter.py b/code/zato-common/src/zato/common/rate_limiting/limiter.py index 96542f02ba..c6d8350c03 100644 --- a/code/zato-common/src/zato/common/rate_limiting/limiter.py +++ b/code/zato-common/src/zato/common/rate_limiting/limiter.py @@ -1,13 +1,11 @@ # -*- coding: utf-8 -*- """ -Copyright (C) 2019, Zato Source s.r.o. https://zato.io +Copyright (C) 2023, Zato Source s.r.o. https://zato.io Licensed under LGPLv3, see LICENSE.txt for terms and conditions. """ -from __future__ import absolute_import, division, print_function, unicode_literals - # stdlib from contextlib import closing from copy import deepcopy @@ -24,28 +22,22 @@ from zato.common.odb.query.rate_limiting import current_period_list, current_state as current_state_query from zato.common.rate_limiting.common import Const, AddressNotAllowed, RateLimitReached -# Python 2/3 compatibility -from zato.common.ext.future.utils import iterkeys - +# ################################################################################################################################ # ################################################################################################################################ if 0: - - # stdlib - from typing import Callable - - # Zato from zato.common.rate_limiting import Approximate as RateLimiterApproximate, RateLimiting from zato.common.rate_limiting.common import DefinitionItem, ObjectInfo + from zato.common.typing_ import any_, callable_, commondict, strcalldict, strdict, strlist # For pyflakes - Callable = Callable DefinitionItem = DefinitionItem ObjectInfo = ObjectInfo RateLimiterApproximate = RateLimiterApproximate RateLimiting = RateLimiting # ################################################################################################################################ +# ################################################################################################################################ RateLimitStateTable = RateLimitState.__table__ RateLimitStateDelete = RateLimitStateTable.delete @@ -62,7 +54,25 @@ class BaseLimiter: 'is_exact', 'from_any_object_id', 'from_any_object_type', 'from_any_object_name', 'cluster_id', 'is_active', \ 'invocation_no' - initial_state = { + api:'RateLimiting' + object_info:'ObjectInfo' + definition:'strlist' + has_from_any:'bool' + from_any_rate:'int' + from_any_unit:'str' + parent_type:'str' + parent_name:'str' + is_exact:'bool' + invocation_no:'int' + + ip_address_cache:'strdict' + by_period:'strdict' + + from_any_object_id:'int' + from_any_object_type:'str' + from_any_object_name:'str' + + initial_state:'commondict' = { 'requests': 0, 'last_cid': None, 'last_request_time_utc': None, @@ -70,30 +80,17 @@ class BaseLimiter: 'last_network': None, } - def __init__(self, cluster_id): - # type: (int) + def __init__(self, cluster_id:'int') -> 'None': self.cluster_id = cluster_id - self.is_active = None + self.is_active = False self.current_idx = 0 self.lock = RLock() - self.api = None # type: RateLimiting - self.object_info = None # type: ObjectInfo - self.definition = None # type: list - self.has_from_any = None # type: bool - self.from_any_rate = None # type: int - self.from_any_unit = None # type: str - self.ip_address_cache = {} # type: dict - self.by_period = {} # type: dict - self.parent_type = None # type: str - self.parent_name = None # type: str - self.is_exact = None # type: bool - self.invocation_no = 0 # type: int - - self.from_any_object_id = None # type: int - self.from_any_object_type = None # type: str - self.from_any_object_name = None # type: str - - self.current_period_func = { + self.ip_address_cache = {} + self.by_period = {} + self.is_exact = False + self.invocation_no = 0 + + self.current_period_func:'strcalldict' = { Const.Unit.day: self._get_current_day, Const.Unit.hour: self._get_current_hour, Const.Unit.minute: self._get_current_minute, @@ -102,12 +99,12 @@ def __init__(self, cluster_id): # ################################################################################################################################ @property - def has_parent(self): + def has_parent(self) -> 'bool': return self.parent_type and self.parent_name # ################################################################################################################################ - def cleanup(self): + def cleanup(self) -> 'None': """ Cleans up time periods that are no longer needed. """ with self.lock: @@ -144,7 +141,7 @@ def cleanup(self): # ################################################################################################################################ - def rewrite_rate_data(self, old_config): + def rewrite_rate_data(self, old_config) -> 'None': """ Writes rate limiting information from old configuration to our own. Used by RateLimiting.edit action. """ # type: (RateLimiterApproximate) @@ -155,13 +152,13 @@ def rewrite_rate_data(self, old_config): # ################################################################################################################################ - def get_config_key(self): + def get_config_key(self) -> 'str': # type: () -> str return '{}:{}'.format(self.object_info.type_, self.object_info.name) # ################################################################################################################################ - def _get_rate_config_by_from(self, orig_from, _from_any=Const.from_any): + def _get_rate_config_by_from(self, orig_from, _from_any=Const.from_any) -> 'DefinitionItem': # type: (str, str) -> DefinitionItem from_ = self.ip_address_cache.setdefault(orig_from, IPAddress(orig_from)) # type: IPAddress @@ -188,21 +185,21 @@ def _get_rate_config_by_from(self, orig_from, _from_any=Const.from_any): # ################################################################################################################################ - def _get_current_day(self, now, _prefix=Const.Unit.day, _format='%Y-%m-%d'): + def _get_current_day(self, now, _prefix=Const.Unit.day, _format='%Y-%m-%d') -> 'str': # type: (datetime, str, str) -> str return '{}.{}'.format(_prefix, now.strftime(_format)) - def _get_current_hour(self, now, _prefix=Const.Unit.hour, _format='%Y-%m-%dT%H'): + def _get_current_hour(self, now, _prefix=Const.Unit.hour, _format='%Y-%m-%dT%H') -> 'str': # type: (datetime, str, str) -> str return '{}.{}'.format(_prefix, now.strftime(_format)) - def _get_current_minute(self, now, _prefix=Const.Unit.minute, _format='%Y-%m-%dT%H:%M'): + def _get_current_minute(self, now, _prefix=Const.Unit.minute, _format='%Y-%m-%dT%H:%M') -> 'str': # type: (datetime, str, str) -> str return '{}.{}'.format(_prefix, now.strftime(_format)) # ################################################################################################################################ - def _format_last_info(self, current_state): + def _format_last_info(self, current_state) -> 'str': # type: (dict) -> str return 'last_from:`{last_from}; last_request_time_utc:`{last_request_time_utc}; last_cid:`{last_cid}`;'.format( @@ -211,7 +208,7 @@ def _format_last_info(self, current_state): # ################################################################################################################################ def _raise_rate_limit_exceeded(self, rate, unit, orig_from, network_found, current_state, cid, - def_object_id, def_object_name, def_object_type): + def_object_id, def_object_name, def_object_type) -> 'None': raise RateLimitReached('Max. rate limit of {}/{} reached; from:`{}`, network:`{}`; {} (cid:{}) (def:{} {} {})'.format( rate, unit, orig_from, network_found, self._format_last_info(current_state), cid, def_object_id, def_object_type, @@ -220,7 +217,7 @@ def _raise_rate_limit_exceeded(self, rate, unit, orig_from, network_found, curre # ################################################################################################################################ def _check_limit(self, cid, orig_from, network_found, rate, unit, def_object_id, def_object_name, def_object_type, - _rate_any=Const.rate_any, _utcnow=datetime.utcnow): + _rate_any=Const.rate_any, _utcnow=datetime.utcnow) -> 'None': # type: (str, str, str, int, str, str, object, str, str) # Increase invocation counter @@ -256,7 +253,7 @@ def _check_limit(self, cid, orig_from, network_found, rate, unit, def_object_id, # ################################################################################################################################ - def check_limit(self, cid, orig_from): + def check_limit(self, cid, orig_from) -> 'None': # type: (str, str) with self.lock: @@ -282,7 +279,7 @@ def check_limit(self, cid, orig_from): # ################################################################################################################################ - def _get_current_periods(self): + def _get_current_periods(self) -> 'None': raise NotImplementedError() _get_current_state = _set_new_state = _delete_periods = _get_current_periods @@ -292,18 +289,18 @@ def _get_current_periods(self): class Approximate(BaseLimiter): - def _get_current_periods(self): - return list(iterkeys(self.by_period)) + def _get_current_periods(self) -> 'strlist': + return list(self.by_period.keys()) # ################################################################################################################################ - def _delete_periods(self, to_delete): + def _delete_periods(self, to_delete) -> 'None': for item in to_delete: # item: str del self.by_period[item] # ################################################################################################################################ - def _get_current_state(self, current_period, network_found): + def _get_current_state(self, current_period, network_found) -> 'strdict': # type: (str, str) -> dict # Get or create a dictionary of requests information for current period @@ -314,7 +311,7 @@ def _get_current_state(self, current_period, network_found): # ################################################################################################################################ - def _set_new_state(self, current_state, cid, orig_from, network_found, now, *ignored): + def _set_new_state(self, current_state, cid, orig_from, network_found, now, *ignored:'any_') -> 'None': current_state['requests'] += 1 current_state['last_cid'] = cid current_state['last_request_time_utc'] = now.isoformat() @@ -326,14 +323,13 @@ def _set_new_state(self, current_state, cid, orig_from, network_found, now, *ign class Exact(BaseLimiter): - def __init__(self, cluster_id, sql_session_func): - # type: (int, Callable) + def __init__(self, cluster_id:'int', sql_session_func:'callable_') -> 'None': super(Exact, self).__init__(cluster_id) self.sql_session_func = sql_session_func # ################################################################################################################################ - def _fetch_current_state(self, session, current_period, network_found): + def _fetch_current_state(self, session, current_period, network_found) -> 'RateLimitState': # type: (str, str) -> RateLimitState # We have a complex Python object but for the query we just need its string representation @@ -345,7 +341,7 @@ def _fetch_current_state(self, session, current_period, network_found): # ################################################################################################################################ - def _get_current_state(self, current_period, network_found): + def _get_current_state(self, current_period, network_found) -> 'strdict': # type: (str, str) -> dict current_state = deepcopy(self.initial_state) # type: dict @@ -360,7 +356,7 @@ def _get_current_state(self, current_period, network_found): # ################################################################################################################################ - def _set_new_state(self, current_state, cid, orig_from, network_found, now, current_period): + def _set_new_state(self, current_state, cid, orig_from, network_found, now, current_period) -> 'None': # We just need a string representation of this object network_found = str(network_found) @@ -392,13 +388,13 @@ def _set_new_state(self, current_state, cid, orig_from, network_found, now, curr # ################################################################################################################################ - def _get_current_periods(self): + def _get_current_periods(self) -> 'strlist': with closing(self.sql_session_func()) as session: return [elem[0] for elem in current_period_list(session, self.cluster_id).all()] # ################################################################################################################################ - def _delete_periods(self, to_delete): + def _delete_periods(self, to_delete) -> 'None': with closing(self.sql_session_func()) as session: session.execute(RateLimitStateDelete().where( RateLimitStateTable.c.period.in_(to_delete) diff --git a/code/zato-common/src/zato/common/typing_.py b/code/zato-common/src/zato/common/typing_.py index e6b48e8e46..c84cb4cc20 100644 --- a/code/zato-common/src/zato/common/typing_.py +++ b/code/zato-common/src/zato/common/typing_.py @@ -137,6 +137,7 @@ class DateTimeWithZone(datetime): strdict = stranydict strbytes = union_[str_, bytes] strbooldict = dict_[str, bool] +strcalldict = dict_[str, callable_] strdictdict = dict_[str, anydict] strdictlist = list_[stranydict] strlistdict = dict_[str, anylist] diff --git a/code/zato-server/src/zato/server/service/internal/http_soap.py b/code/zato-server/src/zato/server/service/internal/http_soap.py index c9cac1e07e..f18f3a090a 100644 --- a/code/zato-server/src/zato/server/service/internal/http_soap.py +++ b/code/zato-server/src/zato/server/service/internal/http_soap.py @@ -14,7 +14,7 @@ from paste.util.converters import asbool # Zato -from zato.common.api import CONNECTION, DATA_FORMAT, DEFAULT_HTTP_PING_METHOD, DEFAULT_HTTP_POOL_SIZE, \ +from zato.common.api import CONNECTION, DEFAULT_HTTP_PING_METHOD, DEFAULT_HTTP_POOL_SIZE, \ HL7, HTTP_SOAP_SERIALIZATION_TYPE, MISC, PARAMS_PRIORITY, SEC_DEF_TYPE, URL_PARAMS_PRIORITY, URL_TYPE, \ ZATO_DEFAULT, ZATO_NONE, ZATO_SEC_USE_RBAC from zato.common.broker_message import CHANNEL, OUTGOING @@ -307,7 +307,7 @@ def handle(self): input.transport = input.get('transport') or URL_TYPE.PLAIN_HTTP input.cluster_id = input.get('cluster_id') or self.server.cluster_id - input.data_format = input.get('data_format') or DATA_FORMAT.JSON + input.data_format = input.get('data_format') or '' # For HL7 input.data_encoding = input.get('data_encoding') or 'utf-8' @@ -502,7 +502,7 @@ def handle(self): input.transport = input.get('transport') or URL_TYPE.PLAIN_HTTP input.cluster_id = input.get('cluster_id') or self.server.cluster_id - input.data_format = input.get('data_format') or DATA_FORMAT.JSON + input.data_format = input.get('data_format') or '' # For HL7 input.data_encoding = input.get('data_encoding') or 'utf-8'