Skip to content

Commit f153408

Browse files
bbarkerbdc34
authored andcommitted
initiating work on strict typing, need sqlalchemy-stubs
attempting to use sqlalchemy stubs fleshed out mypy.ini - verified works with vscode; updated mypy improved support for mypy-sqlalchemy questionable_model_change fixed issues except python/mypy#4049 adding some mypy workarounds for mypy #4049 and #4291
1 parent d430fbb commit f153408

File tree

1,112 files changed

+28711
-160
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,112 files changed

+28711
-160
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "sqlalchemy-stubs"]
2+
path = sqlalchemy-stubs
3+
url = https://github.com/JelleZijlstra/sqlalchemy-stubs.git

browse/controllers.py

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,26 @@
11
"""Browse controllers."""
2-
import re
2+
3+
from typing import Dict, Optional, Tuple
4+
35
from flask import request
4-
from arxiv import status
5-
from typing import Tuple, Dict, Any, Optional
6-
from browse.services.document import metadata
7-
from browse.services.document.metadata import AbsNotFoundException,\
8-
AbsVersionNotFoundException
9-
from browse.domain.identifier import IdentifierException
10-
from browse.services.database.models import get_institution
11-
from werkzeug.exceptions import InternalServerError
6+
from flask_api import status
7+
from browse.services.database import get_institution
128

13-
Response = Tuple[Dict[str, Any], int, Dict[str, Any]]
149

10+
InstitutionResp = Tuple[Dict[str, str], int]
1511

16-
def get_abs_page(arxiv_id: str) -> Response:
17-
"""Get the data that constitutes an /abs page."""
18-
response_data = {} # type: Dict[str, Any]
1912

20-
try:
21-
abs_meta = metadata.get_abs(arxiv_id)
22-
response_data['abs_meta'] = abs_meta
23-
except AbsNotFoundException as e:
24-
return {'not_found': True, 'arxiv_id': arxiv_id}, \
25-
status.HTTP_404_NOT_FOUND, {}
26-
except AbsVersionNotFoundException as e:
27-
arxiv_id_latest = re.sub(r'(v[\d]+)$', '', arxiv_id)
28-
return {'version_not_found': True,
29-
'arxiv_id': arxiv_id,
30-
'arxiv_id_latest': arxiv_id_latest},\
31-
status.HTTP_404_NOT_FOUND, {}
32-
except IdentifierException as e:
33-
print(f'Got IdentifierException {e}')
34-
return {'arxiv_id': arxiv_id}, status.HTTP_404_NOT_FOUND, {}
35-
except IOError as e:
36-
# TODO: handle differently?
37-
raise InternalServerError(
38-
"There was a problem. If this problem "
39-
"persists, please contact [email protected]."
40-
)
41-
42-
return response_data, status.HTTP_200_OK, {}
43-
44-
45-
def get_institution_from_request() -> Optional[str]:
13+
def get_institution_from_request() -> InstitutionResp:
4614
"""Get the institution name from the request context."""
4715
institution_str = None
4816
try:
49-
institution_str = get_institution(request.remote_addr)
17+
institution_opt: Optional[str] = get_institution(request.remote_addr)
18+
response: InstitutionResp = ({
19+
'institution': institution_opt
20+
}, status.HTTP_200_OK) if institution_opt is not None else ({
21+
'explanation': 'Institution not found.'
22+
}, status.HTTP_400_BAD_REQUEST)
23+
return response
5024

5125
except IOError:
5226
# TODO: log this

browse/factory.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
"""Application factory for browse service components."""
22

33
from flask import Flask
4-
from browse.services.database import models
5-
from browse import views
4+
from browse.services.database.models import dbx as db
65

76

8-
def create_web_app() -> Flask:
7+
def create_web_app(config_filename: str) -> Flask:
98
"""Initialize an instance of the browse web application."""
9+
from browse.views import blueprint
1010

11-
app = Flask('browse', static_folder='static', template_folder='templates')
12-
app.config.from_pyfile('config.py')
11+
app: Flask = Flask('browse', static_folder='static',
12+
template_folder='templates')
13+
app.config.from_pyfile(config_filename)
1314

