Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ _doc/examples/data/*.optimized.onnx
_doc/examples/*.html
_doc/_static/require.js
_doc/_static/viz.js
_doc/practice/algo-compose/paris_54000.*
589 changes: 258 additions & 331 deletions _doc/practice/algo-compose/paris_parcours.ipynb

Large diffs are not rendered by default.

32 changes: 19 additions & 13 deletions _unittests/ut_xrun_doc/test_documentation_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,19 @@ def run_test(self, fold: str, name: str, verbose=0) -> int:
res = p.communicate()
out, err = res
st = err.decode("ascii", errors="ignore")
if "No such file or directory" in st:
raise FileNotFoundError(st)
if len(st) > 0 and "Traceback" in st:
if '"dot" not found in path.' in st:
# dot not installed, this part
# is tested in onnx framework
if verbose:
print(f"failed: {name!r} due to missing dot.")
return -1
if "No such file or directory: 'schema_pb2.py'" in str(st):
if verbose:
print(
f"failed: {name!r} due to missing protoc "
f"(or wrong version)."
)
return -1
raise AssertionError(
"Example '{}' (cmd: {} - exec_prefix='{}') "
"failed due to\n{}"
"".format(name, cmds, sys.exec_prefix, st)
f"Example {name!r} (cmd: {cmds!r} - "
f"exec_prefix={sys.exec_prefix!r}) "
f"failed due to\n{st}"
)
dt = time.perf_counter() - perf
if verbose:
Expand All @@ -75,9 +70,20 @@ def add_test_methods(cls):
if name.startswith("plot_") and name.endswith(".py"):
short_name = os.path.split(os.path.splitext(name)[0])[-1]

def _test_(self, name=name):
res = self.run_test(fold, name, verbose=VERBOSE)
self.assertIn(res, (-1, 1))
if sys.platform == "win32" and (
"protobuf" in name or "td_note_2021" in name
):

@unittest.skip("notebook with questions or issues with windows")
def _test_(self, name=name):
res = self.run_test(fold, name, verbose=VERBOSE)
self.assertIn(res, (-1, 1))

else:

def _test_(self, name=name):
res = self.run_test(fold, name, verbose=VERBOSE)
self.assertIn(res, (-1, 1))

setattr(cls, f"test_{short_name}", _test_)

Expand Down
46 changes: 32 additions & 14 deletions _unittests/ut_xrun_doc/test_documentation_notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import sys
import importlib
import subprocess
import tempfile
import time
from nbconvert import PythonExporter
from teachpyx import __file__ as teachpyx_file
Expand Down Expand Up @@ -48,31 +47,40 @@ def run_test(self, nb_name: str, verbose=0) -> int:
content = self.post_process(exporter.from_filename(nb_name)[0])
bcontent = content.encode("utf-8")

with tempfile.NamedTemporaryFile(suffix=".py") as tmp:
self.assertEndsWith(tmp.name, ".py")
tmp.write(bcontent)
tmp.seek(0)
tmp = "temp_notebooks"
if not os.path.exists(tmp):
os.mkdir(tmp)
# with tempfile.NamedTemporaryFile(suffix=".py") as tmp:
name = os.path.splitext(os.path.split(nb_name)[-1])[0]
if os.path.exists(tmp):
tmp_name = os.path.join(tmp, name + ".py")
self.assertEndsWith(tmp_name, ".py")
with open(tmp_name, "wb") as f:
f.write(bcontent)

fold, name = os.path.split(tmp.name)
fold, name = os.path.split(tmp_name)

try:
mod = import_source(fold, os.path.splitext(name)[0])
assert mod is not None
except (FileNotFoundError, RuntimeError):
# try another way
cmds = [sys.executable, "-u", name]
cmds = [sys.executable, "-u", tmp_name]
p = subprocess.Popen(
cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
res = p.communicate()
out, err = res
st = err.decode("ascii", errors="ignore")
if "No such file or directory" in st:
raise FileNotFoundError(st)
if len(st) > 0 and "Traceback" in st:
raise AssertionError(
msg = (
f"Example {nb_name!r} (cmd: {cmds} - "
f"exec_prefix={sys.exec_prefix!r}) "
f"failed due to\n{st}\n-----\n{content}"
f"failed due to\n{st}"
)
raise AssertionError(msg)

dt = time.perf_counter() - perf
if verbose:
Expand All @@ -84,14 +92,23 @@ def add_test_methods_path(cls, fold):
found = os.listdir(fold)
last = os.path.split(fold)[-1]
for name in found:
if "interro_rapide_" in name:
continue
if name.endswith(".ipynb"):
fullname = os.path.join(fold, name)
if "interro_rapide_" in name or (
sys.platform == "win32"
and ("protobuf" in name or "td_note_2021" in name)
):

def _test_(self, fullname=fullname):
res = self.run_test(fullname, verbose=VERBOSE)
self.assertIn(res, (-1, 1))
@unittest.skip("notebook with questions or issues with windows")
def _test_(self, fullname=fullname):
res = self.run_test(fullname, verbose=VERBOSE)
self.assertIn(res, (-1, 1))

else:

def _test_(self, fullname=fullname):
res = self.run_test(fullname, verbose=VERBOSE)
self.assertIn(res, (-1, 1))

lasts = last.replace("-", "_")
names = os.path.splitext(name)[0].replace("-", "_")
Expand All @@ -104,6 +121,7 @@ def add_test_methods(cls):
os.path.join(this, "..", "..", "_doc", "practice", "exams"),
os.path.join(this, "..", "..", "_doc", "practice", "py-base"),
os.path.join(this, "..", "..", "_doc", "practice", "algo-base"),
os.path.join(this, "..", "..", "_doc", "practice", "algo-compose"),
]
for fold in folds:
cls.add_test_methods_path(os.path.normpath(fold))
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ install:
build: off

test_script:
- "%PYTHON%\\python -m pytest _unittests"
- "%PYTHON%\\python -m pytest _unittests -v"

after_test:
- "%PYTHON%\\python -u setup.py bdist_wheel"
Expand Down
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ lifelines
matplotlib
mutagen # mp3
nbsphinx
networkx
pandas
pillow
protobuf<4
Expand Down
90 changes: 56 additions & 34 deletions teachpyx/practice/rues_paris.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ def get_data(
:param dest: répertoire dans lequel télécharger les données
:param timeout: timeout (seconds) when estabishing the connection
:param verbose: affiche le progrès
:param keep: garde tout si la valeur est -1, sinon garde les 1000 premières rues
:param keep: garde tout si la valeur est -1,
sinon garde les 1000 premières rues, ces rues sont choisies
de façon à construire un ensemble connexe
:return: liste d'arcs

Un arc est défini par un 6-uple contenant les informations suivantes :
Expand Down Expand Up @@ -88,22 +90,38 @@ def get_data(
pairs[p] = True

if keep is not None:
short_edges = edges[:keep]
new_vertices = {}
edges = []
for edge in short_edges:
p1, p2 = edge[-3:-1]
if p1 not in new_vertices:
new_vertices[p1] = len(new_vertices)
if p2 not in new_vertices:
new_vertices[p2] = len(new_vertices)
i1, i2 = new_vertices[p1], new_vertices[p2]
edges.append((i1, i2, edge[2], p1, p2, edge[-1]))
already_added = set()
new_edges = []
for _ in range(0, int(keep**0.5) + 1):
for edge in edges:
if edge[:2] in already_added:
continue
p1, p2 = edge[-3:-1]
if (
len(new_vertices) > 0
and p1 not in new_vertices
and p2 not in new_vertices
):
# On considère des rues connectées à des rues déjà sélectionnées.
continue
if p1 not in new_vertices:
new_vertices[p1] = len(new_vertices)
if p2 not in new_vertices:
new_vertices[p2] = len(new_vertices)
i1, i2 = new_vertices[p1], new_vertices[p2]
new_edges.append((i1, i2, edge[2], p1, p2, edge[-1]))
already_added.add(edge[:2])
if len(new_edges) >= keep:
break
if len(new_edges) >= keep:
break
items = [(v, i) for i, v in new_vertices.items()]
items.sort()
vertices = [_[1] for _ in items]
edges = new_edges

return edges
return edges, vertices


def graph_degree(
Expand Down Expand Up @@ -321,7 +339,7 @@ def eulerien_extension(
totali = 0
while len(allow) > 0:
if verbose:
print(f"------- nb odd vertices {len(allow)} iteration {totali}")
print(f"------- # odd vertices {len(allow)} iteration {totali}")
allowset = set(allow)
init = bellman(
edges,
Expand Down Expand Up @@ -384,9 +402,9 @@ def euler_path(
edges_from = {}
somme = 0
for e in edges:
k = e[:2]
v = e[-1]
alledges[k] = ["street"] + list(k + (v,))
k = e[:2] # indices des noeuds
v = e[-1] # distance
alledges[k] = ["street", *k, v]
a, b = k
alledges[b, a] = alledges[a, b]
if a not in edges_from:
Expand All @@ -398,10 +416,10 @@ def euler_path(
somme += v

for e in added_edges: # il ne faut pas enlever les doublons
k = e[:2]
v = e[-1]
k = e[:2] # indices ds noeuds
v = e[-1] # distance
a, b = k
alledges[k] = ["jump"] + list(k + (v,))
alledges[k] = ["jump", *k, v]
alledges[b, a] = alledges[a, b]
if a not in edges_from:
edges_from[a] = []
Expand All @@ -411,39 +429,43 @@ def euler_path(
edges_from[b].append(alledges[a, b])
somme += v

degre = {}
for a, v in edges_from.items():
t = len(v)
degre[t] = degre.get(t, 0) + 1

two = [a for a, v in edges_from.items() if len(v) == 2]
# les noeuds de degré impair
odd = [a for a, v in edges_from.items() if len(v) % 2 == 1]
if len(odd) > 0:
raise ValueError("some vertices have an odd degree")
raise ValueError("Some vertices have an odd degree.")
# les noeuds de degré 2, on les traverse qu'une fois
two = [a for a, v in edges_from.items() if len(v) == 2]
begin = two[0]

# checking
for v, le in edges_from.items():
# v est une extrémité
for e in le:
# to est l'autre extrémité
to = e[1] if v != e[1] else e[2]
if to not in edges_from:
raise RuntimeError(
"unable to find vertex {0} for edge {0},{1}".format(to, v)
)
raise RuntimeError(f"Unable to find vertex {to} for edge {to},{v}")
if to == v:
raise RuntimeError(f"circular edge {to}")
raise RuntimeError(f"Circular edge {to}")

# loop
# On sait qu'il existe un chemin. La fonction explore les arcs
# jusqu'à revenir à son point de départ. Elle supprime les arcs
# utilisées de edges_from.
path = _explore_path(edges_from, begin)
for p in path:
if len(p) == 0:
raise RuntimeError("this exception should not happen")

# Il faut s'assurer que le chemin ne contient pas de boucles non visitées.
while len(edges_from) > 0:
# Il reste des arcs non visités. On cherche le premier
# arc connecté au chemin existant.
start = None
for i, p in enumerate(path):
if p[0] in edges_from:
start = i, p
break
if start is None:
raise RuntimeError(
f"start should not be None\npath={path}\nedges_from={edges_from}"
)
sub = _explore_path(edges_from, start[1][0])
i = start[0]
path[i : i + 1] = path[i : i + 1] + sub
Expand Down