Skip to content

Commit ccab7e6

Browse files
authored
Merge branch 'g2cnew' into g2cnew
2 parents 127acf1 + 6a0364d commit ccab7e6

9 files changed

Lines changed: 47 additions & 127 deletions

File tree

lmfdb/app.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,6 @@ def WhiteListedRoutes():
788788
'alive',
789789
'api',
790790
'bigpicture',
791-
'callback_ajax',
792791
'citation',
793792
'contact',
794793
'editorial-board',

lmfdb/elliptic_curves/isog_class.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,9 @@ def perm(i): return next(c for c in self.curves if c['Cnumber'] == i+1)['lmfdb_n
175175
if self.cm:
176176
# set CM field for Properties box.
177177
D = integer_squarefree_part(ZZ(self.cm))
178-
coeffs = [(1-D)//4,-1,1] if D % 4 == 1 else [-D,0,1]
178+
# int() everything so that the query list is not a mix of Sage Integers
179+
# and Python ints, which psycopg cannot adapt
180+
coeffs = [int((1-D)//4),-1,1] if D % 4 == 1 else [int(-D),0,1]
179181
lab = db.nf_fields.lucky({'coeffs': coeffs}, projection='label')
180182
self.CMfield = field_pretty(lab)
181183
else:

lmfdb/elliptic_curves/test_ell_curves.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ def test_isogeny_class(self):
126126
L = self.tc.get('/EllipticCurve/Q/11/a/')
127127
assert '[0, -1, 1, 0, 0]' in L.get_data(as_text=True)
128128

129+
def test_cm_isogeny_class(self):
130+
# The CM field shown in the Properties box is looked up in nf_fields
131+
# by coefficient list; this 500ed when that list mixed Sage Integers
132+
# with Python ints (see #7129). 27.a and 32.a exercise the two
133+
# branches computing the coefficient list.
134+
L = self.tc.get('/EllipticCurve/Q/27/a/')
135+
assert r'\Q(\sqrt{-3})' in L.get_data(as_text=True)
136+
L = self.tc.get('/EllipticCurve/Q/32/a/')
137+
assert r'\Q(\sqrt{-1})' in L.get_data(as_text=True)
138+
129139
def test_dl_qexp(self):
130140
L = self.tc.get('/EllipticCurve/Q/download_qexp/66.c3/100')
131141
assert '0,1,1,1,1,-4,1,-2,1,1,-4,1,1,4,-2,-4,1,-2,1,0,-4,-2,1,-6,1,11,4,1,-2,10,-4,-8,1,1,-2,8,1,-2,0,4,-4,2,-2,4,1,-4,-6,-2,1,-3,11,-2,4,4,1,-4,-2,0,10,0,-4,-8,-8,-2,1,-16,1,-12,-2,-6,8,2,1,-6,-2,11,0,-2,4,10,-4,1,2,4,-2,8,4,10,1,10,-4,-8,-6,-8,-2,0,1,-2,-3,1,11' in L.get_data(as_text=True)

lmfdb/genus2_curves/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ def render_curve_webpage(label):
303303
try:
304304
g2c = WebG2C.by_label(label)
305305
except (KeyError, ValueError) as err:
306+
print("intentially raising error for debugging")
307+
raise err
306308
return abort(404, err.args)
307309
return render_template(
308310
"g2c_curve.html",

lmfdb/groups/abstract/main.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,12 @@ def index():
796796
if search_type in legacy_searches:
797797
endpoint, new_search_type = legacy_searches[search_type]
798798
args = request.args.to_dict(flat=False)
799-
args.pop("search_type", None)
799+
# Drop both mode parameters: the destination route encodes the
800+
# object type, and SearchWrapper falls back to hst when there is
801+
# no explicit search_type, so a stale hidden hst would otherwise
802+
# override the mode we just resolved.
803+
for key in ("search_type", "hst"):
804+
args.pop(key, None)
800805
if new_search_type is not None:
801806
args["search_type"] = [new_search_type]
802807
return redirect(url_for(endpoint, **args), 307)

lmfdb/groups/abstract/test_browse_page.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ def test_index_page(self):
1919
def test_legacy_search_urls(self):
2020
r"""
2121
Check that old search URLs redirect to the new landing pages without
22-
dropping their filters.
22+
dropping their filters. The hidden hst field records the previous
23+
search mode, so it must not survive the redirect: SearchWrapper falls
24+
back to hst when there is no explicit search_type.
2325
"""
2426
cases = [
2527
("/Groups/Abstract/?search_type=Subgroups&ambient=128.207",
@@ -34,11 +36,25 @@ def test_legacy_search_urls(self):
3436
{"dim": ["3"], "search_type": ["RandomComplexCharacter"]}),
3537
("/Groups/Abstract/?search_type=ConjugacyClasses&group=12.4",
3638
"/Groups/Abstract/ConjugacyClasses", {"group": ["12.4"]}),
39+
# The legacy mode may only be present in the hidden hst field.
40+
("/Groups/Abstract/?hst=Subgroups&ambient=128.207",
41+
"/Groups/Abstract/Subgroups", {"ambient": ["128.207"]}),
42+
("/Groups/Abstract/?hst=RandomSubgroup&ambient=128.207",
43+
"/Groups/Abstract/Subgroups",
44+
{"ambient": ["128.207"], "search_type": ["RandomSubgroup"]}),
45+
# An explicit search_type must keep winning over a stale hst.
46+
("/Groups/Abstract/?search_type=Subgroups&hst=RandomSubgroup&ambient=128.207",
47+
"/Groups/Abstract/Subgroups", {"ambient": ["128.207"]}),
48+
("/Groups/Abstract/?search_type=ComplexCharacters&hst=RandomComplexCharacter&dim=3",
49+
"/Groups/Abstract/ComplexCharacters", {"dim": ["3"]}),
50+
# Repeated values of a non-routing parameter are preserved.
51+
("/Groups/Abstract/?search_type=Subgroups&order=8&order=16",
52+
"/Groups/Abstract/Subgroups", {"order": ["8", "16"]}),
3753
]
3854
for source, expected_path, expected_query in cases:
3955
response = self.tc.get(source)
40-
target = urlsplit(response.location)
4156
assert response.status_code == 307
57+
target = urlsplit(response.location)
4258
assert target.path == expected_path
4359
assert parse_qs(target.query) == expected_query
4460

lmfdb/tests/test_utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ def test_complete(self):
400400
("artin_reps", {'GaloisLabel': '8T34', 'Conductor': {'$gte': 1, '$lte': 200}}),
401401
("gps_groups", {'order': {'$gte': 300, '$lte': 600}}),
402402
("ec_curvedata", {'rank': 6}),
403+
("ec_curvedata", {'conductor': 1000000007}), # prime, but past the 300 million prime conductor bound
404+
("ec_curvedata", {'conductor': {'$in': [1000003, 1000000007]}}), # all prime, but not all within the bound
403405
("hgcwa_passports", {'genus': 6}),
404406
("av_fq_isog", {'g': 6, 'q': 3}),
405407
("belyi_galmaps", {'deg': 8}),

lmfdb/utils/completeness.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,11 @@ class PrimeBound(Bound):
805805
"""
806806
def __call__(self, db, Ds):
807807
Ds = [self.cls(D) for D in Ds]
808-
return all(D.is_finite() and all(is_prime(p) for p in D) for D in Ds)
808+
# The bound is checked first, both because a value outside it is not certified
809+
# complete however prime it is, and because it rules out large ranges without
810+
# iterating over them. ``is_finite`` is still needed: the bounds are typically
811+
# unbounded below, so passing it does not make the set enumerable.
812+
return super().__call__(db, Ds) and all(D.is_finite() and all(is_prime(p) for p in D) for D in Ds)
809813

810814

811815
class Smooth(ColTest):

lmfdb/utils/utilities.py

Lines changed: 1 addition & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import cmath
22
import math
33
import os
4-
import random
54
import re
65
import tempfile
7-
import time
86
from copy import copy
97
from itertools import islice
108
from types import GeneratorType
@@ -35,7 +33,7 @@
3533
from sage.misc.functional import round
3634
from sage.structure.element import Element
3735

38-
from lmfdb.app import app, is_beta, is_debug_mode, _url_source
36+
from lmfdb.app import is_beta, is_debug_mode, _url_source
3937

4038

4139
def integer_divisors(n):
@@ -802,124 +800,6 @@ def flash_success(msg, *args):
802800
flash(Markup(msg % tuple("<span style='color:black'>%s</span>" % escape(x) for x in args)), "success")
803801

804802

805-
################################################################################
806-
# Ajax utilities
807-
################################################################################
808-
809-
# LinkedList is used in Ajax below
810-
class LinkedList():
811-
__slots__ = ('value', 'next', 'timestamp')
812-
813-
def __init__(self, value, nxt):
814-
self.value = value
815-
self.next = nxt
816-
self.timestamp = time.time()
817-
818-
def append(self, value):
819-
self.next = LinkedList(value, self)
820-
return self.next
821-
822-
823-
class AjaxPool():
824-
def __init__(self, size=1e4, expiration=3600):
825-
self._size = size
826-
self._key_list = self._head = LinkedList(None, None)
827-
self._expiration = expiration
828-
self._all = {}
829-
830-
def get(self, key, value=None):
831-
return self._all.get(key, value)
832-
833-
def __contains__(self, key):
834-
return key in self._all
835-
836-
def __setitem__(self, key, value):
837-
self._key_list = self._key_list.append(key)
838-
self._all[key] = value
839-
840-
def __getitem__(self, key):
841-
res = self._all[key]
842-
self.purge()
843-
return res
844-
845-
def __delitem__(self, key):
846-
del self._all[key]
847-
848-
def pop_key(self):
849-
head = self._head
850-
if head.next is None:
851-
return None
852-
else:
853-
key = head.value
854-
self._head = head.next
855-
return key
856-
857-
def purge(self):
858-
if self._size:
859-
while len(self._all) > self._size:
860-
key = self.pop_key()
861-
if key in self._all:
862-
del self._all[key]
863-
if self._expiration:
864-
oldest = time.time() - self._expiration
865-
while self._head.timestamp < oldest:
866-
key = self.pop_key()
867-
if key in self._all:
868-
del self._all[key]
869-
870-
871-
pending = AjaxPool()
872-
def ajax_url(callback, *args, **kwds):
873-
if '_ajax_sticky' in kwds:
874-
_ajax_sticky = kwds.pop('_ajax_sticky')
875-
else:
876-
_ajax_sticky = False
877-
if not isinstance(args, tuple):
878-
args = args,
879-
nonce = hex(random.randint(0, 1 << 128))
880-
pending[nonce] = callback, args, kwds, _ajax_sticky
881-
return url_for('ajax_result', id=nonce)
882-
883-
884-
@app.route('/callback_ajax/<id>')
885-
def ajax_result(id):
886-
if id in pending:
887-
f, args, kwds, _ajax_sticky = pending[id]
888-
if not _ajax_sticky:
889-
del pending[id]
890-
return f(*args, **kwds)
891-
else:
892-
return "<expired>"
893-
894-
895-
def ajax_more(callback, *arg_list, **kwds):
896-
from .web_display import web_latex
897-
inline = kwds.get('inline', True)
898-
text = kwds.get('text', 'more')
899-
nonce = hex(random.randint(0, 1 << 128))
900-
if inline:
901-
args = arg_list[0]
902-
arg_list = arg_list[1:]
903-
if isinstance(args, tuple):
904-
res = callback(*arg_list)
905-
elif isinstance(args, dict):
906-
res = callback(**args)
907-
else:
908-
res = callback(args)
909-
res = web_latex(res)
910-
else:
911-
res = ''
912-
if arg_list:
913-
url = ajax_url(ajax_more, callback, *arg_list, inline=True, text=text)
914-
return """<span id='%(nonce)s'>%(res)s <a onclick="$('#%(nonce)s').load('%(url)s', function() { renderMathInElement($('#%(nonce)s').get(0),katexOpts);}); return false;" href="#">%(text)s</a></span>""" % locals()
915-
else:
916-
return res
917-
918-
919-
def image_src(G):
920-
return ajax_url(image_callback, G, _ajax_sticky=True)
921-
922-
923803
def image_callback(G):
924804
P = G.plot()
925805
_, filename = tempfile.mkstemp('.png')

0 commit comments

Comments
 (0)