From: Yoan Le Clanche Date: Tue, 4 Jun 2024 13:32:21 +0000 (+0200) Subject: Generate pdf with annotations for scripts X-Git-Tag: 2.11.0~15 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=3c5f4005facd6b1ba194fa2967bb257ae6397309;p=teleforma.git Generate pdf with annotations for scripts --- diff --git a/poetry.lock b/poetry.lock index f60c87e2..00a7c44f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aioredis" version = "1.3.1" description = "asyncio (PEP 3156) Redis support" -category = "main" optional = false python-versions = "*" files = [ @@ -20,7 +19,6 @@ hiredis = "*" name = "anyio" version = "4.3.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -43,7 +41,6 @@ trio = ["trio (>=0.23)"] name = "asgiref" version = "3.8.1" description = "ASGI specs, helper code, and adapters" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -61,7 +58,6 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] name = "asttokens" version = "2.4.1" description = "Annotate AST trees with source code positions" -category = "main" optional = false python-versions = "*" files = [ @@ -80,7 +76,6 @@ test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] name = "async-timeout" version = "4.0.3" description = "Timeout context manager for asyncio programs" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -92,7 +87,6 @@ files = [ name = "attrs" version = "23.2.0" description = "Classes Without Boilerplate" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -112,7 +106,6 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p name = "autobahn" version = "23.6.2" description = "WebSocket client & server library, WAMP real-time framework" -category = "main" optional = false python-versions = ">=3.9" files = [ @@ -141,7 +134,6 @@ xbr = ["base58 (>=2.1.0)", "bitarray (>=2.7.5)", "cbor2 (>=5.2.0)", "click (>=8. name = "automat" version = "22.10.0" description = "Self-service finite-state machines for the programmer on the go." -category = "main" optional = false python-versions = "*" files = [ @@ -160,7 +152,6 @@ visualize = ["Twisted (>=16.1.1)", "graphviz (>0.5.1)"] name = "bigbluebutton-api-python" version = "0.0.11" description = "Python library that provides access to the API of BigBlueButton" -category = "main" optional = false python-versions = "*" files = [ @@ -176,7 +167,6 @@ jxmlease = "*" name = "boto3" version = "1.34.91" description = "The AWS SDK for Python" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -196,7 +186,6 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] name = "botocore" version = "1.34.91" description = "Low-level, data-driven core of boto 3." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -216,7 +205,6 @@ crt = ["awscrt (==0.20.9)"] name = "cairocffi" version = "1.6.1" description = "cffi-based cairo bindings for Python" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -236,7 +224,6 @@ xcb = ["xcffib (>=1.4.0)"] name = "cairosvg" version = "2.7.1" description = "A Simple SVG Converter based on Cairo" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -259,7 +246,6 @@ test = ["flake8", "isort", "pytest"] name = "certifi" version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -271,7 +257,6 @@ files = [ name = "cffi" version = "1.16.0" description = "Foreign Function Interface for Python calling C code." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -336,7 +321,6 @@ pycparser = "*" name = "channels" version = "3.0.4" description = "Brings async, event-driven capabilities to Django. Django 2.2 and up only." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -356,7 +340,6 @@ tests = ["async-timeout", "coverage (>=4.5,<5.0)", "pytest", "pytest-asyncio", " name = "channels-redis" version = "3.4.0" description = "Redis-backed ASGI channel layer implementation" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -374,11 +357,21 @@ msgpack = ">=1.0,<2.0" cryptography = ["cryptography (>=1.3.0)"] tests = ["async-generator", "async-timeout", "cryptography (>=1.3.0)", "pytest", "pytest-asyncio (==0.14.0)"] +[[package]] +name = "chardet" +version = "5.2.0" +description = "Universal encoding detector for Python 3" +optional = false +python-versions = ">=3.7" +files = [ + {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, + {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, +] + [[package]] name = "charset-normalizer" version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -478,7 +471,6 @@ files = [ name = "click" version = "8.1.7" description = "Composable command line interface toolkit" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -493,7 +485,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -505,7 +496,6 @@ files = [ name = "constantly" version = "23.10.4" description = "Symbolic constants in Python" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -517,7 +507,6 @@ files = [ name = "cryptography" version = "42.0.5" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -572,7 +561,6 @@ test-randomorder = ["pytest-randomly"] name = "cssselect2" version = "0.7.0" description = "CSS selectors for Python ElementTree" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -592,7 +580,6 @@ test = ["flake8", "isort", "pytest"] name = "daphne" version = "3.0.2" description = "Django ASGI (HTTP/WebSocket) server" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -612,7 +599,6 @@ tests = ["hypothesis (==4.23)", "pytest (>=3.10,<4.0)", "pytest-asyncio (>=0.8,< name = "decorator" version = "5.1.1" description = "Decorators for Humans" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -624,7 +610,6 @@ files = [ name = "defusedxml" version = "0.7.1" description = "XML bomb protection for Python stdlib modules" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -636,7 +621,6 @@ files = [ name = "dj-pagination" version = "2.5.0" description = "Django + Pagination Made Easy" -category = "main" optional = false python-versions = "*" files = [ @@ -648,7 +632,6 @@ files = [ name = "django" version = "3.2.25" description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -669,7 +652,6 @@ bcrypt = ["bcrypt"] name = "django-debug-toolbar" version = "3.2.1" description = "A configurable set of panels that display various debug information about the current request/response." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -685,7 +667,6 @@ sqlparse = ">=0.2.0" name = "django-jazzmin" version = "2.4.7" description = "Drop-in theme for django admin, that utilises AdminLTE 3 & Bootstrap 4 to make yo' admin look jazzy" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -700,7 +681,6 @@ django = ">=2" name = "django-json-rpc" version = "0.7.1" description = "A simple JSON-RPC implementation for Django" -category = "main" optional = false python-versions = "*" files = [ @@ -715,7 +695,6 @@ six = "*" name = "django-nvd3" version = "0.9.7" description = "Django NVD3 - Chart Library for d3.js" -category = "main" optional = false python-versions = "*" files = [ @@ -729,7 +708,6 @@ python-nvd3 = "0.14.2" name = "django-postman" version = "4.2" description = "User-to-User messaging system for Django, with gateway to AnonymousUser, moderation and thread management, user & exchange filters, inbox/sent/archives/trash folders, support for apps: auto-complete, notification, mailer." -category = "main" optional = false python-versions = "*" files = [ @@ -743,7 +721,6 @@ Django = "*" name = "django-recaptcha" version = "2.0.6" description = "Django recaptcha form field/widget app." -category = "main" optional = false python-versions = "*" files = [ @@ -757,7 +734,6 @@ django = ">1.11,<4.0" name = "django-storages" version = "1.14.2" description = "Support for many storage backends in Django" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -782,7 +758,6 @@ sftp = ["paramiko (>=1.15)"] name = "django-tinymce" version = "3.3.0" description = "A Django application that contains a widget to render a form field as a TinyMCE editor." -category = "main" optional = false python-versions = "*" files = [ @@ -794,7 +769,6 @@ files = [ name = "django-unique-session" version = "1.0" description = "Unique session handler for Django" -category = "main" optional = false python-versions = "*" files = [ @@ -806,7 +780,6 @@ files = [ name = "django-user-agents" version = "0.4.0" description = "A django package that allows easy identification of visitors' browser, operating system and device information (mobile phone, tablet or has touch capabilities)." -category = "main" optional = false python-versions = "*" files = [ @@ -822,7 +795,6 @@ user-agents = "*" name = "djangorestframework" version = "3.13.1" description = "Web APIs for Django, made easy." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -838,7 +810,6 @@ pytz = "*" name = "docutils" version = "0.17.1" description = "Docutils -- Python Documentation Utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -850,7 +821,6 @@ files = [ name = "exceptiongroup" version = "1.2.1" description = "Backport of PEP 654 (exception groups)" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -865,7 +835,6 @@ test = ["pytest (>=6)"] name = "executing" version = "2.0.1" description = "Get the currently executing AST node of a frame, and other information" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -880,7 +849,6 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -892,7 +860,6 @@ files = [ name = "hiredis" version = "2.3.2" description = "Python wrapper for hiredis" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1011,7 +978,6 @@ files = [ name = "html5lib" version = "1.1" description = "HTML parser based on the WHATWG HTML specification" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1033,7 +999,6 @@ lxml = ["lxml"] name = "httpcore" version = "0.16.3" description = "A minimal low-level HTTP client." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1045,17 +1010,16 @@ files = [ anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = ">=1.0.0,<2.0.0" +sniffio = "==1.*" [package.extras] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "httptools" version = "0.6.1" description = "A collection of framework independent HTTP protocol utils." -category = "main" optional = false python-versions = ">=3.8.0" files = [ @@ -1104,7 +1068,6 @@ test = ["Cython (>=0.29.24,<0.30.0)"] name = "httpx" version = "0.23.3" description = "The next generation HTTP client." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1120,15 +1083,14 @@ sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<13)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "hyperlink" version = "21.0.0" description = "A featureful, immutable, and correct URL for Python." -category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1143,7 +1105,6 @@ idna = ">=2.5" name = "idna" version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1155,7 +1116,6 @@ files = [ name = "incremental" version = "22.10.0" description = "\"A small library that versions your Python projects.\"" -category = "main" optional = false python-versions = "*" files = [ @@ -1171,7 +1131,6 @@ scripts = ["click (>=6.0)", "twisted (>=16.4.0)"] name = "ipython" version = "8.23.0" description = "IPython: Productive Interactive Computing" -category = "main" optional = false python-versions = ">=3.10" files = [ @@ -1210,7 +1169,6 @@ test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "num name = "jedi" version = "0.19.1" description = "An autocompletion tool for Python that can be used for text editors." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1230,7 +1188,6 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] name = "jinja2" version = "3.1.3" description = "A very fast and expressive template engine." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1248,7 +1205,6 @@ i18n = ["Babel (>=2.7)"] name = "jmespath" version = "1.0.1" description = "JSON Matching Expressions" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1260,7 +1216,6 @@ files = [ name = "jxmlease" version = "1.0.3" description = "jxmlease converts between XML and intelligent Python data structures." -category = "main" optional = false python-versions = "*" files = [ @@ -1272,7 +1227,6 @@ files = [ name = "markupsafe" version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1342,7 +1296,6 @@ files = [ name = "matplotlib-inline" version = "0.1.7" description = "Inline Matplotlib backend for Jupyter" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1357,7 +1310,6 @@ traitlets = "*" name = "msgpack" version = "1.0.8" description = "MessagePack serializer" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1423,7 +1375,6 @@ files = [ name = "numpy" version = "1.26.4" description = "Fundamental package for array computing in Python" -category = "main" optional = false python-versions = ">=3.9" files = [ @@ -1469,7 +1420,6 @@ files = [ name = "parso" version = "0.8.4" description = "A Python Parser" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1485,7 +1435,6 @@ testing = ["docopt", "pytest"] name = "pexpect" version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." -category = "main" optional = false python-versions = "*" files = [ @@ -1500,7 +1449,6 @@ ptyprocess = ">=0.5" name = "pillow" version = "10.3.0" description = "Python Imaging Library (Fork)" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1587,7 +1535,6 @@ xmp = ["defusedxml"] name = "prompt-toolkit" version = "3.0.43" description = "Library for building powerful interactive command lines in Python" -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -1602,7 +1549,6 @@ wcwidth = "*" name = "psycopg2" version = "2.8.6" description = "psycopg2 - Python-PostgreSQL Database Adapter" -category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" files = [ @@ -1627,7 +1573,6 @@ files = [ name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" -category = "main" optional = false python-versions = "*" files = [ @@ -1639,7 +1584,6 @@ files = [ name = "pure-eval" version = "0.2.2" description = "Safely evaluate AST nodes without side effects" -category = "main" optional = false python-versions = "*" files = [ @@ -1654,7 +1598,6 @@ tests = ["pytest"] name = "pyasn1" version = "0.6.0" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1666,7 +1609,6 @@ files = [ name = "pyasn1-modules" version = "0.4.0" description = "A collection of ASN.1-based protocols modules" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1681,7 +1623,6 @@ pyasn1 = ">=0.4.6,<0.7.0" name = "pycparser" version = "2.22" description = "C parser in Python" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1693,7 +1634,6 @@ files = [ name = "pygments" version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1709,7 +1649,6 @@ windows-terminal = ["colorama (>=0.4.6)"] name = "pymemcache" version = "3.4.4" description = "A comprehensive, fast, pure Python memcached client" -category = "main" optional = false python-versions = "*" files = [ @@ -1724,7 +1663,6 @@ six = "*" name = "pyopenssl" version = "24.1.0" description = "Python wrapper module around the OpenSSL library" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1743,7 +1681,6 @@ test = ["pretend", "pytest (>=3.0.1)", "pytest-rerunfailures"] name = "pypdf" version = "4.2.0" description = "A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1765,7 +1702,6 @@ image = ["Pillow (>=8.0.0)"] name = "pyphen" version = "0.15.0" description = "Pure Python module to hyphenate text" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1781,7 +1717,6 @@ test = ["pytest", "ruff"] name = "python-dateutil" version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -1796,7 +1731,6 @@ six = ">=1.5" name = "python-dotenv" version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1811,7 +1745,6 @@ cli = ["click (>=5.0)"] name = "python-nvd3" version = "0.14.2" description = "Python NVD3 - Chart Library for d3.js" -category = "main" optional = false python-versions = "*" files = [ @@ -1826,7 +1759,6 @@ python-slugify = "1.1.4" name = "python-slugify" version = "1.1.4" description = "A Python Slugify application that handles Unicode" -category = "main" optional = false python-versions = "*" files = [ @@ -1840,7 +1772,6 @@ Unidecode = ">=0.04.16" name = "pytz" version = "2024.1" description = "World timezone definitions, modern and historical" -category = "main" optional = false python-versions = "*" files = [ @@ -1852,7 +1783,6 @@ files = [ name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1913,7 +1843,6 @@ files = [ name = "redis" version = "3.5.3" description = "Python client for Redis key-value store" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1924,11 +1853,30 @@ files = [ [package.extras] hiredis = ["hiredis (>=0.1.3)"] +[[package]] +name = "reportlab" +version = "4.2.0" +description = "The Reportlab Toolkit" +optional = false +python-versions = "<4,>=3.7" +files = [ + {file = "reportlab-4.2.0-py3-none-any.whl", hash = "sha256:53630f9d25a7938def3e6a93d723b72a7a5921d34d23cf7a0930adeb2cb0e6c1"}, + {file = "reportlab-4.2.0.tar.gz", hash = "sha256:474fb28d63431a5d47d75c90d580393050df7d491a09c7877df3291a2e9f6d0a"}, +] + +[package.dependencies] +chardet = "*" +pillow = ">=9.0.0" + +[package.extras] +accel = ["rl-accel (>=0.9.0,<1.1)"] +pycairo = ["freetype-py (>=2.3.0,<2.4)", "rlPyCairo (>=0.2.0,<1)"] +renderpm = ["rl-renderPM (>=4.0.3,<4.1)"] + [[package]] name = "requests" version = "2.31.0" description = "Python HTTP for Humans." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1950,7 +1898,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "rfc3986" version = "1.5.0" description = "Validating URI References per RFC 3986" -category = "main" optional = false python-versions = "*" files = [ @@ -1968,7 +1915,6 @@ idna2008 = ["idna"] name = "s3transfer" version = "0.10.1" description = "An Amazon S3 Transfer Manager" -category = "main" optional = false python-versions = ">= 3.8" files = [ @@ -1986,7 +1932,6 @@ crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] name = "service-identity" version = "24.1.0" description = "Service identity verification for pyOpenSSL & cryptography." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2011,7 +1956,6 @@ tests = ["coverage[toml] (>=5.0.2)", "pytest"] name = "setuptools" version = "69.5.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2028,7 +1972,6 @@ testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jar name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -2040,7 +1983,6 @@ files = [ name = "sniffio" version = "1.3.1" description = "Sniff out which async library your code is running under" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2052,7 +1994,6 @@ files = [ name = "sorl-thumbnail" version = "12.10.0" description = "Thumbnails for Django" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2064,7 +2005,6 @@ files = [ name = "sqlparse" version = "0.5.0" description = "A non-validating SQL parser." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2080,7 +2020,6 @@ doc = ["sphinx"] name = "stack-data" version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" -category = "main" optional = false python-versions = "*" files = [ @@ -2100,7 +2039,6 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] name = "tinycss2" version = "1.3.0" description = "A tiny CSS parser" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2119,7 +2057,6 @@ test = ["pytest", "ruff"] name = "traitlets" version = "5.14.3" description = "Traitlets Python configuration system" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2135,7 +2072,6 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, name = "twisted" version = "24.3.0" description = "An asynchronous networking framework written in Python" -category = "main" optional = false python-versions = ">=3.8.0" files = [ @@ -2175,7 +2111,6 @@ windows-platform = ["pywin32 (!=226)", "pywin32 (!=226)", "twisted[all-non-platf name = "twisted-iocpsupport" version = "1.0.4" description = "An extension for use in the twisted I/O Completion Ports reactor." -category = "main" optional = false python-versions = "*" files = [ @@ -2204,7 +2139,6 @@ files = [ name = "txaio" version = "23.1.1" description = "Compatibility API between asyncio/Twisted/Trollius" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2221,7 +2155,6 @@ twisted = ["twisted (>=20.3.0)", "zope.interface (>=5.2.0)"] name = "typing-extensions" version = "4.11.0" description = "Backported and Experimental Type Hints for Python 3.8+" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2233,7 +2166,6 @@ files = [ name = "ua-parser" version = "0.18.0" description = "Python port of Browserscope's user agent parser" -category = "main" optional = false python-versions = "*" files = [ @@ -2245,7 +2177,6 @@ files = [ name = "unidecode" version = "1.2.0" description = "ASCII transliterations of Unicode text" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2257,7 +2188,6 @@ files = [ name = "urllib3" version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2275,7 +2205,6 @@ zstd = ["zstandard (>=0.18.0)"] name = "user-agents" version = "2.2.0" description = "A library to identify devices (phones, tablets) and their capabilities by parsing browser user agent strings." -category = "main" optional = false python-versions = "*" files = [ @@ -2290,7 +2219,6 @@ ua-parser = ">=0.10.0" name = "uvicorn" version = "0.18.1" description = "The lightning-fast ASGI server." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2305,7 +2233,7 @@ h11 = ">=0.8" httptools = {version = ">=0.4.0", optional = true, markers = "extra == \"standard\""} python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} PyYAML = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} -uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} websockets = {version = ">=10.0", optional = true, markers = "extra == \"standard\""} @@ -2316,7 +2244,6 @@ standard = ["PyYAML (>=5.1)", "colorama (>=0.4)", "httptools (>=0.4.0)", "python name = "uvloop" version = "0.19.0" description = "Fast implementation of asyncio event loop on top of libuv" -category = "main" optional = false python-versions = ">=3.8.0" files = [ @@ -2361,7 +2288,6 @@ test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)" name = "uwsgi" version = "2.0.25.1" description = "The uWSGI server" -category = "main" optional = false python-versions = "*" files = [ @@ -2372,7 +2298,6 @@ files = [ name = "watchfiles" version = "0.21.0" description = "Simple, modern and high performance file watching and code reload in python." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2460,7 +2385,6 @@ anyio = ">=3.0.0" name = "wcwidth" version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" -category = "main" optional = false python-versions = "*" files = [ @@ -2472,7 +2396,6 @@ files = [ name = "weasyprint" version = "52.5" description = "The Awesome Document Factory" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2499,7 +2422,6 @@ test = ["pytest-cov", "pytest-flake8", "pytest-isort", "pytest-runner"] name = "webencodings" version = "0.5.1" description = "Character encoding aliases for legacy web content" -category = "main" optional = false python-versions = "*" files = [ @@ -2511,7 +2433,6 @@ files = [ name = "websockets" version = "12.0" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2593,7 +2514,6 @@ files = [ name = "xlrd" version = "2.0.1" description = "Library for developers to extract data from Microsoft Excel (tm) .xls spreadsheet files" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -2610,7 +2530,6 @@ test = ["pytest", "pytest-cov"] name = "xlwt" version = "1.3.0" description = "Library to create spreadsheet files compatible with MS Excel 97/2000/XP/2003 XLS files, on any platform, with Python 2.6, 2.7, 3.3+" -category = "main" optional = false python-versions = "*" files = [ @@ -2622,7 +2541,6 @@ files = [ name = "zope-interface" version = "6.3" description = "Interfaces for Python" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2675,4 +2593,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "ecf8b0f59566e224cb558aacffda4f46926866a8d8471898ff1b032d0ab7009d" +content-hash = "6bc6cbf6fbe9ed773cacf9451ece9f8e29997e5426ad0dddb40529ea90a7bf3c" diff --git a/teleforma/exam/templates/exam/script_detail.html b/teleforma/exam/templates/exam/script_detail.html index f7d5dadb..48e9f4de 100644 --- a/teleforma/exam/templates/exam/script_detail.html +++ b/teleforma/exam/templates/exam/script_detail.html @@ -46,10 +46,11 @@
- + {{ script.title }}
+ Télécharger {% if user.quotas.all %} {% trans "Send a message" %} {% endif %} diff --git a/teleforma/exam/urls.py b/teleforma/exam/urls.py index ddf3aab6..8140c1e8 100644 --- a/teleforma/exam/urls.py +++ b/teleforma/exam/urls.py @@ -32,12 +32,13 @@ # # Authors: Guillaume Pellerin -from teleforma.exam.views import MassScoreCreateView, ScoreCreateView, ScriptCreateView, ScriptView, ScriptsPendingView, ScriptsRejectedView, ScriptsScoreAllView, ScriptsScoreCourseView, ScriptsTreatedView, ScriptsView, get_correctors, get_mass_students, QuotasView +from teleforma.exam.views import MassScoreCreateView, ScoreCreateView, ScriptCreateView, ScriptDownloadView, ScriptView, ScriptsPendingView, ScriptsRejectedView, ScriptsScoreAllView, ScriptsScoreCourseView, ScriptsTreatedView, ScriptsView, get_correctors, get_mass_students, QuotasView from django.conf.urls import url urlpatterns = [ url(r'^scripts/periods/(?P.*)/(?P.*)/detail/$', ScriptView.as_view(), name="teleforma-exam-script-detail"), + url(r'^scripts/periods/(?P.*)/(?P.*)/download/$', ScriptDownloadView.as_view(), name="teleforma-exam-script-download"), url(r'^scripts/periods/(?P.*)/list/$', ScriptsView.as_view(), name="teleforma-exam-script-list"), url(r'^scripts/periods/(?P.*)/create/$', ScriptCreateView.as_view(), name="teleforma-exam-script-create"), url(r'^scripts/periods/(?P.*)/pending/$', ScriptsPendingView.as_view(), name="teleforma-exam-scripts-pending"), diff --git a/teleforma/exam/views.py b/teleforma/exam/views.py index 7a7107d1..9708159a 100755 --- a/teleforma/exam/views.py +++ b/teleforma/exam/views.py @@ -3,6 +3,7 @@ # Create your views here. import datetime +import io import json import numpy as np @@ -20,6 +21,14 @@ from django.utils.translation import ugettext_lazy as _ from django.views.generic.base import View from django.views.generic.edit import CreateView, UpdateView from django.views.generic.list import ListView +from pdfannotator.models import Annotation, AnnotationComment +from pypdf import PdfReader, PdfWriter +from reportlab.lib.pagesizes import A4 +from reportlab.lib.styles import getSampleStyleSheet +from reportlab.lib.units import inch +from reportlab.pdfgen import canvas +from reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer + from teleforma.decorators import access_required, staff_required from teleforma.models.crfpa import Student from teleforma.views.core import CourseAccessMixin, get_courses @@ -165,6 +174,90 @@ class ScriptView(ScriptMixinView, CourseAccessMixin, UpdateView): def dispatch(self, *args, **kwargs): return super(ScriptView, self).dispatch(*args, **kwargs) +class ScriptDownloadView(ScriptMixinView, CourseAccessMixin): + """ + download the script pdf with its annotations + """ + + def get(self, request, *args, **kwargs): + script = get_object_or_404(Script, id=kwargs['pk']) + + packet = io.BytesIO() + can = canvas.Canvas(packet, pagesize=A4) + + # store text to be added in the last page + bottom_texts = [] + + page = 1 + for annotation in Annotation.objects.filter(uuid=script.uuid).order_by('page'): + if annotation.page != page: + # we may have to skip some pages if there are no annotations on it + for i in range(annotation.page - page): + # go to next page + can.showPage() + page = annotation.page + + # set text to red + can.setFillColorRGB(1,0,0) + + annotation_data = json.loads(annotation.content) + print(annotation_data) + text = "N/A" + # we handle only point (comment) and textbox (text) annotations + if annotation_data.get('type') == 'point': + print(annotation.uuid) + # print(uuid) + comment = AnnotationComment.objects.get(annotation_id=annotation.annotation_id, uuid=annotation.uuid) + text = comment.content + bottom_texts.append(text) + # add a number corresponding to the annotation + can.drawString(annotation_data['x'], -12 + A4[1] - annotation_data['y'], str(len(bottom_texts))) + elif annotation_data.get('type') == 'textbox': + can.drawString(annotation_data['x'], -12 + A4[1] - annotation_data['y'], annotation_data['content']) + + can.save() + + # create a new pdf with list of annotations + annotation_page = io.BytesIO() + doc = SimpleDocTemplate(annotation_page, pagesize=A4) + Story = [] + styles = getSampleStyleSheet() + # for i in range(100): + for i, text in enumerate(bottom_texts): + comment = f"{i + 1} : {text}" + style = styles["Normal"] + p = Paragraph(comment, style) + Story.append(p) + Story.append(Spacer(1, 0.2*inch)) + doc.build(Story) + + #move to the beginning of the StringIO buffer + packet.seek(0) + + # create a new PDF that contains reportlab content + new_pdf = PdfReader(packet) + # existing PDF + existing_pdf = PdfReader(script.file.path) + + # new pdf, merged from reportlab pdf and existing pdf + output = PdfWriter() + + # merge annotation layer pdf and existing pdf + for i, page in enumerate(existing_pdf.pages): + page.merge_page(new_pdf.pages[i]) + output.add_page(page) + + # finally, add annotations pages + new_pdf = PdfReader(annotation_page) + for page in new_pdf.pages: + output.add_page(page) + + response = HttpResponse(content_type='application/pdf') + response['Content-Disposition'] = 'attachment; filename="%s"' % script.file.name + output.write(response) + return response + + class ScriptsView(ScriptsListMixinView, ListView): @@ -590,6 +683,7 @@ class MassScoreCreateView(ScoreCreateView): def dispatch(self, request, *args, **kwargs): return super(ScoreCreateView, self).dispatch(request, *args, **kwargs) + def get_mass_students(request): """ @@ -622,3 +716,6 @@ def get_mass_students(request): data = {'results': res, 'pagination': {'more': False}} return HttpResponse(json.dumps(data), content_type='application/json') + + +