14-
models.init_app(app)
15+
from browse.url_converter import ArXivConverter
16+
app.url_map.converters['arxiv'] = ArXivConverter
1517

16-
# from browse.url_converter import ArXivConverter
17-
# app.url_map.converters['arxiv'] = ArXivConverter
18-
app.register_blueprint(views.blueprint)
18+
db.init_app(app)
19+
20+
app.register_blueprint(blueprint)
1921

2022
return app

browse/services/database/__init__.py

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,46 @@
11
"""Import db instance and define utility functions."""
22

33
import ipaddress
4-
from browse.services.database.models import db
4+
from browse.services.database.models import dbx
55
from browse.services.database.models import MemberInstitution, \
66
MemberInstitutionIP
77
from sqlalchemy.sql import func
88
from sqlalchemy.exc import SQLAlchemyError
99
from sqlalchemy.orm.exc import NoResultFound
10+
from flask_sqlalchemy import SQLAlchemy
1011

12+
from typing import Optional
1113

12-
# def get_institution(ip: str):
13-
# """Get institution label from IP address."""
14-
# decimal_ip = int(ipaddress.ip_address(ip))
15-
# try:
16-
# stmt = (
17-
# db.session.query(
18-
# MemberInstitution.label,
19-
# func.sum(MemberInstitutionIP.exclude).label("exclusions")
20-
# ).
21-
# join(MemberInstitutionIP).
22-
# filter(
23-
# MemberInstitutionIP.start <= decimal_ip,
24-
# MemberInstitutionIP.end >= decimal_ip
25-
# ).
26-
# group_by(MemberInstitution.label).
27-
# subquery()
28-
# )
29-
#
30-
# return (
31-
# db.session.query(stmt.c.label).
32-
# filter(stmt.c.exclusions == 0).one().label
33-
# )
34-
# except NoResultFound:
35-
# return None
36-
# except SQLAlchemyError as e:
37-
# raise IOError('Database error: %s' % e) from e
14+
# Temporary fix for https://github.com/python/mypy/issues/4049 :
15+
db: SQLAlchemy = dbx
16+
17+
18+
def get_institution(ip: str) -> Optional[str]:
19+
"""Get institution label from IP address."""
20+
decimal_ip = int(ipaddress.ip_address(ip))
21+
try:
22+
stmt = (
23+
db.session.query(
24+
MemberInstitution.label,
25+
func.sum(MemberInstitutionIP.exclude).label("exclusions")
26+
).
27+
join(MemberInstitutionIP).
28+
filter(
29+
MemberInstitutionIP.start <= decimal_ip,
30+
MemberInstitutionIP.end >= decimal_ip
31+
).
32+
group_by(MemberInstitution.label).
33+
subquery()
34+
)
35+
36+
institution: str = db.session.query(stmt.c.label) \
37+
.filter(stmt.c.exclusions == 0).one().label
38+
39+
return institution
40+
except NoResultFound:
41+
return None
42+
except SQLAlchemyError as e:
43+
raise IOError('Database error: %s' % e) from e
44+
45+
46+
__all__ = ["get_institution", "db"]

browse/services/database/models.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@
44
from sqlalchemy import BigInteger, Column, DateTime, Enum, \
55
ForeignKey, Index, Integer, String, text
66
from sqlalchemy.orm import relationship
7-
from sqlalchemy.sql import func
8-
from sqlalchemy.exc import SQLAlchemyError
9-
from sqlalchemy.orm.exc import NoResultFound
10-
from typing import Any, Optional
11-
from werkzeug.local import LocalProxy
7+
from flask_sqlalchemy import SQLAlchemy, Model
8+
from typing import Any, NewType
9+
#SQLAlchemyType = NewType('SQLAlchemyType', Any)
1210

13-
db: Any = SQLAlchemy()
11+
dbx: SQLAlchemy = SQLAlchemy()
1412

1513

16-
class MemberInstitution(db.Model):
14+
class MemberInstitution(dbx.Model):
1715
"""Primary model for arXiv member insitution data."""
1816

1917
__tablename__ = 'Subscription_UniversalInstitution'
@@ -27,7 +25,7 @@ class MemberInstitution(db.Model):
2725
note = Column(String(255))
2826

2927

