Run black on moto & test directories.
This commit is contained in:
parent
c820395dbf
commit
96e5b1993d
507 changed files with 52541 additions and 47814 deletions
|
|
@ -3,5 +3,5 @@ from __future__ import unicode_literals
|
|||
from .models import events_backends
|
||||
from ..core.models import base_decorator
|
||||
|
||||
events_backend = events_backends['us-east-1']
|
||||
events_backend = events_backends["us-east-1"]
|
||||
mock_events = base_decorator(events_backends)
|
||||
|
|
|
|||
|
|
@ -8,42 +8,40 @@ from moto.core import BaseBackend, BaseModel
|
|||
|
||||
|
||||
class Rule(BaseModel):
|
||||
|
||||
def _generate_arn(self, name):
|
||||
return 'arn:aws:events:{region_name}:111111111111:rule/{name}'.format(
|
||||
region_name=self.region_name,
|
||||
name=name
|
||||
return "arn:aws:events:{region_name}:111111111111:rule/{name}".format(
|
||||
region_name=self.region_name, name=name
|
||||
)
|
||||
|
||||
def __init__(self, name, region_name, **kwargs):
|
||||
self.name = name
|
||||
self.region_name = region_name
|
||||
self.arn = kwargs.get('Arn') or self._generate_arn(name)
|
||||
self.event_pattern = kwargs.get('EventPattern')
|
||||
self.schedule_exp = kwargs.get('ScheduleExpression')
|
||||
self.state = kwargs.get('State') or 'ENABLED'
|
||||
self.description = kwargs.get('Description')
|
||||
self.role_arn = kwargs.get('RoleArn')
|
||||
self.arn = kwargs.get("Arn") or self._generate_arn(name)
|
||||
self.event_pattern = kwargs.get("EventPattern")
|
||||
self.schedule_exp = kwargs.get("ScheduleExpression")
|
||||
self.state = kwargs.get("State") or "ENABLED"
|
||||
self.description = kwargs.get("Description")
|
||||
self.role_arn = kwargs.get("RoleArn")
|
||||
self.targets = []
|
||||
|
||||
def enable(self):
|
||||
self.state = 'ENABLED'
|
||||
self.state = "ENABLED"
|
||||
|
||||
def disable(self):
|
||||
self.state = 'DISABLED'
|
||||
self.state = "DISABLED"
|
||||
|
||||
# This song and dance for targets is because we need order for Limits and NextTokens, but can't use OrderedDicts
|
||||
# with Python 2.6, so tracking it with an array it is.
|
||||
def _check_target_exists(self, target_id):
|
||||
for i in range(0, len(self.targets)):
|
||||
if target_id == self.targets[i]['Id']:
|
||||
if target_id == self.targets[i]["Id"]:
|
||||
return i
|
||||
return None
|
||||
|
||||
def put_targets(self, targets):
|
||||
# Not testing for valid ARNs.
|
||||
for target in targets:
|
||||
index = self._check_target_exists(target['Id'])
|
||||
index = self._check_target_exists(target["Id"])
|
||||
if index is not None:
|
||||
self.targets[index] = target
|
||||
else:
|
||||
|
|
@ -57,8 +55,8 @@ class Rule(BaseModel):
|
|||
|
||||
|
||||
class EventsBackend(BaseBackend):
|
||||
ACCOUNT_ID = re.compile(r'^(\d{1,12}|\*)$')
|
||||
STATEMENT_ID = re.compile(r'^[a-zA-Z0-9-_]{1,64}$')
|
||||
ACCOUNT_ID = re.compile(r"^(\d{1,12}|\*)$")
|
||||
STATEMENT_ID = re.compile(r"^[a-zA-Z0-9-_]{1,64}$")
|
||||
|
||||
def __init__(self, region_name):
|
||||
self.rules = {}
|
||||
|
|
@ -78,7 +76,7 @@ class EventsBackend(BaseBackend):
|
|||
return self.rules.get(self.rules_order[i])
|
||||
|
||||
def _gen_next_token(self, index):
|
||||
token = os.urandom(128).encode('base64')
|
||||
token = os.urandom(128).encode("base64")
|
||||
self.next_tokens[token] = index
|
||||
return token
|
||||
|
||||
|
|
@ -124,24 +122,25 @@ class EventsBackend(BaseBackend):
|
|||
return_obj = {}
|
||||
|
||||
start_index, end_index, new_next_token = self._process_token_and_limits(
|
||||
len(self.rules), next_token, limit)
|
||||
len(self.rules), next_token, limit
|
||||
)
|
||||
|
||||
for i in range(start_index, end_index):
|
||||
rule = self._get_rule_by_index(i)
|
||||
for target in rule.targets:
|
||||
if target['Arn'] == target_arn:
|
||||
if target["Arn"] == target_arn:
|
||||
matching_rules.append(rule.name)
|
||||
|
||||
return_obj['RuleNames'] = matching_rules
|
||||
return_obj["RuleNames"] = matching_rules
|
||||
if new_next_token is not None:
|
||||
return_obj['NextToken'] = new_next_token
|
||||
return_obj["NextToken"] = new_next_token
|
||||
|
||||
return return_obj
|
||||
|
||||
def list_rules(self, prefix=None, next_token=None, limit=None):
|
||||
match_string = '.*'
|
||||
match_string = ".*"
|
||||
if prefix is not None:
|
||||
match_string = '^' + prefix + match_string
|
||||
match_string = "^" + prefix + match_string
|
||||
|
||||
match_regex = re.compile(match_string)
|
||||
|
||||
|
|
@ -149,16 +148,17 @@ class EventsBackend(BaseBackend):
|
|||
return_obj = {}
|
||||
|
||||
start_index, end_index, new_next_token = self._process_token_and_limits(
|
||||
len(self.rules), next_token, limit)
|
||||
len(self.rules), next_token, limit
|
||||
)
|
||||
|
||||
for i in range(start_index, end_index):
|
||||
rule = self._get_rule_by_index(i)
|
||||
if match_regex.match(rule.name):
|
||||
matching_rules.append(rule)
|
||||
|
||||
return_obj['Rules'] = matching_rules
|
||||
return_obj["Rules"] = matching_rules
|
||||
if new_next_token is not None:
|
||||
return_obj['NextToken'] = new_next_token
|
||||
return_obj["NextToken"] = new_next_token
|
||||
|
||||
return return_obj
|
||||
|
||||
|
|
@ -168,7 +168,8 @@ class EventsBackend(BaseBackend):
|
|||
rule = self.rules[rule]
|
||||
|
||||
start_index, end_index, new_next_token = self._process_token_and_limits(
|
||||
len(rule.targets), next_token, limit)
|
||||
len(rule.targets), next_token, limit
|
||||
)
|
||||
|
||||
returned_targets = []
|
||||
return_obj = {}
|
||||
|
|
@ -176,9 +177,9 @@ class EventsBackend(BaseBackend):
|
|||
for i in range(start_index, end_index):
|
||||
returned_targets.append(rule.targets[i])
|
||||
|
||||
return_obj['Targets'] = returned_targets
|
||||
return_obj["Targets"] = returned_targets
|
||||
if new_next_token is not None:
|
||||
return_obj['NextToken'] = new_next_token
|
||||
return_obj["NextToken"] = new_next_token
|
||||
|
||||
return return_obj
|
||||
|
||||
|
|
@ -201,9 +202,9 @@ class EventsBackend(BaseBackend):
|
|||
num_events = len(events)
|
||||
|
||||
if num_events < 1:
|
||||
raise JsonRESTError('ValidationError', 'Need at least 1 event')
|
||||
raise JsonRESTError("ValidationError", "Need at least 1 event")
|
||||
elif num_events > 10:
|
||||
raise JsonRESTError('ValidationError', 'Can only submit 10 events at once')
|
||||
raise JsonRESTError("ValidationError", "Can only submit 10 events at once")
|
||||
|
||||
# We dont really need to store the events yet
|
||||
return []
|
||||
|
|
@ -221,41 +222,47 @@ class EventsBackend(BaseBackend):
|
|||
raise NotImplementedError()
|
||||
|
||||
def put_permission(self, action, principal, statement_id):
|
||||
if action is None or action != 'events:PutEvents':
|
||||
raise JsonRESTError('InvalidParameterValue', 'Action must be PutEvents')
|
||||
if action is None or action != "events:PutEvents":
|
||||
raise JsonRESTError("InvalidParameterValue", "Action must be PutEvents")
|
||||
|
||||
if principal is None or self.ACCOUNT_ID.match(principal) is None:
|
||||
raise JsonRESTError('InvalidParameterValue', 'Principal must match ^(\d{1,12}|\*)$')
|
||||
raise JsonRESTError(
|
||||
"InvalidParameterValue", "Principal must match ^(\d{1,12}|\*)$"
|
||||
)
|
||||
|
||||
if statement_id is None or self.STATEMENT_ID.match(statement_id) is None:
|
||||
raise JsonRESTError('InvalidParameterValue', 'StatementId must match ^[a-zA-Z0-9-_]{1,64}$')
|
||||
raise JsonRESTError(
|
||||
"InvalidParameterValue", "StatementId must match ^[a-zA-Z0-9-_]{1,64}$"
|
||||
)
|
||||
|
||||
self.permissions[statement_id] = {'action': action, 'principal': principal}
|
||||
self.permissions[statement_id] = {"action": action, "principal": principal}
|
||||
|
||||
def remove_permission(self, statement_id):
|
||||
try:
|
||||
del self.permissions[statement_id]
|
||||
except KeyError:
|
||||
raise JsonRESTError('ResourceNotFoundException', 'StatementId not found')
|
||||
raise JsonRESTError("ResourceNotFoundException", "StatementId not found")
|
||||
|
||||
def describe_event_bus(self):
|
||||
arn = "arn:aws:events:{0}:000000000000:event-bus/default".format(self.region_name)
|
||||
arn = "arn:aws:events:{0}:000000000000:event-bus/default".format(
|
||||
self.region_name
|
||||
)
|
||||
statements = []
|
||||
for statement_id, data in self.permissions.items():
|
||||
statements.append({
|
||||
'Sid': statement_id,
|
||||
'Effect': 'Allow',
|
||||
'Principal': {'AWS': 'arn:aws:iam::{0}:root'.format(data['principal'])},
|
||||
'Action': data['action'],
|
||||
'Resource': arn
|
||||
})
|
||||
policy = {'Version': '2012-10-17', 'Statement': statements}
|
||||
statements.append(
|
||||
{
|
||||
"Sid": statement_id,
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::{0}:root".format(data["principal"])
|
||||
},
|
||||
"Action": data["action"],
|
||||
"Resource": arn,
|
||||
}
|
||||
)
|
||||
policy = {"Version": "2012-10-17", "Statement": statements}
|
||||
policy_json = json.dumps(policy)
|
||||
return {
|
||||
'Policy': policy_json,
|
||||
'Name': 'default',
|
||||
'Arn': arn
|
||||
}
|
||||
return {"Policy": policy_json, "Name": "default", "Arn": arn}
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("events")
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ from moto.events import events_backends
|
|||
|
||||
|
||||
class EventsHandler(BaseResponse):
|
||||
|
||||
@property
|
||||
def events_backend(self):
|
||||
"""
|
||||
|
|
@ -19,18 +18,18 @@ class EventsHandler(BaseResponse):
|
|||
|
||||
def _generate_rule_dict(self, rule):
|
||||
return {
|
||||
'Name': rule.name,
|
||||
'Arn': rule.arn,
|
||||
'EventPattern': rule.event_pattern,
|
||||
'State': rule.state,
|
||||
'Description': rule.description,
|
||||
'ScheduleExpression': rule.schedule_exp,
|
||||
'RoleArn': rule.role_arn
|
||||
"Name": rule.name,
|
||||
"Arn": rule.arn,
|
||||
"EventPattern": rule.event_pattern,
|
||||
"State": rule.state,
|
||||
"Description": rule.description,
|
||||
"ScheduleExpression": rule.schedule_exp,
|
||||
"RoleArn": rule.role_arn,
|
||||
}
|
||||
|
||||
@property
|
||||
def request_params(self):
|
||||
if not hasattr(self, '_json_body'):
|
||||
if not hasattr(self, "_json_body"):
|
||||
try:
|
||||
self._json_body = json.loads(self.body)
|
||||
except ValueError:
|
||||
|
|
@ -40,127 +39,134 @@ class EventsHandler(BaseResponse):
|
|||
def _get_param(self, param, if_none=None):
|
||||
return self.request_params.get(param, if_none)
|
||||
|
||||
def error(self, type_, message='', status=400):
|
||||
def error(self, type_, message="", status=400):
|
||||
headers = self.response_headers
|
||||
headers['status'] = status
|
||||
return json.dumps({'__type': type_, 'message': message}), headers,
|
||||
headers["status"] = status
|
||||
return json.dumps({"__type": type_, "message": message}), headers
|
||||
|
||||
def delete_rule(self):
|
||||
name = self._get_param('Name')
|
||||
name = self._get_param("Name")
|
||||
|
||||
if not name:
|
||||
return self.error('ValidationException', 'Parameter Name is required.')
|
||||
return self.error("ValidationException", "Parameter Name is required.")
|
||||
self.events_backend.delete_rule(name)
|
||||
|
||||
return '', self.response_headers
|
||||
return "", self.response_headers
|
||||
|
||||
def describe_rule(self):
|
||||
name = self._get_param('Name')
|
||||
name = self._get_param("Name")
|
||||
|
||||
if not name:
|
||||
return self.error('ValidationException', 'Parameter Name is required.')
|
||||
return self.error("ValidationException", "Parameter Name is required.")
|
||||
|
||||
rule = self.events_backend.describe_rule(name)
|
||||
|
||||
if not rule:
|
||||
return self.error('ResourceNotFoundException', 'Rule test does not exist.')
|
||||
return self.error("ResourceNotFoundException", "Rule test does not exist.")
|
||||
|
||||
rule_dict = self._generate_rule_dict(rule)
|
||||
return json.dumps(rule_dict), self.response_headers
|
||||
|
||||
def disable_rule(self):
|
||||
name = self._get_param('Name')
|
||||
name = self._get_param("Name")
|
||||
|
||||
if not name:
|
||||
return self.error('ValidationException', 'Parameter Name is required.')
|
||||
return self.error("ValidationException", "Parameter Name is required.")
|
||||
|
||||
if not self.events_backend.disable_rule(name):
|
||||
return self.error('ResourceNotFoundException', 'Rule ' + name + ' does not exist.')
|
||||
return self.error(
|
||||
"ResourceNotFoundException", "Rule " + name + " does not exist."
|
||||
)
|
||||
|
||||
return '', self.response_headers
|
||||
return "", self.response_headers
|
||||
|
||||
def enable_rule(self):
|
||||
name = self._get_param('Name')
|
||||
name = self._get_param("Name")
|
||||
|
||||
if not name:
|
||||
return self.error('ValidationException', 'Parameter Name is required.')
|
||||
return self.error("ValidationException", "Parameter Name is required.")
|
||||
|
||||
if not self.events_backend.enable_rule(name):
|
||||
return self.error('ResourceNotFoundException', 'Rule ' + name + ' does not exist.')
|
||||
return self.error(
|
||||
"ResourceNotFoundException", "Rule " + name + " does not exist."
|
||||
)
|
||||
|
||||
return '', self.response_headers
|
||||
return "", self.response_headers
|
||||
|
||||
def generate_presigned_url(self):
|
||||
pass
|
||||
|
||||
def list_rule_names_by_target(self):
|
||||
target_arn = self._get_param('TargetArn')
|
||||
next_token = self._get_param('NextToken')
|
||||
limit = self._get_param('Limit')
|
||||
target_arn = self._get_param("TargetArn")
|
||||
next_token = self._get_param("NextToken")
|
||||
limit = self._get_param("Limit")
|
||||
|
||||
if not target_arn:
|
||||
return self.error('ValidationException', 'Parameter TargetArn is required.')
|
||||
return self.error("ValidationException", "Parameter TargetArn is required.")
|
||||
|
||||
rule_names = self.events_backend.list_rule_names_by_target(
|
||||
target_arn, next_token, limit)
|
||||
target_arn, next_token, limit
|
||||
)
|
||||
|
||||
return json.dumps(rule_names), self.response_headers
|
||||
|
||||
def list_rules(self):
|
||||
prefix = self._get_param('NamePrefix')
|
||||
next_token = self._get_param('NextToken')
|
||||
limit = self._get_param('Limit')
|
||||
prefix = self._get_param("NamePrefix")
|
||||
next_token = self._get_param("NextToken")
|
||||
limit = self._get_param("Limit")
|
||||
|
||||
rules = self.events_backend.list_rules(prefix, next_token, limit)
|
||||
rules_obj = {'Rules': []}
|
||||
rules_obj = {"Rules": []}
|
||||
|
||||
for rule in rules['Rules']:
|
||||
rules_obj['Rules'].append(self._generate_rule_dict(rule))
|
||||
for rule in rules["Rules"]:
|
||||
rules_obj["Rules"].append(self._generate_rule_dict(rule))
|
||||
|
||||
if rules.get('NextToken'):
|
||||
rules_obj['NextToken'] = rules['NextToken']
|
||||
if rules.get("NextToken"):
|
||||
rules_obj["NextToken"] = rules["NextToken"]
|
||||
|
||||
return json.dumps(rules_obj), self.response_headers
|
||||
|
||||
def list_targets_by_rule(self):
|
||||
rule_name = self._get_param('Rule')
|
||||
next_token = self._get_param('NextToken')
|
||||
limit = self._get_param('Limit')
|
||||
rule_name = self._get_param("Rule")
|
||||
next_token = self._get_param("NextToken")
|
||||
limit = self._get_param("Limit")
|
||||
|
||||
if not rule_name:
|
||||
return self.error('ValidationException', 'Parameter Rule is required.')
|
||||
return self.error("ValidationException", "Parameter Rule is required.")
|
||||
|
||||
try:
|
||||
targets = self.events_backend.list_targets_by_rule(
|
||||
rule_name, next_token, limit)
|
||||
rule_name, next_token, limit
|
||||
)
|
||||
except KeyError:
|
||||
return self.error('ResourceNotFoundException', 'Rule ' + rule_name + ' does not exist.')
|
||||
return self.error(
|
||||
"ResourceNotFoundException", "Rule " + rule_name + " does not exist."
|
||||
)
|
||||
|
||||
return json.dumps(targets), self.response_headers
|
||||
|
||||
def put_events(self):
|
||||
events = self._get_param('Entries')
|
||||
events = self._get_param("Entries")
|
||||
|
||||
failed_entries = self.events_backend.put_events(events)
|
||||
|
||||
if failed_entries:
|
||||
return json.dumps({
|
||||
'FailedEntryCount': len(failed_entries),
|
||||
'Entries': failed_entries
|
||||
})
|
||||
return json.dumps(
|
||||
{"FailedEntryCount": len(failed_entries), "Entries": failed_entries}
|
||||
)
|
||||
|
||||
return '', self.response_headers
|
||||
return "", self.response_headers
|
||||
|
||||
def put_rule(self):
|
||||
name = self._get_param('Name')
|
||||
event_pattern = self._get_param('EventPattern')
|
||||
sched_exp = self._get_param('ScheduleExpression')
|
||||
state = self._get_param('State')
|
||||
desc = self._get_param('Description')
|
||||
role_arn = self._get_param('RoleArn')
|
||||
name = self._get_param("Name")
|
||||
event_pattern = self._get_param("EventPattern")
|
||||
sched_exp = self._get_param("ScheduleExpression")
|
||||
state = self._get_param("State")
|
||||
desc = self._get_param("Description")
|
||||
role_arn = self._get_param("RoleArn")
|
||||
|
||||
if not name:
|
||||
return self.error('ValidationException', 'Parameter Name is required.')
|
||||
return self.error("ValidationException", "Parameter Name is required.")
|
||||
|
||||
if event_pattern:
|
||||
try:
|
||||
|
|
@ -168,12 +174,20 @@ class EventsHandler(BaseResponse):
|
|||
except ValueError:
|
||||
# Not quite as informative as the real error, but it'll work
|
||||
# for now.
|
||||
return self.error('InvalidEventPatternException', 'Event pattern is not valid.')
|
||||
return self.error(
|
||||
"InvalidEventPatternException", "Event pattern is not valid."
|
||||
)
|
||||
|
||||
if sched_exp:
|
||||
if not (re.match('^cron\(.*\)', sched_exp) or
|
||||
re.match('^rate\(\d*\s(minute|minutes|hour|hours|day|days)\)', sched_exp)):
|
||||
return self.error('ValidationException', 'Parameter ScheduleExpression is not valid.')
|
||||
if not (
|
||||
re.match("^cron\(.*\)", sched_exp)
|
||||
or re.match(
|
||||
"^rate\(\d*\s(minute|minutes|hour|hours|day|days)\)", sched_exp
|
||||
)
|
||||
):
|
||||
return self.error(
|
||||
"ValidationException", "Parameter ScheduleExpression is not valid."
|
||||
)
|
||||
|
||||
rule_arn = self.events_backend.put_rule(
|
||||
name,
|
||||
|
|
@ -181,59 +195,63 @@ class EventsHandler(BaseResponse):
|
|||
EventPattern=event_pattern,
|
||||
State=state,
|
||||
Description=desc,
|
||||
RoleArn=role_arn
|
||||
RoleArn=role_arn,
|
||||
)
|
||||
|
||||
return json.dumps({'RuleArn': rule_arn}), self.response_headers
|
||||
return json.dumps({"RuleArn": rule_arn}), self.response_headers
|
||||
|
||||
def put_targets(self):
|
||||
rule_name = self._get_param('Rule')
|
||||
targets = self._get_param('Targets')
|
||||
rule_name = self._get_param("Rule")
|
||||
targets = self._get_param("Targets")
|
||||
|
||||
if not rule_name:
|
||||
return self.error('ValidationException', 'Parameter Rule is required.')
|
||||
return self.error("ValidationException", "Parameter Rule is required.")
|
||||
|
||||
if not targets:
|
||||
return self.error('ValidationException', 'Parameter Targets is required.')
|
||||
return self.error("ValidationException", "Parameter Targets is required.")
|
||||
|
||||
if not self.events_backend.put_targets(rule_name, targets):
|
||||
return self.error('ResourceNotFoundException', 'Rule ' + rule_name + ' does not exist.')
|
||||
return self.error(
|
||||
"ResourceNotFoundException", "Rule " + rule_name + " does not exist."
|
||||
)
|
||||
|
||||
return '', self.response_headers
|
||||
return "", self.response_headers
|
||||
|
||||
def remove_targets(self):
|
||||
rule_name = self._get_param('Rule')
|
||||
ids = self._get_param('Ids')
|
||||
rule_name = self._get_param("Rule")
|
||||
ids = self._get_param("Ids")
|
||||
|
||||
if not rule_name:
|
||||
return self.error('ValidationException', 'Parameter Rule is required.')
|
||||
return self.error("ValidationException", "Parameter Rule is required.")
|
||||
|
||||
if not ids:
|
||||
return self.error('ValidationException', 'Parameter Ids is required.')
|
||||
return self.error("ValidationException", "Parameter Ids is required.")
|
||||
|
||||
if not self.events_backend.remove_targets(rule_name, ids):
|
||||
return self.error('ResourceNotFoundException', 'Rule ' + rule_name + ' does not exist.')
|
||||
return self.error(
|
||||
"ResourceNotFoundException", "Rule " + rule_name + " does not exist."
|
||||
)
|
||||
|
||||
return '', self.response_headers
|
||||
return "", self.response_headers
|
||||
|
||||
def test_event_pattern(self):
|
||||
pass
|
||||
|
||||
def put_permission(self):
|
||||
action = self._get_param('Action')
|
||||
principal = self._get_param('Principal')
|
||||
statement_id = self._get_param('StatementId')
|
||||
action = self._get_param("Action")
|
||||
principal = self._get_param("Principal")
|
||||
statement_id = self._get_param("StatementId")
|
||||
|
||||
self.events_backend.put_permission(action, principal, statement_id)
|
||||
|
||||
return ''
|
||||
return ""
|
||||
|
||||
def remove_permission(self):
|
||||
statement_id = self._get_param('StatementId')
|
||||
statement_id = self._get_param("StatementId")
|
||||
|
||||
self.events_backend.remove_permission(statement_id)
|
||||
|
||||
return ''
|
||||
return ""
|
||||
|
||||
def describe_event_bus(self):
|
||||
return json.dumps(self.events_backend.describe_event_bus())
|
||||
|
|
|
|||
|
|
@ -2,10 +2,6 @@ from __future__ import unicode_literals
|
|||
|
||||
from .responses import EventsHandler
|
||||
|
||||
url_bases = [
|
||||
"https?://events.(.+).amazonaws.com"
|
||||
]
|
||||
url_bases = ["https?://events.(.+).amazonaws.com"]
|
||||
|
||||
url_paths = {
|
||||
"{0}/": EventsHandler.dispatch,
|
||||
}
|
||||
url_paths = {"{0}/": EventsHandler.dispatch}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue