Skip to content

Commit e10cbee

Browse files
authored
Merge pull request #76 from geoadmin/feat-PB-1897-resolve-cyclic-import
PB-1897: Resolve cyclic import
2 parents 9d2c476 + 0cb1697 commit e10cbee

File tree

9 files changed

+129
-133
lines changed

9 files changed

+129
-133
lines changed

.pylintrc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,7 @@ disable=missing-docstring,
6464
missing-module-docstring,
6565
useless-object-inheritance,
6666
unnecessary-lambda-assignment,
67-
too-many-positional-arguments,
68-
# there is currently a bug preventing disabling cyclic imports on a specific line
69-
# see https://github.com/pylint-dev/pylint/issues/9490
70-
cyclic-import
67+
too-many-positional-arguments
7168

7269
# Enable the message, report, category or checker with the given id(s). You can
7370
# either give multiple identifier separated by comma (,) or put this option

app/__init__.py

Lines changed: 2 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,123 +1,2 @@
1-
import gzip
2-
import logging
3-
import time
4-
5-
from flask_caching import Cache
6-
from werkzeug.exceptions import HTTPException
7-
8-
from flask import Flask
9-
from flask import g
10-
from flask import request
11-
12-
from app import settings
13-
from app.helpers.utils import make_error_msg
14-
15-
logger = logging.getLogger(__name__)
16-
route_logger = logging.getLogger('app.routes')
17-
18-
# Standard Flask application initialisation
19-
20-
app = Flask(__name__)
21-
app.config.from_object(settings)
22-
23-
cache = Cache(app)
24-
25-
26-
# NOTE it is better to have this method registered first (before validate_origin) otherwise
27-
# the route might not be logged if another method reject the request.
28-
@app.before_request
29-
def log_route():
30-
g.setdefault('request_started', time.time())
31-
route_logger.debug('%s %s', request.method, request.path)
32-
33-
34-
# Add CORS Headers to all request
35-
@app.after_request
36-
def add_cors_header(response):
37-
# Do not add CORS header to internal /checker endpoint.
38-
if request.endpoint == 'checker':
39-
return response
40-
41-
response.headers['Access-Control-Allow-Methods'] = 'GET, HEAD, OPTIONS'
42-
response.headers['Access-Control-Allow-Headers'] = '*'
43-
response.headers['Access-Control-Allow-Origin'] = "*"
44-
return response
45-
46-
47-
# Add Cache-Control Headers to all request except for checker
48-
@app.after_request
49-
def add_cache_control_header(response):
50-
# Do not add Cache-Control header to internal /checker endpoint.
51-
if request.endpoint == 'checker':
52-
return response
53-
54-
# no cache on these 5xx errors, they are supposed to be temporary
55-
if response.status_code in (502, 503, 504, 507):
56-
response.headers['Cache-Control'] = 'no-cache'
57-
# short cache duration for other 5xx errors
58-
elif response.status_code >= 500:
59-
response.headers['Cache-Control'] = 'public, max-age=10'
60-
else:
61-
response.headers['Cache-Control'] = settings.CACHE_CONTROL_HEADER
62-
return response
63-
64-
65-
@app.after_request
66-
def compress(response):
67-
accept_encoding = request.headers.get('accept-encoding', '').lower()
68-
69-
if (
70-
response.status_code < 200 or response.status_code >= 300 or response.direct_passthrough or
71-
'gzip' not in accept_encoding or 'Content-Encoding' in response.headers
72-
):
73-
return response
74-
75-
content = gzip.compress(response.get_data(), compresslevel=settings.GZIP_COMPRESSION_LEVEL)
76-
response.set_data(content)
77-
response.headers['content-length'] = len(content)
78-
response.headers['content-encoding'] = 'gzip'
79-
return response
80-
81-
82-
# NOTE it is better to have this method registered last (after add_cors_header) otherwise
83-
# the response might not be correct (e.g. headers added in another after_request hook).
84-
@app.after_request
85-
def log_response(response):
86-
log_extra = {
87-
'response': {
88-
"status_code": response.status_code,
89-
"headers": dict(response.headers.items()),
90-
},
91-
"duration": time.time() - g.get('request_started', time.time())
92-
}
93-
if route_logger.isEnabledFor(logging.DEBUG):
94-
log_extra['response']['json'] = response.json if response.is_json else response.data
95-
route_logger.info("%s %s - %s", request.method, request.path, response.status, extra=log_extra)
96-
return response
97-
98-
99-
# Register error handler to make sure that every error returns a json answer
100-
@app.errorhandler(Exception)
101-
def handle_exception(err):
102-
"""Return JSON instead of HTML for HTTP errors."""
103-
if isinstance(err, HTTPException):
104-
if err.code >= 500:
105-
logger.exception(err)
106-
else:
107-
logger.error(err)
108-
return make_error_msg(err.code, err.description)
109-
110-
logger.exception('Unexpected exception: %s', err)
111-
return make_error_msg(500, "Internal server error, please consult logs")
112-
113-
114-
@app.teardown_appcontext
115-
def close_db_connection(exception):
116-
if exception:
117-
logger.exception('Unexpected exception: %s', exception)
118-
# close db connection
119-
if hasattr(g, 'db_connection'):
120-
g.db_connection.close()
121-
122-
123-
from app import routes # isort:skip pylint: disable=wrong-import-position
1+
from app import routes
2+
from app.app import app