30-
class MemberInstitutionContact(db.Model):
28+
class MemberInstitutionContact(dbx.Model):
3129
"""Model for arXiv member institution contact information."""
3230

3331
__tablename__ = 'Subscription_UniversalInstitutionContact'
@@ -44,7 +42,7 @@ class MemberInstitutionContact(db.Model):
4442
Subscription_UniversalInstitution = relationship('MemberInstitution')
4543

4644

47-
class MemberInstitutionIP(db.Model):
45+
class MemberInstitutionIP(dbx.Model):
4846
"""Model for arXiv member insitution IP address ranges and exclusions."""
4947

5048
__tablename__ = 'Subscription_UniversalInstitutionIP'
@@ -62,7 +60,7 @@ class MemberInstitutionIP(db.Model):
6260
Subscription_UniversalInstitution = relationship('MemberInstitution')
6361

6462

65-
class SciencewisePing(db.Model):
63+
class SciencewisePing(dbx.Model):
6664
"""Model for ScienceWISE (trackback) pings."""
6765

6866
__tablename__ = 'arXiv_sciencewise_pings'
@@ -71,7 +69,7 @@ class SciencewisePing(db.Model):
7169
updated = Column(DateTime)
7270

7371

74-
class TrackbackPing(db.Model):
72+
class TrackbackPing(dbx.Model):
7573
"""Primary model for arXiv trackback data."""
7674

7775
__tablename__ = 'arXiv_trackback_pings'
@@ -99,7 +97,7 @@ class TrackbackPing(db.Model):
9997
site_id = Column(Integer)
10098

10199

102-
class TrackbackSite(db.Model):
100+
class TrackbackSite(dbx.Model):
103101
"""Model for sites that submit trackbacks to arXiv."""
104102

105103
__tablename__ = 'arXiv_trackback_sites'

browse/views.py

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,14 @@
1-
"""Provides the user intefaces for browse."""
2-
from typing import Union
1+
"""Views."""
2+
from typing import Any
33

4-
from browse.controllers import get_abs_page, get_institution_from_request
5-
from flask import Blueprint, render_template, redirect, Response, session
6-
from arxiv import status
7-
from arxiv.base import exceptions
4+
from browse.controllers import get_institution_from_request
5+
from flask import Blueprint, render_template
86

97
blueprint = Blueprint('browse', __name__, url_prefix='')
108

119

12-
@blueprint.before_request
13-
def before_request() -> None:
14-
if 'institution' not in session:
15-
institution = get_institution_from_request()
16-
session['institution'] = institution
17-
18-
19-
@blueprint.after_request
20-
def apply_response_headers(response: Response) -> Response:
21-
"""Hook for applying response headers to all responses."""
22-
"""Prevent UI redress attacks"""
23-
response.headers["Content-Security-Policy"] = "frame-ancestors 'none'"
24-
response.headers["X-Frame-Options"] = "SAMEORIGIN"
25-
return response
26-
27-
28-
# @blueprint.route('/abs/<arxiv:document_id>', methods=['GET'])
29-
@blueprint.route('/abs/', methods=['GET'], defaults={'arxiv_id': ''})
30-
@blueprint.route('/abs/<path:arxiv_id>', methods=['GET'])
31-
def abstract(arxiv_id: str) -> Union[str, Response]:
10+
@blueprint.route('/abs/<arxiv:document_id>', methods=['GET'])
11+
def abstract(document_id: str) -> Any:
3212
"""Abstract (abs) page view."""
3313
response, code, headers = get_abs_page(arxiv_id)
3414
if code == status.HTTP_200_OK:

mypy.ini

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
[mypy]
22
mypy_path = $MYPYPATH:./sqlalchemy-stubs
3+
#mypy_path = $MYPYPATH
4+
35

46
#
57
# Covered by --strict, with some turned off:
68
#
7-
#disallow_untyped_calls=True
9+
disallow_untyped_calls=True
810
disallow_untyped_defs=True
911
check_untyped_defs=True
1012
# currently an issue with sql alchemy
@@ -13,15 +15,14 @@ disallow_subclassing_any=false
1315
disallow_any_decorated=false
1416
warn_redundant_casts=True
1517
warn_return_any=True
16-
#warn_unused_ignores=True
17-
# this seems to be at least somewhat non-functioning:
18-
#warn_unused_configs=True
18+
warn_unused_ignores=True
19+
warn_unused_configs=True
1920
#may be worth reconsidering this one:
2021
no_implicit_optional=True
2122
strict_optional=True
2223

