Diff
Modified: trunk/Tools/ChangeLog (269113 => 269114)
--- trunk/Tools/ChangeLog 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/ChangeLog 2020-10-28 19:08:28 UTC (rev 269114)
@@ -1,3 +1,27 @@
+2020-10-28 Jonathan Bedard <[email protected]>
+
+ [webkitflaskpy] Create shared library for WebKit's flask tooling
+ https://bugs.webkit.org/show_bug.cgi?id=218257
+ <rdar://problem/70736269>
+
+ Rubber-stamped by Aakash Jain.
+
+ * Scripts/libraries/resultsdbpy/resultsdbpy/__init__.py:
+ (_maybe_add_webkit_python_library_paths): Add webkitcorepy and webkitflaskpy.
+ (_maybe_add_webkitcorepy_path): Renamed _maybe_add_webkit_python_library_paths.
+ * Scripts/libraries/resultsdbpy/resultsdbpy/flask_support/util.py: Moved to webkitflaskpy/util.py.
+ * Scripts/libraries/resultsdbpy/resultsdbpy/flask_support/util_unittest.py: Moved to webkitflaskpy/util_unittest.py.
+ * Scripts/libraries/webkitflaskpy: Added.
+ * Scripts/libraries/webkitflaskpy/MANIFEST.in: Added.
+ * Scripts/libraries/webkitflaskpy/README.md: Added.
+ * Scripts/libraries/webkitflaskpy/setup.py: Added.
+ * Scripts/libraries/webkitflaskpy/webkitflaskpy: Added.
+ * Scripts/libraries/webkitflaskpy/webkitflaskpy/__init__.py: Added.
+ * Scripts/libraries/webkitflaskpy/webkitflaskpy/util.py: Moved from resultsdpy/flask_support/util.py.
+ * Scripts/libraries/webkitflaskpy/webkitflaskpy/util_unittest.py: Moved from resultsdpy/flask_support/util_unittest.py.
+ * Scripts/webkitpy/test/main.py:
+ (main): Add
+
2020-10-28 Sam Weinig <[email protected]>
Reduce Preference Override Methods: TabsToLinks/SpatialNavigation
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/__init__.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/__init__.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/__init__.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -24,15 +24,16 @@
import sys
-def _maybe_add_webkitcorepy_path():
- # Hopefully we're beside webkitcorepy, otherwise webkitcorepy will need to be installed.
+def _maybe_add_webkit_python_library_paths():
+ # Hopefully we're beside webkit*py libraries, otherwise webkit*py will need to be installed.
libraries_path = os.path.dirname(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))
- webkitcorepy_path = os.path.join(libraries_path, 'webkitcorepy')
- if os.path.isdir(webkitcorepy_path) and os.path.isdir(os.path.join(webkitcorepy_path, 'webkitcorepy')) and webkitcorepy_path not in sys.path:
- sys.path.insert(0, webkitcorepy_path)
+ for library in ['webkitcorepy', 'webkitflaskpy']:
+ library_path = os.path.join(libraries_path, library)
+ if os.path.isdir(library_path) and os.path.isdir(os.path.join(library_path, library)) and library_path not in sys.path:
+ sys.path.insert(0, library_path)
-_maybe_add_webkitcorepy_path()
+_maybe_add_webkit_python_library_paths()
try:
from webkitcorepy.version import Version
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/archive_controller.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/archive_controller.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/archive_controller.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -26,12 +26,11 @@
import time
from flask import abort, jsonify, request, send_file
-from resultsdbpy.controller.commit import Commit
from resultsdbpy.controller.commit_controller import uuid_range_for_query, HasCommitContext
from resultsdbpy.controller.configuration import Configuration
from resultsdbpy.controller.configuration_controller import configuration_for_query
from resultsdbpy.controller.suite_controller import time_range_for_query
-from resultsdbpy.flask_support.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
+from webkitflaskpy.util import AssertRequest, query_as_kwargs, boolean_query
class ArchiveController(HasCommitContext):
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/ci_controller.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/ci_controller.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/ci_controller.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -25,7 +25,7 @@
from resultsdbpy.controller.configuration import Configuration
from resultsdbpy.controller.configuration_controller import configuration_for_query
from resultsdbpy.controller.suite_controller import time_range_for_query
-from resultsdbpy.flask_support.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
+from webkitflaskpy.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
class CIController(HasCommitContext):
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/commit.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/commit.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/commit.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -25,7 +25,7 @@
import re
from datetime import datetime
-from resultsdbpy.flask_support.util import FlaskJSONEncoder
+from webkitflaskpy.util import FlaskJSONEncoder
class Commit(object):
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/commit_controller.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/commit_controller.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/commit_controller.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -24,9 +24,9 @@
from collections import defaultdict
from flask import abort, jsonify, request
-from resultsdbpy.flask_support.util import AssertRequest, query_as_kwargs, limit_for_query
from resultsdbpy.model.repository import SCMException
from resultsdbpy.controller.commit import Commit
+from webkitflaskpy.util import AssertRequest, query_as_kwargs, limit_for_query
def _find_comparison(commit_context, repository_id, branch, id, uuid, timestamp, priority=min):
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/configuration.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/configuration.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/configuration.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -22,7 +22,7 @@
import json
-from resultsdbpy.flask_support.util import FlaskJSONEncoder
+from webkitflaskpy.util import FlaskJSONEncoder
class Configuration(object):
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/configuration_controller.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/configuration_controller.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/configuration_controller.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -20,8 +20,8 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-from resultsdbpy.flask_support.util import boolean_query
from resultsdbpy.controller.configuration import Configuration
+from webkitflaskpy.util import boolean_query
def configuration_for_query():
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/failure_controller.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/failure_controller.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/failure_controller.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -25,7 +25,7 @@
from resultsdbpy.controller.configuration import Configuration
from resultsdbpy.controller.configuration_controller import configuration_for_query
from resultsdbpy.controller.suite_controller import time_range_for_query
-from resultsdbpy.flask_support.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
+from webkitflaskpy.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
class FailureController(HasCommitContext):
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/suite_controller.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/suite_controller.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/suite_controller.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -24,7 +24,7 @@
from resultsdbpy.controller.commit_controller import uuid_range_for_query, HasCommitContext
from resultsdbpy.controller.configuration import Configuration
from resultsdbpy.controller.configuration_controller import configuration_for_query
-from resultsdbpy.flask_support.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
+from webkitflaskpy.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
def time_range_for_query():
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/test_controller.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/test_controller.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/test_controller.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -25,7 +25,7 @@
from resultsdbpy.controller.configuration import Configuration
from resultsdbpy.controller.configuration_controller import configuration_for_query
from resultsdbpy.controller.suite_controller import time_range_for_query
-from resultsdbpy.flask_support.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
+from webkitflaskpy.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
class TestController(HasCommitContext):
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/controller/upload_controller.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -25,11 +25,11 @@
from collections import defaultdict
from flask import abort, jsonify, request
-from resultsdbpy.flask_support.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
from resultsdbpy.controller.commit import Commit
from resultsdbpy.controller.commit_controller import uuid_range_for_query, HasCommitContext
from resultsdbpy.controller.configuration import Configuration
from resultsdbpy.controller.configuration_controller import configuration_for_query
+from webkitflaskpy.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
class UploadController(HasCommitContext):
Deleted: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/flask_support/util.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/flask_support/util.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/flask_support/util.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -1,131 +0,0 @@
-# Copyright (C) 2019 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS `"AS IS" AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import json
-from flask import abort, request
-
-
-class FlaskJSONEncoder(json.JSONEncoder):
- # Flask's jsonify only accepts a dictionary and does not accept a JSON encoder. When overriding the default JSON
- # encoder, encoder.default(...) will return a dictionary to be serialized. However, the default encoder will raise
- # an exception if default(...) is called on primative JSON types. Implement a version of the default encoder which
- # passes primative JSON types back to the caller.
- def default(self, obj):
- if isinstance(obj, dict):
- return {key: self.default(value) for key, value in obj.items()}
- if isinstance(obj, list):
- return [self.default(value) for value in obj]
- return obj
-
-
-class AssertRequest(object):
- @classmethod
- def is_type(cls, supported_requests=None):
- if supported_requests is None:
- supported_requests = ['GET']
- if not supported_requests:
- abort(500, description='Endpoint does not support any requests')
- if request.method not in supported_requests:
- abort(405, description='Endpoint only supports {} requests'.format(
- supported_requests[0] if len(supported_requests) == 1 else ', '.join(supported_requests[:-1]) + ' and ' + supported_requests[-1],
- ))
-
- @classmethod
- def no_query(cls):
- if request.query_string:
- abort(400, description='Queries not supported on this endpoint')
-
- @classmethod
- def query_kwargs_empty(cls, **kwargs):
- for key, value in kwargs.items():
- if value:
- abort(400, description=f"'{key}' not supported in queries by this endpoint")
-
-
-def query_as_kwargs():
- def decorator(method):
- def real_method(val, method=method, **kwargs):
- for key, value in request.args.to_dict(flat=False).items():
- if key in kwargs:
- abort(400, description=f'{key} is not a valid query parameter on this endpoint')
- kwargs[key] = tuple(value)
- return method(val, **kwargs)
-
- real_method.__name__ = method.__name__
- return real_method
- return decorator
-
-
-def query_as_string():
- query = '?'
- for key, values in request.args.to_dict(flat=False).items():
- for value in values:
- query += f'{key}={value}&'
- return query[:-1]
-
-
-def boolean_query(*args):
-
- def func(string):
- if string.lower() in ['true', 'yes']:
- return True
- try:
- return bool(int(string))
- except ValueError:
- return False
-
- return [func(arg) for arg in args]
-
-
-def limit_for_query(default_limit=100):
- def decorator(method):
- def real_method(self=None, method=method, limit=None, **kwargs):
- limit_to_use = default_limit
- if limit:
- try:
- limit_to_use = int(limit[-1])
- if limit_to_use <= 0:
- raise ValueError()
- except ValueError:
- abort(400, description='Limit must be a positive integer')
- if self:
- return method(self=self, limit=limit_to_use, **kwargs)
- return method(limit=limit_to_use, **kwargs)
-
- real_method.__name__ = method.__name__
- return real_method
- return decorator
-
-
-def cache_for(hours=12):
- def decorator(method):
- def real_method(self=None, method=method, **kwargs):
- if self:
- response = method(self=self, **kwargs)
- else:
- response = method(**kwargs)
- response.headers.add('Cache-Control', f'public,max-age={hours * 60 * 60}')
- return response
-
- real_method.__name__ = method.__name__
- return real_method
- return decorator
Deleted: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/flask_support/util_unittest.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/flask_support/util_unittest.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/flask_support/util_unittest.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -1,50 +0,0 @@
-# Copyright (C) 2019 Apple Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import unittest
-
-from werkzeug.exceptions import BadRequest
-from resultsdbpy.flask_support.util import boolean_query, limit_for_query
-
-
-class UtilTest(unittest.TestCase):
-
- def test_boolean_query(self):
- self.assertTrue(all(boolean_query('True', 'true')))
- self.assertTrue(all(boolean_query('Yes', 'yes')))
- self.assertTrue(all(boolean_query('1', '100')))
-
- self.assertFalse(any(boolean_query('False', 'false')))
- self.assertFalse(any(boolean_query('No', 'no')))
- self.assertFalse(any(boolean_query('0', 'any string')))
-
- def test_limit_decorator(self):
- @limit_for_query()
- def func(limit=None):
- return limit
-
- self.assertEqual(func(), 100)
- self.assertEqual(func(limit=['10']), 10)
- self.assertEqual(func(limit=['10', '1']), 1)
- self.assertRaises(BadRequest, func, limit=['string'])
- self.assertRaises(BadRequest, func, limit=['0'])
- self.assertRaises(BadRequest, func, limit=['-1'])
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/archive_view.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/archive_view.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/archive_view.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -20,14 +20,12 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-import json
-
from flask import abort, jsonify, request, Response
from resultsdbpy.controller.commit_controller import uuid_range_for_query, HasCommitContext
from resultsdbpy.controller.configuration_controller import configuration_for_query
from resultsdbpy.controller.suite_controller import time_range_for_query
-from resultsdbpy.flask_support.util import AssertRequest, boolean_query, cache_for, limit_for_query, query_as_kwargs, query_as_string
from resultsdbpy.view.site_menu import SiteMenu
+from webkitflaskpy.util import AssertRequest, boolean_query, cache_for, limit_for_query, query_as_kwargs, query_as_string
class ArchiveView(HasCommitContext):
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/ci_view.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/ci_view.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/ci_view.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -21,9 +21,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from flask import abort, redirect, request
-from resultsdbpy.controller.commit import Commit
-from resultsdbpy.flask_support.util import AssertRequest, query_as_kwargs
-from resultsdbpy.view.site_menu import SiteMenu
+from webkitflaskpy.util import query_as_kwargs
class CIView(object):
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/commit_view.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/commit_view.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/commit_view.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -22,8 +22,8 @@
from flask import abort, redirect, request
from resultsdbpy.controller.commit import Commit
-from resultsdbpy.flask_support.util import AssertRequest, query_as_kwargs
from resultsdbpy.view.site_menu import SiteMenu
+from webkitflaskpy.util import AssertRequest, query_as_kwargs
class CommitView(object):
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/suite_view.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/suite_view.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/suite_view.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -26,8 +26,8 @@
from resultsdbpy.controller.commit_controller import uuid_range_for_query, HasCommitContext
from resultsdbpy.controller.configuration_controller import configuration_for_query
from resultsdbpy.controller.suite_controller import time_range_for_query
-from resultsdbpy.flask_support.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
from resultsdbpy.view.site_menu import SiteMenu
+from webkitflaskpy.util import AssertRequest, query_as_kwargs, limit_for_query, boolean_query
class SuiteView(HasCommitContext):
Modified: trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/view_routes.py (269113 => 269114)
--- trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/view_routes.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/view/view_routes.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -26,7 +26,6 @@
from flask import abort, jsonify, send_from_directory, redirect, Response
from jinja2 import Environment, PackageLoader, select_autoescape
-from resultsdbpy.flask_support.util import AssertRequest, cache_for
from resultsdbpy.flask_support.authed_blueprint import AuthedBlueprint
from resultsdbpy.view.archive_view import ArchiveView
from resultsdbpy.view.ci_view import CIView
@@ -34,6 +33,7 @@
from resultsdbpy.view.site_menu import SiteMenu
from resultsdbpy.view.suite_view import SuiteView
from werkzeug.exceptions import HTTPException, InternalServerError
+from webkitflaskpy.util import AssertRequest, cache_for
class ViewRoutes(AuthedBlueprint):
Added: trunk/Tools/Scripts/libraries/webkitflaskpy/MANIFEST.in (0 => 269114)
--- trunk/Tools/Scripts/libraries/webkitflaskpy/MANIFEST.in (rev 0)
+++ trunk/Tools/Scripts/libraries/webkitflaskpy/MANIFEST.in 2020-10-28 19:08:28 UTC (rev 269114)
@@ -0,0 +1 @@
+include README.md
Added: trunk/Tools/Scripts/libraries/webkitflaskpy/README.md (0 => 269114)
--- trunk/Tools/Scripts/libraries/webkitflaskpy/README.md (rev 0)
+++ trunk/Tools/Scripts/libraries/webkitflaskpy/README.md 2020-10-28 19:08:28 UTC (rev 269114)
@@ -0,0 +1,3 @@
+# webkitflaskpy
+
+Python package used by some of WebKit's web services to share CSS and _javascript_.
Copied: trunk/Tools/Scripts/libraries/webkitflaskpy/setup.py (from rev 269111, trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/flask_support/util_unittest.py) (0 => 269114)
--- trunk/Tools/Scripts/libraries/webkitflaskpy/setup.py (rev 0)
+++ trunk/Tools/Scripts/libraries/webkitflaskpy/setup.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -0,0 +1,64 @@
+# Copyright (C) 2020 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitflaskpy import version
+from setuptools import setup
+
+
+def readme():
+ with open('README.md') as f:
+ return f.read()
+
+
+setup(
+ name='webkitflaskpy',
+ version=str(version),
+ description='Library for visualizing, processing and storing test results.',
+ long_description=readme(),
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Framework :: Flask',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: BSD License',
+ 'Operating System :: MacOS',
+ 'Natural Language :: English',
+ 'Programming Language :: Python :: 3 :: Only',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ 'Topic :: Software Development :: Testing',
+ ],
+ keywords='web _javascript_ webkit',
+ url='',
+ author='Jonathan Bedard',
+ author_email='[email protected]',
+ license='Modified BSD',
+ packages=[
+ 'webkitflaskpy',
+ ],
+ install_requires=[
+ 'Flask',
+ 'Flask-Cors',
+ 'gunicorn',
+ 'webkitcorepy',
+ ],
+ include_package_data=True,
+ zip_safe=False,
+)
Copied: trunk/Tools/Scripts/libraries/webkitflaskpy/webkitflaskpy/__init__.py (from rev 269111, trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/__init__.py) (0 => 269114)
--- trunk/Tools/Scripts/libraries/webkitflaskpy/webkitflaskpy/__init__.py (rev 0)
+++ trunk/Tools/Scripts/libraries/webkitflaskpy/webkitflaskpy/__init__.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -0,0 +1,55 @@
+# Copyright (C) 2020 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+
+
+def _maybe_add_webkitcorepy_path():
+ # Hopefully we're beside webkitcorepy, otherwise webkitcorepy will need to be installed.
+ libraries_path = os.path.dirname(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))
+ webkitcorepy_path = os.path.join(libraries_path, 'webkitcorepy')
+ if os.path.isdir(webkitcorepy_path) and os.path.isdir(os.path.join(webkitcorepy_path, 'webkitcorepy')) and webkitcorepy_path not in sys.path:
+ sys.path.insert(0, webkitcorepy_path)
+
+
+_maybe_add_webkitcorepy_path()
+
+try:
+ from webkitcorepy import AutoInstall, Package, Version
+except ImportError:
+ raise ImportError(
+ "'webkitcorepy' could not be found on your Python path.\n" +
+ "You are not running from a WebKit checkout.\n" +
+ "Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"
+ )
+
+version = Version(0, 1, 0)
+
+AutoInstall.register(Package('click'), Version(7, 1, 2))
+AutoInstall.register(Package('flask'), Version(1, 1, 2))
+AutoInstall.register(Package('itsdangerous'), Version(2, 0, 0))
+AutoInstall.register(Package('jinja2'), Version(3, 0, 0))
+AutoInstall.register(Package('markupsafe'), Version(2, 0, 0))
+AutoInstall.register(Package('werkzeug'), Version(1, 0, 1))
+
+name = 'webkitflaskpy'
Copied: trunk/Tools/Scripts/libraries/webkitflaskpy/webkitflaskpy/util.py (from rev 269111, trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/flask_support/util.py) (0 => 269114)
--- trunk/Tools/Scripts/libraries/webkitflaskpy/webkitflaskpy/util.py (rev 0)
+++ trunk/Tools/Scripts/libraries/webkitflaskpy/webkitflaskpy/util.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -0,0 +1,131 @@
+# Copyright (C) 2019 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS `"AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import json
+from flask import abort, request
+
+
+class FlaskJSONEncoder(json.JSONEncoder):
+ # Flask's jsonify only accepts a dictionary and does not accept a JSON encoder. When overriding the default JSON
+ # encoder, encoder.default(...) will return a dictionary to be serialized. However, the default encoder will raise
+ # an exception if default(...) is called on primative JSON types. Implement a version of the default encoder which
+ # passes primative JSON types back to the caller.
+ def default(self, obj):
+ if isinstance(obj, dict):
+ return {key: self.default(value) for key, value in obj.items()}
+ if isinstance(obj, list):
+ return [self.default(value) for value in obj]
+ return obj
+
+
+class AssertRequest(object):
+ @classmethod
+ def is_type(cls, supported_requests=None):
+ if supported_requests is None:
+ supported_requests = ['GET']
+ if not supported_requests:
+ abort(500, description='Endpoint does not support any requests')
+ if request.method not in supported_requests:
+ abort(405, description='Endpoint only supports {} requests'.format(
+ supported_requests[0] if len(supported_requests) == 1 else ', '.join(supported_requests[:-1]) + ' and ' + supported_requests[-1],
+ ))
+
+ @classmethod
+ def no_query(cls):
+ if request.query_string:
+ abort(400, description='Queries not supported on this endpoint')
+
+ @classmethod
+ def query_kwargs_empty(cls, **kwargs):
+ for key, value in kwargs.items():
+ if value:
+ abort(400, description="'{}' not supported in queries by this endpoint".format(key))
+
+
+def query_as_kwargs():
+ def decorator(method):
+ def real_method(val, method=method, **kwargs):
+ for key, value in request.args.to_dict(flat=False).items():
+ if key in kwargs:
+ abort(400, description='{} is not a valid query parameter on this endpoint'.format(key))
+ kwargs[key] = tuple(value)
+ return method(val, **kwargs)
+
+ real_method.__name__ = method.__name__
+ return real_method
+ return decorator
+
+
+def query_as_string():
+ query = '?'
+ for key, values in request.args.to_dict(flat=False).items():
+ for value in values:
+ query += '{}={}&'.format(key, value)
+ return query[:-1]
+
+
+def boolean_query(*args):
+
+ def func(string):
+ if string.lower() in ['true', 'yes']:
+ return True
+ try:
+ return bool(int(string))
+ except ValueError:
+ return False
+
+ return [func(arg) for arg in args]
+
+
+def limit_for_query(default_limit=100):
+ def decorator(method):
+ def real_method(self=None, method=method, limit=None, **kwargs):
+ limit_to_use = default_limit
+ if limit:
+ try:
+ limit_to_use = int(limit[-1])
+ if limit_to_use <= 0:
+ raise ValueError()
+ except ValueError:
+ abort(400, description='Limit must be a positive integer')
+ if self:
+ return method(self=self, limit=limit_to_use, **kwargs)
+ return method(limit=limit_to_use, **kwargs)
+
+ real_method.__name__ = method.__name__
+ return real_method
+ return decorator
+
+
+def cache_for(hours=12):
+ def decorator(method):
+ def real_method(self=None, method=method, **kwargs):
+ if self:
+ response = method(self=self, **kwargs)
+ else:
+ response = method(**kwargs)
+ response.headers.add('Cache-Control', 'public,max-age={}'.format(hours * 60 * 60))
+ return response
+
+ real_method.__name__ = method.__name__
+ return real_method
+ return decorator
Copied: trunk/Tools/Scripts/libraries/webkitflaskpy/webkitflaskpy/util_unittest.py (from rev 269111, trunk/Tools/Scripts/libraries/resultsdbpy/resultsdbpy/flask_support/util_unittest.py) (0 => 269114)
--- trunk/Tools/Scripts/libraries/webkitflaskpy/webkitflaskpy/util_unittest.py (rev 0)
+++ trunk/Tools/Scripts/libraries/webkitflaskpy/webkitflaskpy/util_unittest.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -0,0 +1,50 @@
+# Copyright (C) 2019 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest
+
+from werkzeug.exceptions import BadRequest
+from webkitflaskpy.util import boolean_query, limit_for_query
+
+
+class UtilTest(unittest.TestCase):
+
+ def test_boolean_query(self):
+ self.assertTrue(all(boolean_query('True', 'true')))
+ self.assertTrue(all(boolean_query('Yes', 'yes')))
+ self.assertTrue(all(boolean_query('1', '100')))
+
+ self.assertFalse(any(boolean_query('False', 'false')))
+ self.assertFalse(any(boolean_query('No', 'no')))
+ self.assertFalse(any(boolean_query('0', 'any string')))
+
+ def test_limit_decorator(self):
+ @limit_for_query()
+ def func(limit=None):
+ return limit
+
+ self.assertEqual(func(), 100)
+ self.assertEqual(func(limit=['10']), 10)
+ self.assertEqual(func(limit=['10', '1']), 1)
+ self.assertRaises(BadRequest, func, limit=['string'])
+ self.assertRaises(BadRequest, func, limit=['0'])
+ self.assertRaises(BadRequest, func, limit=['-1'])
Modified: trunk/Tools/Scripts/webkitpy/test/main.py (269113 => 269114)
--- trunk/Tools/Scripts/webkitpy/test/main.py 2020-10-28 18:59:31 UTC (rev 269113)
+++ trunk/Tools/Scripts/webkitpy/test/main.py 2020-10-28 19:08:28 UTC (rev 269114)
@@ -64,6 +64,7 @@
tester.add_tree(os.path.join(_webkit_root, 'Tools', 'Scripts'), 'webkitpy')
tester.add_tree(os.path.join(_webkit_root, 'Tools', 'Scripts', 'libraries', 'webkitcorepy'), 'webkitcorepy')
tester.add_tree(os.path.join(_webkit_root, 'Tools', 'Scripts', 'libraries', 'webkitscmpy'), 'webkitscmpy')
+ tester.add_tree(os.path.join(_webkit_root, 'Tools', 'Scripts', 'libraries', 'webkitflaskpy'), 'webkitflaskpy')
# There is no WebKit2 on Windows, so we don't need to run WebKit2 unittests on it.
if not (sys.platform.startswith('win') or sys.platform == 'cygwin'):