app/app.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import gzip
2+
import logging
3+
import time
4+
5+
from flask_caching import Cache
6+
from werkzeug.exceptions import HTTPException
7+
8+
from flask import Flask
9+
from flask import g
10+
from flask import request
11+
12+
from app import settings
13+
from app.helpers.utils import make_error_msg
14+
15+
logger = logging.getLogger(__name__)
16+
route_logger = logging.getLogger('app.routes')
17+
18+
# Standard Flask application initialisation
19+
20+
app = Flask(__name__)
21+
app.config.from_object(settings)
22+
23+
cache = Cache(app)
24+
25+
26+
# NOTE it is better to have this method registered first (before validate_origin) otherwise
27+
# the route might not be logged if another method reject the request.
28+
@app.before_request
29+
def log_route():
30+
g.setdefault('request_started', time.time())
31+
route_logger.debug('%s %s', request.method, request.path)
32+
33+
34+
# Add CORS Headers to all request
35+
@app.after_request
36+
def add_cors_header(response):
37+
# Do not add CORS header to internal /checker endpoint.
38+
if request.endpoint == 'checker':
39+
return response
40+
41+
response.headers['Access-Control-Allow-Methods'] = 'GET, HEAD, OPTIONS'
42+
response.headers['Access-Control-Allow-Headers'] = '*'
43+
response.headers['Access-Control-Allow-Origin'] = "*"
44+
return response
45+
46+
47+
# Add Cache-Control Headers to all request except for checker
48+
@app.after_request
49+
def add_cache_control_header(response):
50+
# Do not add Cache-Control header to internal /checker endpoint.
51+
if request.endpoint == 'checker':
52+
return response
53+
54+
# no cache on these 5xx errors, they are supposed to be temporary
55+
if response.status_code in (502, 503, 504, 507):
56+
response.headers['Cache-Control'] = 'no-cache'
57+
# short cache duration for other 5xx errors
58+
elif response.status_code >= 500:
59+
response.headers['Cache-Control'] = 'public, max-age=10'
60+
else:
61+
response.headers['Cache-Control'] = settings.CACHE_CONTROL_HEADER
62+
return response
63+
64+
65+
@app.after_request
66+
def compress(response):
67+
accept_encoding = request.headers.get('accept-encoding', '').lower()
68+
69+
if (
70+
response.status_code < 200 or response.status_code >= 300 or response.direct_passthrough or
71+
'gzip' not in accept_encoding or 'Content-Encoding' in response.headers
72+
):
73+
return response
74+
75+
content = gzip.compress(response.get_data(), compresslevel=settings.GZIP_COMPRESSION_LEVEL)
76+
response.set_data(content)
77+
response.headers['content-length'] = len(content)
78+
response.headers['content-encoding'] = 'gzip'
79+
return response
80+
81+
82+
# NOTE it is better to have this method registered last (after add_cors_header) otherwise
83+
# the response might not be correct (e.g. headers added in another after_request hook).
84+
@app.after_request
85+
def log_response(response):
86+
log_extra = {
87+
'response': {
88+
"status_code": response.status_code,
89+
"headers": dict(response.headers.items()),
90+
},
91+
"duration": time.time() - g.get('request_started', time.time())
92+
}
93+
if route_logger.isEnabledFor(logging.DEBUG):
94+
log_extra['response']['json'] = response.json if response.is_json else response.data
95+
route_logger.info("%s %s - %s", request.method, request.path, response.status, extra=log_extra)
96+
return response
97+
98+
99+
# Register error handler to make sure that every error returns a json answer
100+
@app.errorhandler(Exception)
101+
def handle_exception(err):
102+
"""Return JSON instead of HTML for HTTP errors."""
103+
if isinstance(err, HTTPException):
104+
if err.code >= 500:
105+
logger.exception(err)
106+
else:
107+
logger.error(err)
108+
return make_error_msg(err.code, err.description)
109+
110+
logger.exception('Unexpected exception: %s', err)
111+
return make_error_msg(500, "Internal server error, please consult logs")
112+
113+
114+
@app.teardown_appcontext
115+
def close_db_connection(exception):
116+
if exception:
117+
logger.exception('Unexpected exception: %s', exception)
118+
# close db connection
119+
if hasattr(g, 'db_connection'):
120+
g.db_connection.close()

app/helpers/db.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
from flask import g
66

7-
from app import cache
87
from app import settings
8+
from app.app import cache
99

1010
logger = logging.getLogger(__name__)
1111

app/helpers/helpers_search.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from shapely.wkt import dumps as shape_dumps
1515
from shapely.wkt import loads as shape_loads
1616

17-
from app import cache
17+
from app.app import cache
1818
from app.lib import sphinxapi
1919

2020
logger = logging.getLogger(__name__)

app/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from flask import make_response
66
from flask import request
77

8-
from app import app
8+
from app.app import app
99
from app.lib import sphinxapi
1010
from app.search import Search
1111
from app.settings import SEARCH_SPHINX_HOST

service_launcher.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'''Service launcher to use Flask without wsgi.py
22
'''
3-
from app import app # pylint: disable=unused-import
3+
from app.app import app # pylint: disable=unused-import
44
from app.helpers.utils import init_logging
55

66
# Initialize Logging using JSON format for all loggers and using the Stream Handler.

tests/unit_tests/base_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from gatilegrid import getTileGrid
44

5-
from app import app
5+
from app.app import app
66
from app.helpers.helpers_search import parse_box2d
77
from app.helpers.validation_search import SUPPORTED_OUTPUT_SRS
88
from app.settings import CACHE_CONTROL_HEADER

wsgi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from gunicorn.app.base import BaseApplication
44

5-
from app import app as application
5+
from app.app import app as application
66
from app.helpers.utils import get_logging_cfg
77
from app.settings import FORWARDED_PROTO_HEADER_NAME
88
from app.settings import FORWARED_ALLOW_IPS

0 commit comments

Comments
 (0)