2324
#
24-
# Other:
25+
# Other:
2526
#
2627
ignore_missing_imports=True
2728

requirements/dev.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ Jinja2==2.9.6
1212
lazy-object-proxy==1.3.1
1313
MarkupSafe==1.0
1414
mccabe==0.6.1
15-
mypy==0.540
15+
mypy==0.550
1616
mysqlclient==1.3.10
1717
nose2==0.6.5
18+
pep8==1.7.1
19+
psutil==5.4.1
1820
pylint==1.7.4
1921
six==1.11.0
2022
sqlacodegen==1.1.6

sqlalchemy-stubs

Submodule sqlalchemy-stubs added at 5e89b66
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
------------------------------------------------------------------------------
2+
\\
3+
arXiv:acc-phys/9411001
4+
From: Salman Habib <[email protected]>
5+
Date: Tue, 1 Nov 1994 18:57:48 GMT (199kb)
6+
7+
Title: Symplectic Computation of Lyapunov Exponents
8+
Authors: Salman Habib and Robert D. Ryne
9+
Categories: acc-phys physics.acc-ph
10+
Comments: 12 pages, uuencoded PostScript (figures included)
11+
Report-no: LA-UR-94-3641
12+
\\
13+
A recently developed method for the calculation of Lyapunov exponents of
14+
dynamical systems is described. The method is applicable whenever the
15+
linearized dynamics is Hamiltonian. By utilizing the exponential representation
16+
of symplectic matrices, this approach avoids the renormalization and
17+
reorthogonalization procedures necessary in usual techniques. It is also easily
18+
extendible to damped systems. The method is illustrated by considering two
19+
examples of physical interest: a model system that describes the beam halo in
20+
charged particle beams and the driven van der Pol oscillator.
21+
\\
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
------------------------------------------------------------------------------
2+
\\
3+
arXiv:acc-phys/9411002
4+
From: Salman Habib <[email protected]>
5+
Date: Sat, 19 Nov 1994 21:03:56 GMT (12kb)
6+
7+
Title: Order $\hbar$ Corrections to the Classical Dynamics of a Particle with
8+
Intrinsic Spin Moving in a Constant Magnetic Field
9+
Authors: Patrick L. Nash (University of Texas at San Antonio)
10+
Categories: acc-phys physics.acc-ph
11+
\\
12+
$O(\hbar)$ effects that modify the classical orbit of a charged particle are
13+
described for the case of a classical spin-1/2 particle moving in a constant
14+
magnetic field, using a manifestly covariant formalism reported previously. It
15+
is found that the coupling between the momentum and spin gives rise to a shift
16+
in the cyclotron frequency, which is explicitly calculated. In addition the
17+
orbit is found to exhibit $O(\hbar)$ oscillations along the axis of the uniform
18+
static magnetic field whenever the gyromagnetic ratio $g$ of the particle is
19+
not 2. This oscillation is found to occur at a frequency $\propto$ $\frac{g}{2}
20+
- 1$, and is an observable source of electric dipole radiation.
21+
\\
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
------------------------------------------------------------------------------
2+
\\
3+
arXiv:acc-phys/9411003
4+
From: Peter V. Vorob'ev. <[email protected]>
5+
Date: Tue, 22 Nov 1994 12:45:16 GMT (69kb)
6+
7+
Title: Candela Photo-Injector Experimental Results
8+
Authors: C. Travier, L. Boy, J.N. Cayla, B. Leblond, P. Georges, P. Thomas
9+
Categories: acc-phys physics.acc-ph
10+
Comments: 8 pages, 6 figures, LATEX
11+
Report-no: LAL/RT/94-15
12+
\\
13+
The CANDELA photo-injector is a two cell S-band photo-injector. The copper
14+
cathode is illuminated by a 500 fs Ti:sapphire laser. This paper presents
15+
energy spectrum measurements of the dark current and intense electron emission
16+
that occurs when the laser power density is very high.
17+
\\

0 commit comments

Comments
 (0)