diff --git a/docker/all/all.py b/docker/all/all.py index 0bc1073f4697df8a7879b01919eb4bffe2bbf79a..54919c969e2f97ed30a7ff0f7f43fe91d9506631 100755 --- a/docker/all/all.py +++ b/docker/all/all.py @@ -7,35 +7,43 @@ import asyncio import sys from asyncio.subprocess import DEVNULL, PIPE -DISTRIBUTIONS = '16.04 18.04 20.04 fedora28 fedora31 archlinux stretch buster centos7'.split() +DISTRIBUTIONS = ( + "16.04 18.04 20.04 fedora28 fedora31 archlinux stretch buster centos7".split() +) async def build_run(dist, verbose=False, parallel=1): """Build and run a dockerfile.""" - cmd = f'docker build --build-arg DIST={dist} --build-arg PARALLEL={parallel} -t all/{dist} .' + cmd = f"docker build --build-arg DIST={dist} --build-arg PARALLEL={parallel} -t all/{dist} ." if verbose: - print(f'+ {cmd}\r') - proc = await asyncio.create_subprocess_exec(*cmd.split(), stdout=DEVNULL, stderr=DEVNULL) + print(f"+ {cmd}\r") + proc = await asyncio.create_subprocess_exec( + *cmd.split(), stdout=DEVNULL, stderr=DEVNULL + ) await proc.wait() if proc.returncode != 0: - print(f'{dist:10} build failed\r') + print(f"{dist:10} build failed\r") return - cmd = f'docker run --rm -it all/{dist}' + cmd = f"docker run --rm -it all/{dist}" if verbose: - print(f'+ {cmd}\r') - proc = await asyncio.create_subprocess_exec(*cmd.split(), stdout=PIPE, stderr=DEVNULL) + print(f"+ {cmd}\r") + proc = await asyncio.create_subprocess_exec( + *cmd.split(), stdout=PIPE, stderr=DEVNULL + ) stdout, _ = await proc.communicate() - stdout = stdout.decode().replace('\r\n', ' ') + stdout = stdout.decode().replace("\r\n", " ") if proc.returncode == 0: - print(f'{dist:10} {stdout}\r') + print(f"{dist:10} {stdout}\r") else: - print(f'{dist:10} run failed\r') + print(f"{dist:10} run failed\r") -if __name__ == '__main__': +if __name__ == "__main__": loop = asyncio.get_event_loop() if len(sys.argv) > 1: loop.run_until_complete(build_run(sys.argv[1], verbose=True, parallel=8)) else: - loop.run_until_complete(asyncio.gather(*(build_run(dist) for dist in DISTRIBUTIONS))) + loop.run_until_complete( + asyncio.gather(*(build_run(dist) for dist in DISTRIBUTIONS)) + ) loop.close() diff --git a/docker/all/run.py b/docker/all/run.py index bee47a63b3e5d2a24a74a40c33d93077e3913d36..39e1b4d6cd42d13d4169b5b63eae33d3779583f9 100755 --- a/docker/all/run.py +++ b/docker/all/run.py @@ -12,19 +12,23 @@ import numpy as np import pinocchio import tsid -with open('/dist') as f: +with open("/dist") as f: dist = f.read() -if '20.04' in dist: - print('*' * 74) -print('{: <6s}'.format(sys.version.split()[0])) +if "20.04" in dist: + print("*" * 74) +print("{: <6s}".format(sys.version.split()[0])) print(eigenpy.Quaternion(1, 2, 3, 4).norm()) print(hppfcl.Capsule(2, 3).computeVolume()) print(pinocchio.SE3.Identity().inverse()) -print(example_robot_data.load('talos').model.nq) +print(example_robot_data.load("talos").model.nq) URDF = "/talos_data/robots/talos_left_arm.urdf" PATH = example_robot_data.robots_loader.getModelPath(URDF) print(tsid.RobotWrapper(PATH + URDF, [PATH], False).na) print(crocoddyl.ActionModelUnicycle().nr) -print(curves.bezier(np.array([[1, 2, 3], [4, 5, 6], [4, 5, 6], [4, 5, 6], [4, 5, 6]]), 0.2, 1.5).dim()) +print( + curves.bezier( + np.array([[1, 2, 3], [4, 5, 6], [4, 5, 6], [4, 5, 6], [4, 5, 6]]), 0.2, 1.5 + ).dim() +) print(multicontact_api.ContactModel().mu) diff --git a/docker/manylinux2014/config/eigenpy/setup.py b/docker/manylinux2014/config/eigenpy/setup.py index 028c0a2e8baac9c275adf49c3872b61c1ee69c13..9d2cdc9a157b1509cb243964e8de80ba8bb78251 100644 --- a/docker/manylinux2014/config/eigenpy/setup.py +++ b/docker/manylinux2014/config/eigenpy/setup.py @@ -13,11 +13,13 @@ setup( long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/stack-of-tasks/eigenpy", - install_requires=['numpy'], - cmake_minimum_required_version='3.1', + install_requires=["numpy"], + cmake_minimum_required_version="3.1", classifiers=[ - "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", - "License :: OSI Approved :: BSD License", "Operating System :: POSIX :: Linux" + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "License :: OSI Approved :: BSD License", + "Operating System :: POSIX :: Linux", ], - python_requires='>=2.7', + python_requires=">=2.7", ) diff --git a/docker/manylinux2014/config/eigenpy/test.py b/docker/manylinux2014/config/eigenpy/test.py index af64145debf3bba3220ad2a036520c9730bbef68..d0c2bb9aee3cdf339a4742e3de759366c4ccd75f 100644 --- a/docker/manylinux2014/config/eigenpy/test.py +++ b/docker/manylinux2014/config/eigenpy/test.py @@ -5,8 +5,10 @@ import eigenpy class TestEigenpy(unittest.TestCase): def test_trivial(self): - self.assertLess(abs(eigenpy.Quaternion(1, 2, 3, 4).norm() - 5.47722557505), 1e-7) + self.assertLess( + abs(eigenpy.Quaternion(1, 2, 3, 4).norm() - 5.47722557505), 1e-7 + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/docker/manylinux2014/config/example-robot-data/setup.py b/docker/manylinux2014/config/example-robot-data/setup.py index f02d5fb9d156aaa2a4138e1247b8a7f6c0e22834..b6ed3d312d33cbc4a395312cc29c0fbdb15299a7 100644 --- a/docker/manylinux2014/config/example-robot-data/setup.py +++ b/docker/manylinux2014/config/example-robot-data/setup.py @@ -1,26 +1,35 @@ from setuptools import setup import os + def read_text(path): with open(path) as f: - return f.read().decode('utf-8').strip() + return f.read().decode("utf-8").strip() + def data_files(*paths): - return [(root, [os.path.join(root, f) for f in files]) for path in paths for root, _, files in os.walk(path)] + return [ + (root, [os.path.join(root, f) for f in files]) + for path in paths + for root, _, files in os.walk(path) + ] + setup( name="example-robot-data", - packages=['example_robot_data'], + packages=["example_robot_data"], description="Set of robot URDFs for benchmarking and developed examples.", url="https://github.com/gepetto/example-robot-data", - install_requires=['pinocchio'], + install_requires=["pinocchio"], data_files=data_files("include", "lib", "share"), - version=read_text('.version'), + version=read_text(".version"), long_description=read_text("README.md"), long_description_content_type="text/markdown", classifiers=[ - "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", - "License :: OSI Approved :: BSD License", "Operating System :: POSIX :: Linux" + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "License :: OSI Approved :: BSD License", + "Operating System :: POSIX :: Linux", ], - python_requires='>=2.7', + python_requires=">=2.7", ) diff --git a/docker/manylinux2014/config/example-robot-data/test.py b/docker/manylinux2014/config/example-robot-data/test.py index 325870f22ae5d59c4a4636f3d0796728586ddf99..3a0165a7c4b2388156f8ffe6e7f15af53e8f174f 100644 --- a/docker/manylinux2014/config/example-robot-data/test.py +++ b/docker/manylinux2014/config/example-robot-data/test.py @@ -5,8 +5,8 @@ import example_robot_data class TestPinocchio(unittest.TestCase): def test_trivial(self): - self.assertEqual(example_robot_data.load('talos').model.nq, 39) + self.assertEqual(example_robot_data.load("talos").model.nq, 39) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/docker/manylinux2014/config/hpp-fcl/setup.py b/docker/manylinux2014/config/hpp-fcl/setup.py index 0a852d47cdd63d1b0b5aef873f25b9135717700a..d58e3db604c55b393a84a33c9565cf02d181eb69 100644 --- a/docker/manylinux2014/config/hpp-fcl/setup.py +++ b/docker/manylinux2014/config/hpp-fcl/setup.py @@ -13,11 +13,13 @@ setup( long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/humanoid-path-planner/hpp-fcl", - install_requires=['eigenpy'], - cmake_minimum_required_version='3.1', + install_requires=["eigenpy"], + cmake_minimum_required_version="3.1", classifiers=[ - "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", - "License :: OSI Approved :: BSD License", "Operating System :: POSIX :: Linux" + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "License :: OSI Approved :: BSD License", + "Operating System :: POSIX :: Linux", ], - python_requires='>=2.7', + python_requires=">=2.7", ) diff --git a/docker/manylinux2014/config/hpp-fcl/test.py b/docker/manylinux2014/config/hpp-fcl/test.py index 23856d17358d0f607826fce49536e758e4d5da9e..d4c8678a8bad79b54e3dc2ebf805d1faf9c4f4e6 100644 --- a/docker/manylinux2014/config/hpp-fcl/test.py +++ b/docker/manylinux2014/config/hpp-fcl/test.py @@ -8,5 +8,5 @@ class TestHPPFCL(unittest.TestCase): self.assertLess(abs(hppfcl.Capsule(2, 3).computeVolume() - 71.2094334814), 1e-7) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/docker/manylinux2014/config/pinocchio/setup.py b/docker/manylinux2014/config/pinocchio/setup.py index a215ee777db8c2a8577014d1488f82c175a993dd..0299f70f27f49a01b23febcead90140fbb264392 100644 --- a/docker/manylinux2014/config/pinocchio/setup.py +++ b/docker/manylinux2014/config/pinocchio/setup.py @@ -13,11 +13,13 @@ setup( long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/stack-of-tasks/pinocchio", - install_requires=['hpp-fcl'], - cmake_minimum_required_version='3.1', + install_requires=["hpp-fcl"], + cmake_minimum_required_version="3.1", classifiers=[ - "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", - "License :: OSI Approved :: BSD License", "Operating System :: POSIX :: Linux" + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "License :: OSI Approved :: BSD License", + "Operating System :: POSIX :: Linux", ], - python_requires='>=2.7', + python_requires=">=2.7", ) diff --git a/docker/manylinux2014/config/pinocchio/test.py b/docker/manylinux2014/config/pinocchio/test.py index 9025d6fe799d5ba542f7bd979cae2c9d5d05e9b2..b51b086b5d6dec5d121dce4cff790e88c54f248b 100644 --- a/docker/manylinux2014/config/pinocchio/test.py +++ b/docker/manylinux2014/config/pinocchio/test.py @@ -5,8 +5,11 @@ import pinocchio class TestPinocchio(unittest.TestCase): def test_trivial(self): - self.assertEqual(str(pinocchio.SE3.Identity().inverse()), ' R =\n1 0 0\n0 1 0\n0 0 1\n p = -0 -0 -0\n') + self.assertEqual( + str(pinocchio.SE3.Identity().inverse()), + " R =\n1 0 0\n0 1 0\n0 0 1\n p = -0 -0 -0\n", + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/docker/manylinux2014/scripts/patch_whitelist.py b/docker/manylinux2014/scripts/patch_whitelist.py index 03cf15152e99e397889cacc7a11dd3851fa0e527..9d5e0f3437764ec6d9b6f2912a215f19d4d2dc96 100755 --- a/docker/manylinux2014/scripts/patch_whitelist.py +++ b/docker/manylinux2014/scripts/patch_whitelist.py @@ -13,18 +13,18 @@ from pathlib import Path import auditwheel -POLICY = Path(auditwheel.__file__).parent / 'policy/policy.json' +POLICY = Path(auditwheel.__file__).parent / "policy/policy.json" with POLICY.open() as f: policies = json.load(f) deps = [] -for dep in Path(sys.argv[-1]).glob('*.libs'): +for dep in Path(sys.argv[-1]).glob("*.libs"): deps.append(dep.name) - for lib in dep.glob('*.so*'): + for lib in dep.glob("*.so*"): policies[-1]["lib_whitelist"].append(lib.name) -with POLICY.open('w') as f: +with POLICY.open("w") as f: json.dump(policies, f) -print(''.join(f':$ORIGIN/../{dep}' for dep in deps)) +print("".join(f":$ORIGIN/../{dep}" for dep in deps)) diff --git a/newcomers/check_matrix.py b/newcomers/check_matrix.py index b75a10ee05e2de56a201ff562864c25f34386b9b..f94fd1bcc58dee2bb2502c89bcbf6025e29d6251 100755 --- a/newcomers/check_matrix.py +++ b/newcomers/check_matrix.py @@ -6,15 +6,19 @@ from matrix_client.client import MatrixClient from greet_newcomers import get_gepetto -HOME = 'https://matrix.laas.fr' -ROOM = '#gepetto:laas.fr' +HOME = "https://matrix.laas.fr" +ROOM = "#gepetto:laas.fr" -if __name__ == '__main__': +if __name__ == "__main__": client = MatrixClient(HOME) client.login(username=getpass.getuser(), password=getpass.getpass()) room = client.rooms[client.api.get_room_id(ROOM)] - members = [m.user_id.split(':')[0][1:] for m in room.get_joined_members() if m.user_id.endswith(':laas.fr')] + members = [ + m.user_id.split(":")[0][1:] + for m in room.get_joined_members() + if m.user_id.endswith(":laas.fr") + ] for member in get_gepetto(): - print('v' if member in members else 'x', member) + print("v" if member in members else "x", member) diff --git a/newcomers/find_gepettist.py b/newcomers/find_gepettist.py index f9331ca7d551bdd6db222f977eeec066eed0e6cd..14cd6a2077a1e4b89243b0a8f6d7849fddb5fbd6 100755 --- a/newcomers/find_gepettist.py +++ b/newcomers/find_gepettist.py @@ -5,21 +5,22 @@ import sys import requests from bs4 import BeautifulSoup -URL = 'https://www.laas.fr/public/fr/' +URL = "https://www.laas.fr/public/fr/" def find_in_directory(name): - req = requests.get(URL + 'searchuser', {'letter': name}) - soup = BeautifulSoup(req.content, 'html.parser') - for guy in soup.find('div', class_='personnel').find_all('tr')[1:]: - if 'GEPETTO' in guy.text: - return URL + guy.find('a').attrs['href'] + req = requests.get(URL + "searchuser", {"letter": name}) + soup = BeautifulSoup(req.content, "html.parser") + for guy in soup.find("div", class_="personnel").find_all("tr")[1:]: + if "GEPETTO" in guy.text: + return URL + guy.find("a").attrs["href"] -if __name__ == '__main__': +if __name__ == "__main__": if len(sys.argv) > 1: print(find_in_directory(sys.argv[1])) else: from greet_newcomers import get_gepetto # noqa + for username in get_gepetto(): print(username.center(10), find_in_directory(username[1:])) diff --git a/newcomers/greet_newcomers.py b/newcomers/greet_newcomers.py index 76f810ccc8fc18ad5749e21989d72a05a077ae35..62c9db1bbb281ad18b01025a63ded45736f36a66 100755 --- a/newcomers/greet_newcomers.py +++ b/newcomers/greet_newcomers.py @@ -9,7 +9,7 @@ from pathlib import Path from ldap3 import Connection HERE = Path(__file__).resolve().parent -SHELF = str(HERE / '.cache') +SHELF = str(HERE / ".cache") def get_gepetto(): @@ -17,7 +17,7 @@ def get_gepetto(): Get the old list of Gepetto members """ with shelve.open(SHELF) as shelf: - gepetto = shelf['gepetto'] if 'gepetto' in shelf else [] + gepetto = shelf["gepetto"] if "gepetto" in shelf else [] return gepetto @@ -27,15 +27,18 @@ def whoami(gepetto): The mail will be sent from this account """ with shelve.open(SHELF) as shelf: - me = shelf['me'] if 'me' in shelf else getuser() + me = shelf["me"] if "me" in shelf else getuser() while me not in gepetto: - print("You (%s) dont's seem to be in the Gepetto group… What's your LAAS username ?" % me) - me = input('--> ') + print( + "You (%s) dont's seem to be in the Gepetto group… What's your LAAS username ?" + % me + ) + me = input("--> ") # remember this in the cache with shelve.open(SHELF) as shelf: - shelf['me'] = me + shelf["me"] = me return me @@ -44,20 +47,20 @@ def greet(to, sender): """ Send a greeting email to `to` """ - if '@' not in sender: - sender = '%s@laas.fr' % sender + if "@" not in sender: + sender = "%s@laas.fr" % sender - if '@' not in to: - to = '%s@laas.fr' % to + if "@" not in to: + to = "%s@laas.fr" % to - with (HERE / 'template.txt').open() as f: + with (HERE / "template.txt").open() as f: msg = MIMEText(f.read()) - msg['Subject'] = 'Welcome in Gepetto !' - msg['From'] = sender - msg['To'] = to - msg['Bcc'] = sender - s = SMTP('mail.laas.fr') + msg["Subject"] = "Welcome in Gepetto !" + msg["From"] = sender + msg["To"] = to + msg["Bcc"] = sender + s = SMTP("mail.laas.fr") s.send_message(msg) s.quit() @@ -66,12 +69,12 @@ def get_gepetto_ldap(): """ Get a new list of Gepetto members in the LDAP of the LAAS """ - conn = Connection('ldap.laas.fr', auto_bind=True) - conn.search('dc=laas,dc=fr', '(o=gepetto)', attributes=['uid']) + conn = Connection("ldap.laas.fr", auto_bind=True) + conn.search("dc=laas,dc=fr", "(o=gepetto)", attributes=["uid"]) return [str(entry.uid) for entry in conn.entries] -if __name__ == '__main__': +if __name__ == "__main__": # Get old and new list of members gepetto = get_gepetto() gepetto_ldap = get_gepetto_ldap() @@ -89,4 +92,4 @@ if __name__ == '__main__': # Save the new list with shelve.open(SHELF) as shelf: - shelf['gepetto'] = gepetto_ldap + shelf["gepetto"] = gepetto_ldap diff --git a/scripts/doc.py b/scripts/doc.py index 096a4d378a064945a0b06826d505d86166327436..3e45d02179b24bcbe314295a619813f19286b154 100755 --- a/scripts/doc.py +++ b/scripts/doc.py @@ -6,21 +6,28 @@ from zipfile import ZipFile import requests -DOC = Path('/net/cubitus/projects/Partage_GEPETTO/Doc') -GITLAB = 'https://gitlab.laas.fr' -RAINBOARD = 'http://rainboard.laas.fr' -INDEX = DOC / 'index.html' -HEAD = DOC / 'index.head.html' +DOC = Path("/net/cubitus/projects/Partage_GEPETTO/Doc") +GITLAB = "https://gitlab.laas.fr" +RAINBOARD = "http://rainboard.laas.fr" +INDEX = DOC / "index.html" +HEAD = DOC / "index.head.html" -if __name__ == '__main__': - with INDEX.open('w') as f: +if __name__ == "__main__": + with INDEX.open("w") as f: with HEAD.open() as head: f.write(head.read()) - for project, namespace, branch in sorted(requests.get('%s/doc' % RAINBOARD).json()['ret']): - url = '%s/%s/%s/-/jobs/artifacts/%s/download' % (GITLAB, namespace, project, branch) + for project, namespace, branch in sorted( + requests.get("%s/doc" % RAINBOARD).json()["ret"] + ): + url = "%s/%s/%s/-/jobs/artifacts/%s/download" % ( + GITLAB, + namespace, + project, + branch, + ) path = DOC / namespace / project / branch - r = requests.get(url, {'job': 'doc-coverage'}, stream=True) + r = requests.get(url, {"job": "doc-coverage"}, stream=True) try: z = ZipFile(BytesIO(r.content)) path.mkdir(parents=True, exist_ok=True) @@ -29,16 +36,20 @@ if __name__ == '__main__': pass if path.exists(): - with INDEX.open('a') as f: + with INDEX.open("a") as f: link = path.relative_to(DOC) - doxygen, coverage = link / 'doxygen-html', link / 'coverage' - print('<tr><td>%s</td><td>%s</td><td>%s</td><td>' % (project, namespace, branch), file=f) + doxygen, coverage = link / "doxygen-html", link / "coverage" + print( + "<tr><td>%s</td><td>%s</td><td>%s</td><td>" + % (project, namespace, branch), + file=f, + ) if (DOC / doxygen).is_dir(): print('<a href="%s">Doc</a>' % doxygen, file=f) - print('</td><td>', file=f) + print("</td><td>", file=f) if (DOC / coverage).is_dir(): print('<a href="%s">Coverage</a>' % coverage, file=f) - print('</td></tr>', file=f) + print("</td></tr>", file=f) - with INDEX.open('a') as f: - print('</table></body></html>', file=f) + with INDEX.open("a") as f: + print("</table></body></html>", file=f) diff --git a/scripts/offices.py b/scripts/offices.py index 98ab2b03526743a07d94ed2d77fb7b15dd0a4a82..ab2f6293983ff6bfb8270a8a61d8c3fa5c13386b 100755 --- a/scripts/offices.py +++ b/scripts/offices.py @@ -15,47 +15,52 @@ from wand.drawing import Drawing from wand.image import Image # Cache LDAP data -CACHE = Path('data/offices-ldap.json') +CACHE = Path("data/offices-ldap.json") # Drawings constants -LOGO = 'data/logo-low-black.png' +LOGO = "data/logo-low-black.png" DPCM = 300 / 2.54 # dot per cm @300DPI WIDTH, HEIGHT = int(6 * DPCM), int(3 * DPCM) # door labels are 6cm x 3cm -NOT_OFFICES = ['Exterieur', 'BSalleGerardBauzil'] -BAT_B = 'data/bat_b.png' +NOT_OFFICES = ["Exterieur", "BSalleGerardBauzil"] +BAT_B = "data/bat_b.png" MAP_POSITIONS = [ - ('B181', 1600, 830), - ('B185', 1600, 130), - ('B61a', 1333, 1820), - ('B63', 1333, 1500), - ('B65', 1333, 1320), - ('B67', 1333, 870), - ('B69.1', 1333, 680), - ('B69.2', 1333, 520), - ('B90', 0, 130), - ('B91', 0, 280), - ('B92', 0, 430), - ('B94', 0, 750), + ("B181", 1600, 830), + ("B185", 1600, 130), + ("B61a", 1333, 1820), + ("B63", 1333, 1500), + ("B65", 1333, 1320), + ("B67", 1333, 870), + ("B69.1", 1333, 680), + ("B69.2", 1333, 520), + ("B90", 0, 130), + ("B91", 0, 280), + ("B92", 0, 430), + ("B94", 0, 750), ] class Gepettist(NamedTuple): """A Gepettist has a SurName and a GivenName.""" + sn: str gn: str def __str__(self): - return f'{self.gn} {self.sn}' + return f"{self.gn} {self.sn}" class Offices: """A dict with rooms as key and set of Gepettists as values, defaulting to empty set.""" + def __init__(self, **offices): self.data = defaultdict(set) self.data.update(offices) def __str__(self): - return '\n'.join(f'{room:5}: {", ".join(str(m) for m in members)}' for room, members in self.sorted().items()) + return "\n".join( + f'{room:5}: {", ".join(str(m) for m in members)}' + for room, members in self.sorted().items() + ) def __getitem__(self, key): return self.data[key] @@ -70,7 +75,11 @@ class Offices: return self.data.items() def sorted(self): - return {o: sorted(self.data[o]) for o in sorted(self.data) if o != 'Exterieur' and self.data[o]} + return { + o: sorted(self.data[o]) + for o in sorted(self.data) + if o != "Exterieur" and self.data[o] + } def dumps(self): """dump a sorted dict of offices with sorted lists of members as a JSON string""" @@ -79,25 +88,39 @@ class Offices: @staticmethod def loads(s): """constructor from a JSON string""" - return Offices(**{room: set(Gepettist(*m) for m in members) for room, members in loads(s).items()}) + return Offices( + **{ + room: set(Gepettist(*m) for m in members) + for room, members in loads(s).items() + } + ) # Stuff that is wrong in LDAP… We should fix that there WRONG_OFFICE = { - 'Exterieur': {('Nils', 'Hareng')}, - 'BSalleGerardBauzil': {('Quang Anh', 'Le')}, - 'B69.1': {('Guilhem', 'Saurel'), ('Pierre', 'Fernbach')}, - 'B90': {('Nicolas', 'Mansard')}, - 'B69.2': {('Dinh Vinh Thanh', 'Nguyen'), ('Filip', 'Becanovic')}, + "Exterieur": {("Nils", "Hareng")}, + "BSalleGerardBauzil": {("Quang Anh", "Le")}, + "B69.1": {("Guilhem", "Saurel"), ("Pierre", "Fernbach")}, + "B90": {("Nicolas", "Mansard")}, + "B69.2": {("Dinh Vinh Thanh", "Nguyen"), ("Filip", "Becanovic")}, +} +WRONG_OFFICE = { + k: {Gepettist(sn, gn) for (gn, sn) in v} for k, v in WRONG_OFFICE.items() } -WRONG_OFFICE = {k: {Gepettist(sn, gn) for (gn, sn) in v} for k, v in WRONG_OFFICE.items()} # Fix unicode from LDAP data… ALIAS = { - 'B67': [({Gepettist('Leziart', 'Pierre-Alexandre')}, {Gepettist('Léziart', 'P-A')}), - ({Gepettist('Smaldone', 'Filippo Maria')}, {Gepettist('Smaldone', 'Filippo M.')})], - 'B61a': [({Gepettist('Taix', 'Michel')}, {Gepettist('Taïx', 'Michel')})], - 'B91': [({Gepettist('Soueres', 'Philippe')}, {Gepettist('Souères', 'Philippe')})], - 'B69.2': [({Gepettist('Nguyen', 'Dinh Vinh Thanh')}, {Gepettist('Nguyen', 'D. V. T.')})], + "B67": [ + ({Gepettist("Leziart", "Pierre-Alexandre")}, {Gepettist("Léziart", "P-A")}), + ( + {Gepettist("Smaldone", "Filippo Maria")}, + {Gepettist("Smaldone", "Filippo M.")}, + ), + ], + "B61a": [({Gepettist("Taix", "Michel")}, {Gepettist("Taïx", "Michel")})], + "B91": [({Gepettist("Soueres", "Philippe")}, {Gepettist("Souères", "Philippe")})], + "B69.2": [ + ({Gepettist("Nguyen", "Dinh Vinh Thanh")}, {Gepettist("Nguyen", "D. V. T.")}) + ], } @@ -105,34 +128,52 @@ def door_label(members, logo=True): """Generate the label for one office.""" if not members: return - with Image(width=WIDTH, height=HEIGHT, background=Color('white')) as img, Drawing() as draw: + with Image( + width=WIDTH, height=HEIGHT, background=Color("white") + ) as img, Drawing() as draw: if logo: with Image(filename=LOGO) as logo: - logo.transform(resize=f'{WIDTH}x{HEIGHT}') - draw.composite('over', 200, 0, logo.width, logo.height, logo) + logo.transform(resize=f"{WIDTH}x{HEIGHT}") + draw.composite("over", 200, 0, logo.width, logo.height, logo) if len(members) > 4: draw.font_size = 70 elif len(members) == 4: draw.font_size = 80 else: draw.font_size = 90 - draw.text_alignment = 'center' + draw.text_alignment = "center" height = HEIGHT - len(members) * draw.font_size - draw.text(int(WIDTH / 2), int(height / 2) + 65, '\n'.join(str(m) for m in sorted(members))) + draw.text( + int(WIDTH / 2), + int(height / 2) + 65, + "\n".join(str(m) for m in sorted(members)), + ) draw(img) return img.clone() def offices_ldap(): """Get a dict of Gepettists in their respective office from LDAP.""" - conn = Connection('ldap.laas.fr', auto_bind=True) - conn.search('dc=laas,dc=fr', '(laas-mainGroup=gepetto)', attributes=['sn', 'givenName', 'roomNumber', 'st']) + conn = Connection("ldap.laas.fr", auto_bind=True) + conn.search( + "dc=laas,dc=fr", + "(laas-mainGroup=gepetto)", + attributes=["sn", "givenName", "roomNumber", "st"], + ) offices = Offices() for entry in conn.entries: - room, gn, sn, st = str(entry.roomNumber), str(entry.givenName), str(entry.sn), str(entry.st) - if st not in ['JAMAIS', 'NON-PERTINENT'] and date(*(int(i) for i in reversed(st.split('/')))) < date.today(): + room, gn, sn, st = ( + str(entry.roomNumber), + str(entry.givenName), + str(entry.sn), + str(entry.st), + ) + if ( + st not in ["JAMAIS", "NON-PERTINENT"] + and date(*(int(i) for i in reversed(st.split("/")))) < date.today() + ): continue # filter out alumni - if room == '[]': + if room == "[]": continue # filter out the Sans-Bureaux-Fixes offices[room].add(Gepettist(sn, gn)) return offices @@ -153,7 +194,9 @@ def fix_wrong_offices(offices): def labels(offices): """Generate an A4 papier with labels for the doors of Gepetto offices.""" - with Image(width=int(21 * DPCM), height=int(29.7 * DPCM)) as page, Drawing() as draw: + with Image( + width=int(21 * DPCM), height=int(29.7 * DPCM) + ) as page, Drawing() as draw: for i, (office, members) in enumerate(offices.items()): if not members or office in NOT_OFFICES: continue @@ -161,9 +204,16 @@ def labels(offices): row, col = divmod(i, 3) row *= HEIGHT + DPCM col *= WIDTH + DPCM * 0.5 - draw.composite('over', int(col + DPCM * 0.75), int(row + DPCM), label.width, label.height, label) + draw.composite( + "over", + int(col + DPCM * 0.75), + int(row + DPCM), + label.width, + label.height, + label, + ) draw(page) - page.save(filename='labels.png') + page.save(filename="labels.png") def maps(offices, fixed): @@ -172,44 +222,46 @@ def maps(offices, fixed): for office, x, y in MAP_POSITIONS: label = door_label(offices[office], logo=False) if label: - draw.composite('over', x, y, label.width / 3, label.height / 3, label) + draw.composite("over", x, y, label.width / 3, label.height / 3, label) draw(page) - page.save(filename='generated_map%s.png' % ('_fixed' if fixed else '')) + page.save(filename="generated_map%s.png" % ("_fixed" if fixed else "")) -if __name__ == '__main__': +if __name__ == "__main__": parser = ArgumentParser(description=__doc__) - parser.add_argument('--update', action='store_true', help='update data from ldap') - parser.add_argument('--fixed', action='store_true', help='fix LDAP data from embeded infos') - parser.add_argument('--show', action='store_true', help='show data') - parser.add_argument('--labels', action='store_true', help='generate door labels') - parser.add_argument('--map', action='store_true', help='generate offices map') - parser.add_argument('-v', '--verbose', action='count', default=0) + parser.add_argument("--update", action="store_true", help="update data from ldap") + parser.add_argument( + "--fixed", action="store_true", help="fix LDAP data from embeded infos" + ) + parser.add_argument("--show", action="store_true", help="show data") + parser.add_argument("--labels", action="store_true", help="generate door labels") + parser.add_argument("--map", action="store_true", help="generate offices map") + parser.add_argument("-v", "--verbose", action="count", default=0) args = parser.parse_args() logging.basicConfig(level=50 - 10 * args.verbose) # Collect and fix data if args.update or not CACHE.exists(): - logging.info(' updating team members from LDAP') + logging.info(" updating team members from LDAP") offices = offices_ldap() - with CACHE.open('w') as f: + with CACHE.open("w") as f: f.write(offices.dumps()) else: - logging.info(' using cached team members') + logging.info(" using cached team members") with CACHE.open() as f: offices = Offices.loads(f.read()) if args.fixed: - logging.info(' fixing data') + logging.info(" fixing data") offices = fix_wrong_offices(offices) # Use collected data if args.show: - logging.info(' showing data') + logging.info(" showing data") print(offices) if args.labels: - logging.info(' generating door labels') + logging.info(" generating door labels") labels(offices) if args.map: - logging.info(' generating map') + logging.info(" generating map") maps(offices, args.fixed) diff --git a/scripts/parse_muscod_logs.py b/scripts/parse_muscod_logs.py index 0019f11478de4d4fe135db123ac0cf6985ca9167..2a0ea16fd9490f92103e8017ca3a8a680f76dcc9 100755 --- a/scripts/parse_muscod_logs.py +++ b/scripts/parse_muscod_logs.py @@ -5,13 +5,15 @@ import datetime import logging import re -DESC = "Parse muscod's logs to get NDIS, the number of iterations & total computation time" +DESC = ( + "Parse muscod's logs to get NDIS, the number of iterations & total computation time" +) args = argparse.ArgumentParser(description=DESC) -args.add_argument('filename', type=argparse.FileType('r')) -args.add_argument('-v', '--verbose', action='store_true') +args.add_argument("filename", type=argparse.FileType("r")) +args.add_argument("-v", "--verbose", action="store_true") logging.basicConfig() -logger = logging.getLogger('parse_muscod_logs') +logger = logging.getLogger("parse_muscod_logs") def parse_muscod_logs(filename, verbose): @@ -19,27 +21,29 @@ def parse_muscod_logs(filename, verbose): logger.setLevel(logging.INFO if verbose else logging.WARNING) for number, line in enumerate(filename): - if 'NDIS' in line: - ndis = int(line.split('=')[1].strip()) - logger.info('found NDIS on line %i: %s' % (number, ndis)) - elif '**** SQP iteration' in line: # Only the last will be remembered - iterations = int(line.split(' ')[3].strip()) - logger.info('found iterations on line %i: %s' % (number, iterations)) - elif ' Total' in line: # double space to avoid 'Grand Total' line - total_dict = re.search('(?P<minutes>\d{2}):(?P<seconds>\d{2}).(?P<milliseconds>\d{3})', line).groupdict() + if "NDIS" in line: + ndis = int(line.split("=")[1].strip()) + logger.info("found NDIS on line %i: %s" % (number, ndis)) + elif "**** SQP iteration" in line: # Only the last will be remembered + iterations = int(line.split(" ")[3].strip()) + logger.info("found iterations on line %i: %s" % (number, iterations)) + elif " Total" in line: # double space to avoid 'Grand Total' line + total_dict = re.search( + "(?P<minutes>\d{2}):(?P<seconds>\d{2}).(?P<milliseconds>\d{3})", line + ).groupdict() total = datetime.timedelta(**{k: int(v) for k, v in total_dict.items()}) - logger.info('found total on line %i: %s' % (number, total)) + logger.info("found total on line %i: %s" % (number, total)) if ndis is None: - logger.error('NDIS not found') + logger.error("NDIS not found") if iterations is None: - logger.error('iterations not found') + logger.error("iterations not found") if total is None: - logger.error('total not found') + logger.error("total not found") - return {'ndis': ndis, 'iterations': iterations, 'total': total} + return {"ndis": ndis, "iterations": iterations, "total": total} -if __name__ == '__main__': +if __name__ == "__main__": ret = parse_muscod_logs(**vars(args.parse_args())) print(ret) diff --git a/scripts/robotpkg-test-rc.py b/scripts/robotpkg-test-rc.py index 31451854955777005a999b2f8cc810e92f222f7d..cad00047942853b1d1796318f061ebd2a91a8a32 100755 --- a/scripts/robotpkg-test-rc.py +++ b/scripts/robotpkg-test-rc.py @@ -11,34 +11,84 @@ from pathlib import Path from shutil import rmtree # Shell colors -BOLD = '\033[1m' -RED = '\033[1;31m' -GREEN = '\033[1;32m' -PURPLE = '\033[1;35m' -NC = '\033[0m' +BOLD = "\033[1m" +RED = "\033[1;31m" +GREEN = "\033[1;32m" +PURPLE = "\033[1;35m" +NC = "\033[0m" # Robotpkg configuration ACCEPTABLE_LICENSES = [ - 'openhrp-grx-license', 'cnrs-hpp-closed-source', 'gnu-gpl', 'motion-analysis-license', 'pal-license' + "openhrp-grx-license", + "cnrs-hpp-closed-source", + "gnu-gpl", + "motion-analysis-license", + "pal-license", ] PREFER_SYSTEM = [ - 'gnupg', 'urdfdom', 'urdfdom-headers', 'ros-catkin', 'ros-comm', 'ros-genlisp', 'ros-message-generation', - 'ros-std-msgs', 'ros-rospack', 'ros-message-runtime', 'ros-roscpp-core', 'ros-xacro', 'ros-common-msgs', - 'ros-lint', 'ros-com-msgs', 'ros-com-msgs', 'bullet', 'ros-ros', 'ros-cmake-modules', 'ros-dynamic-reconfigure', - 'ros-realtime-tools', 'ros-control-toolbox', 'ros-bond-core', 'ros-class-loader', 'ros-pluginlib', 'ros-rqt', - 'ros-humanoid-msgs', 'ros-genmsg', 'ros-actionlib', 'ros-geometry', 'collada-dom', 'orocos-kdl', 'ros-angles ', - 'ros-console-bridge', 'ros-eigen-stl-containers', 'ros-random-numbers', 'ros-resource-retriever', - 'ros-shape-tools', 'ros-geometric-shapes', 'ros-srdfdom', 'ros-robot-model', 'ros-orocos-kdl', 'assimp' + "gnupg", + "urdfdom", + "urdfdom-headers", + "ros-catkin", + "ros-comm", + "ros-genlisp", + "ros-message-generation", + "ros-std-msgs", + "ros-rospack", + "ros-message-runtime", + "ros-roscpp-core", + "ros-xacro", + "ros-common-msgs", + "ros-lint", + "ros-com-msgs", + "ros-com-msgs", + "bullet", + "ros-ros", + "ros-cmake-modules", + "ros-dynamic-reconfigure", + "ros-realtime-tools", + "ros-control-toolbox", + "ros-bond-core", + "ros-class-loader", + "ros-pluginlib", + "ros-rqt", + "ros-humanoid-msgs", + "ros-genmsg", + "ros-actionlib", + "ros-geometry", + "collada-dom", + "orocos-kdl", + "ros-angles ", + "ros-console-bridge", + "ros-eigen-stl-containers", + "ros-random-numbers", + "ros-resource-retriever", + "ros-shape-tools", + "ros-geometric-shapes", + "ros-srdfdom", + "ros-robot-model", + "ros-orocos-kdl", + "assimp", ] parser = argparse.ArgumentParser(description=__doc__) -parser.add_argument('robotpkg_root', nargs='?', type=Path, default=Path.home() / 'devel-src/robotpkg-test-rc') -parser.add_argument('-v', '--verbose', action='count', default=0) -parser.add_argument('-d', '--delete', action='store_true') -parser.add_argument('-c', '--clean', action='store_true') -parser.add_argument('--robotpkg_git', default='https://git.openrobots.org/robots/robotpkg.git') -parser.add_argument('--robotpkg_wip_git', default='ssh://git@git.openrobots.org/robots/robotpkg/robotpkg-wip') -parser.add_argument('--conf', type=Path) +parser.add_argument( + "robotpkg_root", + nargs="?", + type=Path, + default=Path.home() / "devel-src/robotpkg-test-rc", +) +parser.add_argument("-v", "--verbose", action="count", default=0) +parser.add_argument("-d", "--delete", action="store_true") +parser.add_argument("-c", "--clean", action="store_true") +parser.add_argument( + "--robotpkg_git", default="https://git.openrobots.org/robots/robotpkg.git" +) +parser.add_argument( + "--robotpkg_wip_git", + default="ssh://git@git.openrobots.org/robots/robotpkg/robotpkg-wip", +) +parser.add_argument("--conf", type=Path) def prepend_paths(base, dirs, old=None): @@ -47,28 +97,36 @@ def prepend_paths(base, dirs, old=None): """ paths = [str(Path(base) / path) for path in dirs] if old is not None: - paths += old.split(':') - return ':'.join(paths) + paths += old.split(":") + return ":".join(paths) class RobotpkgTestRC: - def __init__(self, robotpkg_root, verbose, delete, clean, robotpkg_git, robotpkg_wip_git, conf): - """ Init environment variables - """ + def __init__( + self, + robotpkg_root, + verbose, + delete, + clean, + robotpkg_git, + robotpkg_wip_git, + conf, + ): + """Init environment variables""" self.robotpkg_root = robotpkg_root - self.robotpkg_base = self.robotpkg_root / 'install' + self.robotpkg_base = self.robotpkg_root / "install" self.delete = delete self.clean = clean self.robotpkg_git = robotpkg_git self.robotpkg_wip_git = robotpkg_wip_git self.conf = conf - logging.basicConfig(format='%(message)s', level=40 - verbose * 10) - logging.critical('enabled logging of CRITICALs') - logging.error(RED + 'enabled logging of ERRORs' + NC) - logging.warning(PURPLE + 'enabled logging of WARNINGs' + NC) - logging.info(GREEN + 'enabled logging of INFOs' + NC) - logging.debug(BOLD + 'enabled logging of DEBUGs\n' + NC) + logging.basicConfig(format="%(message)s", level=40 - verbose * 10) + logging.critical("enabled logging of CRITICALs") + logging.error(RED + "enabled logging of ERRORs" + NC) + logging.warning(PURPLE + "enabled logging of WARNINGs" + NC) + logging.info(GREEN + "enabled logging of INFOs" + NC) + logging.debug(BOLD + "enabled logging of DEBUGs\n" + NC) self.init_environment_variables() self.init_robotpkg_conf_add() @@ -81,35 +139,54 @@ class RobotpkgTestRC: self.env = os.environ.copy() self.env["ROBOTPKG_BASE"] = str(self.robotpkg_base) # For binaries - self.env["PATH"] = prepend_paths(self.robotpkg_base, ['sbin', 'bin'], self.env['PATH']) + self.env["PATH"] = prepend_paths( + self.robotpkg_base, ["sbin", "bin"], self.env["PATH"] + ) # For libraries - self.env["LD_LIBRARY_PATH"] = prepend_paths(self.robotpkg_base, ['lib', 'lib/plugin', 'lib64'], - self.env.get('LD_LIBRARY_PATH')) + self.env["LD_LIBRARY_PATH"] = prepend_paths( + self.robotpkg_base, + ["lib", "lib/plugin", "lib64"], + self.env.get("LD_LIBRARY_PATH"), + ) # For python - self.env["PYTHON_PATH"] = prepend_paths(self.robotpkg_base, - ['lib/python2.7/site-packages', 'lib/python2.7/dist-packages'], - self.env.get('PYTHON_PATH', '')) + self.env["PYTHON_PATH"] = prepend_paths( + self.robotpkg_base, + ["lib/python2.7/site-packages", "lib/python2.7/dist-packages"], + self.env.get("PYTHON_PATH", ""), + ) # For pkgconfig - self.env["PKG_CONFIG_PATH"] = prepend_paths(self.robotpkg_base, ['lib/pkgconfig'], - self.env.get("PKG_CONFIG_PATH", '')) + self.env["PKG_CONFIG_PATH"] = prepend_paths( + self.robotpkg_base, ["lib/pkgconfig"], self.env.get("PKG_CONFIG_PATH", "") + ) # For ros packages - self.env["ROS_PACKAGE_PATH"] = prepend_paths(self.robotpkg_base, ['share', 'stacks'], - self.env.get("ROS_PACKAGE_PATH", '')) + self.env["ROS_PACKAGE_PATH"] = prepend_paths( + self.robotpkg_base, + ["share", "stacks"], + self.env.get("ROS_PACKAGE_PATH", ""), + ) # For cmake - self.env["CMAKE_PREFIX_PATH"] = str(self.robotpkg_base) + ':' + self.env.get("CMAKE_PREFIX_PATH", '') + self.env["CMAKE_PREFIX_PATH"] = ( + str(self.robotpkg_base) + ":" + self.env.get("CMAKE_PREFIX_PATH", "") + ) def init_robotpkg_conf_add(self): - self.robotpkg_conf_lines = ['ROS_PACKAGE_PATH=${ROBOTPKG_BASE}/share:$ROS_PACKAGE_PATH'] - self.robotpkg_conf_lines += ['ACCEPTABLE_LICENSES += %s' % license for license in ACCEPTABLE_LICENSES] - self.robotpkg_conf_lines += ['PREFER.%s = system' % pkg for pkg in PREFER_SYSTEM] + self.robotpkg_conf_lines = [ + "ROS_PACKAGE_PATH=${ROBOTPKG_BASE}/share:$ROS_PACKAGE_PATH" + ] + self.robotpkg_conf_lines += [ + "ACCEPTABLE_LICENSES += %s" % license for license in ACCEPTABLE_LICENSES + ] + self.robotpkg_conf_lines += [ + "PREFER.%s = system" % pkg for pkg in PREFER_SYSTEM + ] def execute(self, command, cwd=None): - """ Execute command + """Execute command Keyword arguments: command -- the command to be run @@ -120,7 +197,9 @@ class RobotpkgTestRC: """ logging.debug(BOLD + "execute command: %s" + NC, command) - outputdata = subprocess.check_output(command.split(), env=self.env, cwd=str(cwd), universal_newlines=True) + outputdata = subprocess.check_output( + command.split(), env=self.env, cwd=str(cwd), universal_newlines=True + ) for stdout_line in outputdata.splitlines(): logging.debug(BOLD + stdout_line + NC) return outputdata @@ -144,33 +223,36 @@ class RobotpkgTestRC: and eventually delete or clean them, depending on the argparser's options """ if self.delete and self.robotpkg_root.is_dir(): - logging.warning(PURPLE + 'rm -rf %s' % self.robotpkg_root + NC + '\n') + logging.warning(PURPLE + "rm -rf %s" % self.robotpkg_root + NC + "\n") rmtree(str(self.robotpkg_root)) if self.clean: if self.robotpkg_base.is_dir(): - logging.warning(PURPLE + 'rm -rf %s' % self.robotpkg_base + NC + '\n') + logging.warning(PURPLE + "rm -rf %s" % self.robotpkg_base + NC + "\n") rmtree(str(self.robotpkg_base)) - logging.info(GREEN + 'Creating the repositories' + NC) + logging.info(GREEN + "Creating the repositories" + NC) self.robotpkg_base.mkdir(parents=True, exist_ok=True) def cloning_robotpkg_main(self): """Clones the main robotpkg repository""" - logging.info(GREEN + 'Cloning robotpkg\n' + NC) - if (self.robotpkg_root / 'robotpkg').exists(): - self.execute("git pull", cwd=self.robotpkg_root / 'robotpkg') + logging.info(GREEN + "Cloning robotpkg\n" + NC) + if (self.robotpkg_root / "robotpkg").exists(): + self.execute("git pull", cwd=self.robotpkg_root / "robotpkg") else: self.execute("git clone %s" % self.robotpkg_git, cwd=self.robotpkg_root) def cloning_robotpkg_wip(self): """Clones the wip robotpkg repository""" - logging.info(GREEN + 'Cloning robotpkg/wip\n' + NC) - if (self.robotpkg_root / 'robotpkg/wip').exists(): - self.execute("git pull", cwd=self.robotpkg_root / 'robotpkg/wip') + logging.info(GREEN + "Cloning robotpkg/wip\n" + NC) + if (self.robotpkg_root / "robotpkg/wip").exists(): + self.execute("git pull", cwd=self.robotpkg_root / "robotpkg/wip") else: - self.execute("git clone %s wip" % self.robotpkg_wip_git, cwd=self.robotpkg_root / 'robotpkg') + self.execute( + "git clone %s wip" % self.robotpkg_wip_git, + cwd=self.robotpkg_root / "robotpkg", + ) def bootstrap_robotpkg(self): - """ bootstrap robotpkg + """bootstrap robotpkg This method calls: bootstrap --prefix=${robotpkg_base} @@ -179,44 +261,63 @@ class RobotpkgTestRC: already present. """ # Test if a file in robotpkg_base/etc/robotpkg.conf already exists - rpkg_conf_file = self.robotpkg_base / 'etc/robotpkg.conf' + rpkg_conf_file = self.robotpkg_base / "etc/robotpkg.conf" if rpkg_conf_file.is_file(): - logging.warning(PURPLE + str(rpkg_conf_file) + NC + ' already exists\n') + logging.warning(PURPLE + str(rpkg_conf_file) + NC + " already exists\n") return - logging.info(GREEN + 'Boostrap robotpkg\n' + NC) - self.execute('./bootstrap --prefix=%s' % self.robotpkg_base, cwd=self.robotpkg_root / 'robotpkg/bootstrap') + logging.info(GREEN + "Boostrap robotpkg\n" + NC) + self.execute( + "./bootstrap --prefix=%s" % self.robotpkg_base, + cwd=self.robotpkg_root / "robotpkg/bootstrap", + ) def complete_robotpkg_conffile(self): """Add the contents of robotpkg_conf_lines in robotpkg.conf file Avoid to add two times the same information. """ - logging.info(GREEN + 'Adding information to ' + str(self.robotpkg_base) + '/etc/robotpkg.conf\n' + NC) + logging.info( + GREEN + + "Adding information to " + + str(self.robotpkg_base) + + "/etc/robotpkg.conf\n" + + NC + ) # Open the file, read it and stores it in file_robotpkg_contents - with (self.robotpkg_base / 'etc/robotpkg.conf').open() as file_robotpkgconf: + with (self.robotpkg_base / "etc/robotpkg.conf").open() as file_robotpkgconf: file_robotpkgconf_contents = file_robotpkgconf.read() # Append the optional conf file given as parameter if self.conf is not None and self.conf.exists(): - logging.info(GREEN + 'Adding %s to %s/etc/robotpkg.conf\n' + NC, self.conf, self.robotpkg_base) + logging.info( + GREEN + "Adding %s to %s/etc/robotpkg.conf\n" + NC, + self.conf, + self.robotpkg_base, + ) with self.conf.open() as f: self.robotpkg_conf_lines += [line.strip() for line in f.readlines()] # Add new lines at the end of robotpkg.conf file. - with (self.robotpkg_base / 'etc/robotpkg.conf').open('a') as file_robotpkgconf: + with (self.robotpkg_base / "etc/robotpkg.conf").open("a") as file_robotpkgconf: for stdout_line in self.robotpkg_conf_lines: if file_robotpkgconf_contents.find(stdout_line) == -1: - file_robotpkgconf.write(stdout_line + '\n') + file_robotpkgconf.write(stdout_line + "\n") def build_rpkg_checkout_package(self, packagename, category): - ''' Execute cmd in the working directory of packagename''' + """Execute cmd in the working directory of packagename""" # Going into the repository directory - pathname = self.robotpkg_root / 'robotpkg' / category / packagename / ('work.' + socket.gethostname()) + pathname = ( + self.robotpkg_root + / "robotpkg" + / category + / packagename + / ("work." + socket.gethostname()) + ) return pathname def apply_rpkg_checkout_package(self, packagename, branchname, category): - """ Performs a make checkout in packagename directory + """Performs a make checkout in packagename directory packagename: The name of package in which the git clone will be perfomed. branchname: The name of the branch used in the repository. @@ -224,15 +325,19 @@ class RobotpkgTestRC: The location of the repository is specified in the robotpkg Makefile. """ - logging.info(GREEN + 'Checkout ' + packagename + ' in robotpkg/' + category + NC + '\n') + logging.info( + GREEN + "Checkout " + packagename + " in robotpkg/" + category + NC + "\n" + ) # Checking if we need to clean or not the package # First check if the working directory exists directory_to_clean = True - checkoutdir_packagename = self.build_rpkg_checkout_package(packagename, category) + checkoutdir_packagename = self.build_rpkg_checkout_package( + packagename, category + ) if checkoutdir_packagename.exists(): - logging.debug(BOLD + 'Going into :\n' + str(checkoutdir_packagename) + NC) + logging.debug(BOLD + "Going into :\n" + str(checkoutdir_packagename) + NC) # If it does then maybe this is not a git directory for folder in checkoutdir_packagename.iterdir(): @@ -240,31 +345,41 @@ class RobotpkgTestRC: continue logging.debug(BOLD + "Going into: %s" % folder + NC) # Check if there is a git folder - if (folder / '.git').is_dir(): - logging.debug(BOLD + 'Git folder found' + NC) + if (folder / ".git").is_dir(): + logging.debug(BOLD + "Git folder found" + NC) # Now that we detected a git folder # Check the branch - outputdata = self.execute("git symbolic-ref --short -q HEAD", cwd=folder) + outputdata = self.execute( + "git symbolic-ref --short -q HEAD", cwd=folder + ) for stdout_line in outputdata.splitlines(): if stdout_line != branchname: - logging.error(RED + ' Wrong branch name: ' + stdout_line + ' instead of ' + branchname + - NC) + logging.error( + RED + + " Wrong branch name: " + + stdout_line + + " instead of " + + branchname + + NC + ) else: finaldirectory = folder directory_to_clean = False break - logging.debug(BOLD + 'Directory to clean: ' + str(directory_to_clean) + NC) + logging.debug(BOLD + "Directory to clean: " + str(directory_to_clean) + NC) if directory_to_clean: # Going into the directory of the package - cwd = self.robotpkg_root / 'robotpkg' / category / packagename + cwd = self.robotpkg_root / "robotpkg" / category / packagename self.execute("make clean confirm", cwd=cwd) self.execute("make checkout", cwd=cwd) else: # Remove all the files which may have been modified. self.execute("git reset --hard", cwd=finaldirectory) # Pull all the modification push upstream. - self.execute("git pull origin " + branchname + ':' + branchname, cwd=finaldirectory) + self.execute( + "git pull origin " + branchname + ":" + branchname, cwd=finaldirectory + ) self.execute("git submodule update", cwd=finaldirectory) def apply_git_checkout_branch(self, packagename, branchname, category): @@ -274,22 +389,28 @@ class RobotpkgTestRC: The method first detects that the package working directory is really a git repository. Then it performs the branch switch. """ - checkoutdir_packagename = self.build_rpkg_checkout_package(packagename, category) + checkoutdir_packagename = self.build_rpkg_checkout_package( + packagename, category + ) for folder in checkoutdir_packagename.iterdir(): if not folder.is_dir(): continue logging.debug(BOLD + "Going into: %s" % folder + NC) - if (folder / '.git').is_dir(): - self.execute('git checkout ' + branchname, cwd=folder) - self.execute('git submodule update', cwd=folder) + if (folder / ".git").is_dir(): + self.execute("git checkout " + branchname, cwd=folder) + self.execute("git submodule update", cwd=folder) def compile_package(self, packagename, category): - """ Performs make replace confirm in package working directory - """ + """Performs make replace confirm in package working directory""" # Going into the directory of the package - logging.info(GREEN + 'Compile ' + packagename + ' in robotpkg/' + category + NC + '\n') + logging.info( + GREEN + "Compile " + packagename + " in robotpkg/" + category + NC + "\n" + ) # Compiling the repository - self.execute("make replace confirm", cwd=self.robotpkg_root / 'robotpkg' / category / packagename) + self.execute( + "make replace confirm", + cwd=self.robotpkg_root / "robotpkg" / category / packagename, + ) def handle_package(self, packagename, branchname, category): """Compile and install packagename with branch branchname @@ -313,17 +434,17 @@ class RobotpkgTestRC: arch_release_candidates = [ - ('math', 'pinocchio', 'devel'), - ('math', 'py-pinocchio', 'devel'), - ('wip', 'sot-core-v3', 'topic/pinocchio_v2'), - ('wip', 'py-sot-core-v3', 'topic/pinocchio_v2'), - ('wip', 'sot-dynamic-pinocchio-v3', 'topic/pinocchio_v2'), - ('wip', 'py-sot-dynamic-pinocchio-v3', 'topic/pinocchio_v2'), - ('wip', 'sot-talos', 'master'), - ('wip', 'sot-hrp2-v3', 'master'), - ('wip', 'py-sot-application-v3', 'master'), - ('wip', 'py-dynamic-graph-bridge-v3', 'master'), + ("math", "pinocchio", "devel"), + ("math", "py-pinocchio", "devel"), + ("wip", "sot-core-v3", "topic/pinocchio_v2"), + ("wip", "py-sot-core-v3", "topic/pinocchio_v2"), + ("wip", "sot-dynamic-pinocchio-v3", "topic/pinocchio_v2"), + ("wip", "py-sot-dynamic-pinocchio-v3", "topic/pinocchio_v2"), + ("wip", "sot-talos", "master"), + ("wip", "sot-hrp2-v3", "master"), + ("wip", "py-sot-application-v3", "master"), + ("wip", "py-dynamic-graph-bridge-v3", "master"), ] -if __name__ == '__main__': +if __name__ == "__main__": RobotpkgTestRC(**vars(parser.parse_args())).perform_test(arch_release_candidates) diff --git a/scripts/video.py b/scripts/video.py index 2f9a6bffe4582ee51ca58d39968ef50d95bd5d21..43344eec8f29248b4a5c0e711c0e729fe29dd2a8 100755 --- a/scripts/video.py +++ b/scripts/video.py @@ -12,51 +12,74 @@ from slugify import slugify def valid_time(option): - match = re.match(r'(?P<H>\d\d)?:?(?P<M>\d\d):(?P<S>\d\d)(?P<F>.\d+)?', option) + match = re.match(r"(?P<H>\d\d)?:?(?P<M>\d\d):(?P<S>\d\d)(?P<F>.\d+)?", option) if not match: - raise argparse.ArgumentTypeError(f'Time should be specified as [HH:]MM:SS[.f], got {option}') + raise argparse.ArgumentTypeError( + f"Time should be specified as [HH:]MM:SS[.f], got {option}" + ) r = match.groupdict(0) - return str(timedelta(seconds=int(r['S']) + float(r['F']) + 60 * (int(r['M']) + 60 * int(r['H'])))) + return str( + timedelta( + seconds=int(r["S"]) + float(r["F"]) + 60 * (int(r["M"]) + 60 * int(r["H"])) + ) + ) def valid_file(option): if not exists(option): - raise argparse.ArgumentTypeError(f'This should be an existing file: {option}') + raise argparse.ArgumentTypeError(f"This should be an existing file: {option}") return str(option) -parser = argparse.ArgumentParser(description='Append a title slide to a video. Optionnaly cut it and crop it') -parser.add_argument('rush', type=valid_file, help="filename of the rush") -parser.add_argument('author', type=str, help="speaker's name") -parser.add_argument('title', type=str, help="talk's title") -parser.add_argument('--image', type=valid_file, help="title image", default='title.png') -parser.add_argument('-ss', '--start-time', default='00:00', type=valid_time, help="start of the video") -parser.add_argument('-to', '--end-time', default='00:00', type=valid_time, help="end of the video") -parser.add_argument('-n', default=0, type=int, help="number of the video in a playlist (0 for no playlist)") -parser.add_argument('-fs', default=60, type=int, help="font size") -parser.add_argument('--no-magic', action='store_true', default=False) -parser.add_argument('-c', '--crop', action='store_true', default=False, help='Crop the speaker only from the video') - - -if __name__ == '__main__': +parser = argparse.ArgumentParser( + description="Append a title slide to a video. Optionnaly cut it and crop it" +) +parser.add_argument("rush", type=valid_file, help="filename of the rush") +parser.add_argument("author", type=str, help="speaker's name") +parser.add_argument("title", type=str, help="talk's title") +parser.add_argument("--image", type=valid_file, help="title image", default="title.png") +parser.add_argument( + "-ss", "--start-time", default="00:00", type=valid_time, help="start of the video" +) +parser.add_argument( + "-to", "--end-time", default="00:00", type=valid_time, help="end of the video" +) +parser.add_argument( + "-n", + default=0, + type=int, + help="number of the video in a playlist (0 for no playlist)", +) +parser.add_argument("-fs", default=60, type=int, help="font size") +parser.add_argument("--no-magic", action="store_true", default=False) +parser.add_argument( + "-c", + "--crop", + action="store_true", + default=False, + help="Crop the speaker only from the video", +) + + +if __name__ == "__main__": options = parser.parse_args() # get cmd that cuts the rush - cut_rush_cmd = f'ffmpeg -i {options.rush}' - if options.start_time != '0:00:00': - cut_rush_cmd += f' -ss {options.start_time}' - if options.end_time != '0:00:00': - cut_rush_cmd += f' -to {options.end_time}' + cut_rush_cmd = f"ffmpeg -i {options.rush}" + if options.start_time != "0:00:00": + cut_rush_cmd += f" -ss {options.start_time}" + if options.end_time != "0:00:00": + cut_rush_cmd += f" -to {options.end_time}" author, title = slugify(options.author), slugify(options.title) - filename = f'{author}_{title}' + filename = f"{author}_{title}" if options.n: - filename = f'{options.n:02}_{filename}' + filename = f"{options.n:02}_{filename}" directory = dirname(options.rush) path = join(directory, filename) # get title frame if options.no_magic: - copy(options.image, f'{path}_title.png') + copy(options.image, f"{path}_title.png") else: from wand.display import display # noqa from wand.drawing import Drawing # noqa @@ -65,41 +88,59 @@ if __name__ == '__main__': with Image(filename=join(directory, options.image)) as img: with Drawing() as draw: draw.font_size = options.fs - draw.text_alignment = 'center' - title = options.title.replace('^', '\n') - draw.text(int(img.width/2), int(img.height / 2), f'{options.author}:\n{title}') + draw.text_alignment = "center" + title = options.title.replace("^", "\n") + draw.text( + int(img.width / 2), + int(img.height / 2), + f"{options.author}:\n{title}", + ) draw(img) - img.save(filename=f'{path}_title.png') + img.save(filename=f"{path}_title.png") # convert title frame to title video - for line in run(['ffmpeg', '-i', options.rush], stderr=PIPE).stderr.decode().split('\n'): - if 'Stream' in line and 'Video' in line: - video_parameters = [s.strip() for s in line.split(',')] - if 'Stream' in line and 'Audio' in line: - audio_parameters = [s.strip() for s in line.split(',')] - cv = 'libx264' # if 'h264' in video_parameters[0]. otherwise… I don't know :P + for line in ( + run(["ffmpeg", "-i", options.rush], stderr=PIPE).stderr.decode().split("\n") + ): + if "Stream" in line and "Video" in line: + video_parameters = [s.strip() for s in line.split(",")] + if "Stream" in line and "Audio" in line: + audio_parameters = [s.strip() for s in line.split(",")] + cv = "libx264" # if 'h264' in video_parameters[0]. otherwise… I don't know :P fps, fmt = (video_parameters[i].split()[0] for i in (4, 1)) sr = audio_parameters[1].split()[0] # sample_rate # write script - cutted, cropped = f'{path}_cutted.mp4', f'{path}_cropped.mp4' - with open(f'process_{path}.sh', 'w') as f: - print('#!/bin/bash', file=f) - print('set -x', file=f) - print('set -e', file=f) - print(f'{cut_rush_cmd} -c copy {cutted}', file=f) + cutted, cropped = f"{path}_cutted.mp4", f"{path}_cropped.mp4" + with open(f"process_{path}.sh", "w") as f: + print("#!/bin/bash", file=f) + print("set -x", file=f) + print("set -e", file=f) + print(f"{cut_rush_cmd} -c copy {cutted}", file=f) if options.crop: - print(f'ffmpeg -i {cutted} -filter:v "crop=296:176:0:90" -strict -2 -c:a copy {cropped}', - file=f) + print( + f'ffmpeg -i {cutted} -filter:v "crop=296:176:0:90" -strict -2 -c:a copy {cropped}', + file=f, + ) else: - print(f'mv {cutted} {cropped}', file=f) - print(f'ffmpeg -loop 1 -i {path}_title.png -f lavfi -i anullsrc=channel_layout=stereo:sample_rate={sr} ' - f'-shortest -strict -2 -c:v {cv} -t 5 -vf fps={fps},format={fmt} -map 0:v -map 1:a {path}_title.mp4', - file=f) - for part in ['title', 'cropped']: - print(f'ffmpeg -i {path}_{part}.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts {part}.ts', file=f) - print(f'ffmpeg -i "concat:title.ts|cropped.ts" -c copy -bsf:a aac_adtstoasc {path}.mp4', file=f) - print(f'rm -f {path}_title.png {path}_title.mp4 {cutted} {cropped} *.ts', file=f) - - chmod(f'process_{path}.sh', 0o755) - print(f'./process_{path}.sh') + print(f"mv {cutted} {cropped}", file=f) + print( + f"ffmpeg -loop 1 -i {path}_title.png -f lavfi -i anullsrc=channel_layout=stereo:sample_rate={sr} " + f"-shortest -strict -2 -c:v {cv} -t 5 -vf fps={fps},format={fmt} -map 0:v -map 1:a {path}_title.mp4", + file=f, + ) + for part in ["title", "cropped"]: + print( + f"ffmpeg -i {path}_{part}.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts {part}.ts", + file=f, + ) + print( + f'ffmpeg -i "concat:title.ts|cropped.ts" -c copy -bsf:a aac_adtstoasc {path}.mp4', + file=f, + ) + print( + f"rm -f {path}_title.png {path}_title.mp4 {cutted} {cropped} *.ts", file=f + ) + + chmod(f"process_{path}.sh", 0o755) + print(f"./process_{path}.sh")